Fixed DevStudio 2003 build with memory check code.
[pwlib.git] / src / ptlib / unix / osutil.cxx
blobde789823ae581257da8e771b50b4d044e6103ce0
1 /*
2 * osutil.cxx
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
18 * under the License.
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): ______________________________________.
29 * $Log$
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
46 * Mac OS X update
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
146 * BeOS port changes.
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
179 * BeOS port changes.
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
191 * FreeBSD port.
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.
213 #define _OSUTIL_CXX
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"
230 #if defined(P_LINUX)
231 #ifndef _REENTRANT
232 #define _REENTRANT
233 #endif
234 #elif defined(P_SOLARIS)
235 #define _POSIX_PTHREAD_SEMANTICS
236 #endif
238 #include <ptlib.h>
241 #include <fcntl.h>
242 #ifdef P_VXWORKS
243 #include <sys/times.h>
244 #else
245 #include <time.h>
246 #include <sys/time.h>
247 #endif
248 #include <ctype.h>
250 #if defined(P_LINUX)
252 #include <mntent.h>
253 #include <sys/vfs.h>
255 #if (__GNUC_MINOR__ < 7 && __GNUC__ < 3)
256 #include <localeinfo.h>
257 #else
258 #define P_USE_LANGINFO
259 #endif
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
270 #elif defined(P_AIX)
271 #define P_USE_STRFTIME
273 #include <fstab.h>
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>
293 #include <stdio.h>
294 #include <mntent.h>
296 #elif defined(P_VXWORKS)
297 #define P_USE_STRFTIME
299 #elif defined(P_RTEMS)
300 #define P_USE_STRFTIME
301 #include <time.h>
302 #include <stdio.h>
303 #define random() rand()
304 #define srandom(a) srand(a)
306 #elif defined(P_QNX)
307 #include <sys/dcmd_blk.h>
308 #include <sys/statvfs.h>
309 #define P_USE_STRFTIME
310 #endif
312 #ifdef P_USE_LANGINFO
313 #include <langinfo.h>
314 #endif
316 #define LINE_SIZE_STEP 100
318 #define DEFAULT_FILE_MODE (S_IRUSR|S_IWUSR|S_IROTH|S_IRGRP)
320 #include <ptlib/pprocess.h>
322 #if !P_USE_INLINES
323 #include "ptlib/osutil.inl"
324 #ifdef _WIN32
325 #include "ptlib/win32/ptlib/ptlib.inl"
326 #else
327 #include "ptlib/unix/ptlib/ptlib.inl"
328 #endif
329 #endif
331 #ifdef P_SUN4
332 extern "C" {
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" };
340 #endif
342 #define new PNEW
345 static PMutex waterMarkMutex;
346 static int lowWaterMark = INT_MAX;
347 static int highWaterMark = 0;
349 int PX_NewHandle(const char * clsName, int fd)
351 if (fd < 0)
352 return fd;
354 PWaitAndSignal m(waterMarkMutex);
356 if (fd > highWaterMark) {
357 highWaterMark = fd;
358 lowWaterMark = fd;
360 int maxHandles = PProcess::Current().GetMaxHandles();
361 if (fd < (maxHandles-maxHandles/20))
362 PTRACE(4, "PWLib\tFile handle high water mark set: " << fd << ' ' << clsName);
363 else
364 PTRACE(1, "PWLib\tFile handle high water mark within 5% of maximum: " << fd << ' ' << clsName);
367 if (fd < lowWaterMark) {
368 lowWaterMark = fd;
369 PTRACE(4, "PWLib\tFile handle low water mark set: " << fd << ' ' << clsName);
372 return fd;
376 static PString CanonicaliseDirectory (const PString & path)
379 PString canonical_path;
381 if (path[0] == '/')
382 canonical_path = '/';
383 else {
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;
393 const char * end;
395 for (;;) {
396 // ignore slashes
397 while (*ptr == '/' && *ptr != '\0')
398 ptr++;
400 // finished if end of string
401 if (*ptr == '\0')
402 break;
404 // collect non-slash characters
405 end = ptr;
406 while (*end != '/' && *end != '\0')
407 end++;
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;
414 if (last_char > 0)
415 canonical_path = canonical_path.Left(canonical_path.FindLast('/', last_char-1)+1);
416 } else if (element == "." || element == "") {
417 } else {
418 canonical_path += element;
419 canonical_path += '/';
421 ptr = end;
424 return canonical_path;
428 static PString CanonicaliseFilename(const PString & filename)
430 if (filename.IsEmpty())
431 return filename;
433 PINDEX p;
434 PString dirname;
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] == '/')
440 p++;
441 } else
442 p = 0;
444 return CanonicaliseDirectory(dirname) + filename(p, P_MAX_INDEX);
448 PInt64 PString::AsInt64(unsigned base) const
450 char * dummy;
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);
455 #else
456 return strtoq(theArray, &dummy, base);
457 #endif
460 PUInt64 PString::AsUnsigned64(unsigned base) const
462 char * dummy;
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);
467 #else
468 return strtouq(theArray, &dummy, base);
469 #endif
473 ///////////////////////////////////////////////////////////////////////////////
475 // timer
478 PTimeInterval PTimer::Tick()
481 #ifdef P_VXWORKS
482 struct timespec ts;
483 clock_gettime(0,&ts);
484 return (int)(ts.tv_sec*10000) + ts.tv_nsec/100000L;
485 #else
486 struct timeval tv;
487 ::gettimeofday (&tv, NULL);
488 return (PInt64)(tv.tv_sec) * 1000 + tv.tv_usec/1000L;
489 #endif // P_VXWORKS
494 ///////////////////////////////////////////////////////////////////////////////
496 // PDirectory
499 void PDirectory::CopyContents(const PDirectory & d)
501 if (d.entryInfo == NULL)
502 entryInfo = NULL;
503 else {
504 entryInfo = new PFileInfo;
505 *entryInfo = *d.entryInfo;
507 directory = NULL;
508 entryBuffer = NULL;
511 void PDirectory::Close()
513 if (directory != NULL) {
514 PAssert(closedir(directory) == 0, POperatingSystemError);
515 directory = NULL;
518 if (entryBuffer != NULL) {
519 free(entryBuffer);
520 entryBuffer = NULL;
523 if (entryInfo != NULL) {
524 delete entryInfo;
525 entryInfo = NULL;
529 void PDirectory::Construct ()
531 directory = NULL;
532 entryBuffer = NULL;
533 entryInfo = NULL;
535 PString::AssignContents(CanonicaliseDirectory(*this));
538 BOOL PDirectory::Open(int ScanMask)
541 if (directory != NULL)
542 Close();
544 scanMask = ScanMask;
546 if ((directory = opendir(theArray)) == NULL)
547 return FALSE;
549 entryBuffer = (struct dirent *)malloc(sizeof(struct dirent) + P_MAX_PATH);
550 entryInfo = new PFileInfo;
552 if (Next())
553 return TRUE;
555 Close();
556 return FALSE;
560 BOOL PDirectory::Next()
562 if (directory == NULL)
563 return FALSE;
565 do {
566 do {
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)
571 return FALSE;
572 if (entryPtr != entryBuffer)
573 return FALSE;
574 #elif P_HAS_POSIX_READDIR_R == 2
575 entryPtr = ::readdir_r(directory, entryBuffer);
576 if (entryPtr == NULL)
577 return FALSE;
578 #else
579 if ((entryPtr = ::readdir(directory)) == NULL)
580 return FALSE;
581 *entryBuffer = *entryPtr;
582 strcpy(entryBuffer->d_name, entryPtr->d_name);
583 #endif
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)
588 continue;
590 if (scanMask == PFileInfo::AllPermissions)
591 return TRUE;
592 } while ((entryInfo->type & scanMask) == 0);
594 return TRUE;
598 BOOL PDirectory::IsSubDir() const
600 if (entryInfo == NULL)
601 return FALSE;
603 return entryInfo->type == PFileInfo::SubDirectory;
606 BOOL PDirectory::Restart(int newScanMask)
608 scanMask = newScanMask;
609 if (directory != NULL)
610 rewinddir(directory);
611 return TRUE;
614 PString PDirectory::GetEntryName() const
616 if (entryBuffer == NULL)
617 return PString();
619 return entryBuffer->d_name;
623 BOOL PDirectory::GetInfo(PFileInfo & info) const
625 if (entryInfo == NULL)
626 return FALSE;
628 info = *entryInfo;
629 return TRUE;
633 BOOL PDirectory::Exists(const PString & p)
635 struct stat sbuf;
636 if (stat((const char *)p, &sbuf) != 0)
637 return FALSE;
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;
647 PString str = p;
648 if (p[last] == '/')
649 str = p.Left(last);
650 #ifdef P_VXWORKS
651 return mkdir(str) == 0;
652 #else
653 return mkdir(str, perm) == 0;
654 #endif
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
666 PString volume;
668 #if defined(P_QNX)
669 int fd;
670 char mounton[257];
672 if ((fd = open(operator+("."), O_RDONLY)) != -1) {
673 mounton[256] = 0;
674 devctl(fd, DCMD_FSYS_MOUNTED_ON, mounton, 256, 0);
675 close(fd);
676 volume = strdup(mounton);
679 #else
680 struct stat status;
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");
687 if (fp != NULL) {
688 struct mntent * mnt;
689 while ((mnt = getmntent(fp)) != NULL) {
690 if (stat(mnt->mnt_dir, &status) != -1 && status.st_dev == my_dev) {
691 volume = mnt->mnt_fsname;
692 break;
696 endmntent(fp);
698 #elif defined(P_SOLARIS)
700 FILE * fp = fopen("/etc/mnttab", "r");
701 if (fp != NULL) {
702 struct mnttab mnt;
703 while (getmntent(fp, &mnt) == 0) {
704 if (stat(mnt.mnt_mountp, &status) != -1 && status.st_dev == my_dev) {
705 volume = mnt.mnt_special;
706 break;
710 fclose(fp);
712 #elif defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_MACOS)
714 struct statfs * mnt;
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;
719 break;
723 #elif defined (P_AIX)
725 struct fstab * fs;
726 setfsent();
727 while ((fs = getfsent()) != NULL) {
728 if (stat(fs->fs_file, &status) != -1 && status.st_dev == my_dev) {
729 volume = fs->fs_spec;
730 break;
733 endfsent();
735 #elif defined (P_VXWORKS)
737 PAssertAlways("Get Volume - not implemented for VxWorks");
738 return PString::Empty();
740 #else
741 #warning Platform requires implemetation of GetVolume()
743 #endif
745 #endif
747 return volume;
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)
754 struct statfs fs;
756 if (statfs(operator+("."), &fs) == -1)
757 return FALSE;
759 clusterSize = fs.f_bsize;
760 total = fs.f_blocks*(PInt64)fs.f_bsize;
761 free = fs.f_bavail*(PInt64)fs.f_bsize;
762 return TRUE;
764 #elif defined(P_AIX) || defined(P_VXWORKS)
766 struct statfs fs;
767 if (statfs((char *) ((const char *)operator+(".") ), &fs) == -1)
768 return FALSE;
770 clusterSize = fs.f_bsize;
771 total = fs.f_blocks*(PInt64)fs.f_bsize;
772 free = fs.f_bavail*(PInt64)fs.f_bsize;
773 return TRUE;
775 #elif defined(P_SOLARIS)
777 struct statvfs buf;
778 if (statvfs(operator+("."), &buf) != 0)
779 return FALSE;
781 clusterSize = buf.f_frsize;
782 total = buf.f_blocks * buf.f_frsize;
783 free = buf.f_bfree * buf.f_frsize;
785 return TRUE;
787 #elif defined(P_IRIX)
789 struct statfs fs;
791 if (statfs(operator+("."), &fs, sizeof(struct statfs), 0) == -1)
792 return FALSE;
794 clusterSize = fs.f_bsize;
795 total = fs.f_blocks*(PInt64)fs.f_bsize;
796 free = fs.f_bfree*(PInt64)fs.f_bsize;
797 return TRUE;
799 #elif defined(P_QNX)
801 struct statvfs fs;
803 if (statvfs(operator+("."), &fs) == -1)
804 return FALSE;
806 clusterSize = fs.f_bsize;
807 total = fs.f_blocks*(PInt64)fs.f_bsize;
808 free = fs.f_bavail*(PInt64)fs.f_bsize;
809 return TRUE;
811 #else
813 #warning Platform requires implemetation of GetVolumeSpace()
814 return FALSE;
816 #endif
819 PDirectory PDirectory::GetParent() const
821 if (IsRoot())
822 return *this;
824 return *this + "..";
827 PStringArray PDirectory::GetPath() const
829 PStringArray path;
831 if (IsEmpty())
832 return path;
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++) {
840 if (!tokens[i])
841 path[count++] = tokens[i];
844 path.SetSize(count);
846 return path;
850 ///////////////////////////////////////////////////////////////////////////////
852 // PFile
855 void PFile::SetFilePath(const PString & newName)
857 PINDEX p;
859 if ((p = newName.FindLast('/')) == P_MAX_INDEX)
860 path = CanonicaliseDirectory("") + newName;
861 else
862 path = CanonicaliseDirectory(newName(0,p)) + newName(p+1, P_MAX_INDEX);
866 BOOL PFile::Open(OpenMode mode, int opt)
869 Close();
870 clear();
872 if (opt > 0)
873 removeOnClose = (opt & Temporary) != 0;
875 if (path.IsEmpty()) {
876 char templateStr[3+6+1];
877 strcpy(templateStr, "PWLXXXXXX");
878 #ifndef P_VXWORKS
879 #ifdef P_RTEMS
880 _reent _reent_data;
881 memset(&_reent_data, 0, sizeof(_reent_data));
882 os_handle = _mkstemp_r(&_reent_data, templateStr);
883 #else
884 os_handle = mkstemp(templateStr);
885 #endif // P_RTEMS
886 if (!ConvertOSError(os_handle))
887 return FALSE;
888 path = templateStr;
889 } else {
890 #else
891 static int number = 0;
892 sprintf(templateStr+3, "%06d", number++);
893 path = templateStr;
896 #endif // !P_VXWORKS
897 int oflags = 0;
898 switch (mode) {
899 case ReadOnly :
900 oflags |= O_RDONLY;
901 if (opt == ModeDefault)
902 opt = MustExist;
903 break;
904 case WriteOnly :
905 oflags |= O_WRONLY;
906 if (opt == ModeDefault)
907 opt = Create|Truncate;
908 break;
909 case ReadWrite :
910 oflags |= O_RDWR;
911 if (opt == ModeDefault)
912 opt = Create;
913 break;
915 default :
916 PAssertAlways(PInvalidParameter);
918 if ((opt&Create) != 0)
919 oflags |= O_CREAT;
920 if ((opt&Exclusive) != 0)
921 oflags |= O_EXCL;
922 if ((opt&Truncate) != 0)
923 oflags |= O_TRUNC;
926 if (!ConvertOSError(os_handle = PX_NewHandle(GetClass(), ::open(path, oflags, DEFAULT_FILE_MODE))))
927 return FALSE;
930 #ifndef P_VXWORKS
931 return ConvertOSError(::fcntl(os_handle, F_SETFD, 1));
932 #else
933 return TRUE;
934 #endif
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) {
947 errno = EINVAL;
948 return FALSE;
951 if (rename(oldname, oldname.GetPath() + newname) == 0)
952 return TRUE;
954 if (!force || errno == ENOENT || !Exists(newname))
955 return FALSE;
957 if (!Remove(newname, TRUE))
958 return FALSE;
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)
970 return TRUE;
972 if (errno == EXDEV)
973 return Copy(from, to, force) && Remove(from);
975 if (force && errno == EEXIST)
976 if (Remove(to, TRUE))
977 if (rename(from, to) == 0)
978 return TRUE;
980 return FALSE;
984 BOOL PFile::Exists(const PFilePath & name)
986 #ifdef P_VXWORKS
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();
992 if(exists == TRUE)
993 file.Close();
994 return exists;
995 #else
996 return access(name, 0) == 0;
997 #endif // P_VXWORKS
1001 BOOL PFile::Access(const PFilePath & name, OpenMode mode)
1003 #ifdef P_VXWORKS
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();
1009 if(access == TRUE)
1010 file.Close();
1011 return access;
1012 #else
1013 int accmode;
1015 switch (mode) {
1016 case ReadOnly :
1017 accmode = R_OK;
1018 break;
1020 case WriteOnly :
1021 accmode = W_OK;
1022 break;
1024 default :
1025 accmode = R_OK | W_OK;
1028 return access(name, accmode) == 0;
1029 #endif // P_VXWORKS
1033 BOOL PFile::GetInfo(const PFilePath & name, PFileInfo & status)
1035 status.type = PFileInfo::UnknownFileType;
1037 struct stat s;
1038 #ifdef P_VXWORKS
1039 if (stat(name, &s) != OK)
1040 #else
1041 if (lstat(name, &s) != 0)
1042 #endif // P_VXWORKS
1043 return FALSE;
1045 #ifndef P_VXWORKS
1046 if (S_ISLNK(s.st_mode)) {
1047 status.type = PFileInfo::SymbolicLink;
1048 if (stat(name, &s) != 0) {
1049 status.created = 0;
1050 status.modified = 0;
1051 status.accessed = 0;
1052 status.size = 0;
1053 status.permissions = PFileInfo::AllPermissions;
1054 return TRUE;
1057 else
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;
1080 return TRUE;
1084 BOOL PFile::SetPermissions(const PFilePath & name, int permissions)
1087 mode_t mode = 0;
1089 mode |= S_IROTH;
1090 mode |= S_IRGRP;
1092 if (permissions & PFileInfo::WorldExecute)
1093 mode |= S_IXOTH;
1094 if (permissions & PFileInfo::WorldWrite)
1095 mode |= S_IWOTH;
1096 if (permissions & PFileInfo::WorldRead)
1097 mode |= S_IROTH;
1099 if (permissions & PFileInfo::GroupExecute)
1100 mode |= S_IXGRP;
1101 if (permissions & PFileInfo::GroupWrite)
1102 mode |= S_IWGRP;
1103 if (permissions & PFileInfo::GroupRead)
1104 mode |= S_IRGRP;
1106 if (permissions & PFileInfo::UserExecute)
1107 mode |= S_IXUSR;
1108 if (permissions & PFileInfo::UserWrite)
1109 mode |= S_IWUSR;
1110 if (permissions & PFileInfo::UserRead)
1111 mode |= S_IRUSR;
1113 #ifdef P_VXWORKS
1114 PFile file(name, ReadOnly, MustExist);
1115 if (file.IsOpen())
1116 return (::ioctl(file.GetHandle(), FIOATTRIBSET, mode) >= 0);
1118 return FALSE;
1119 #else
1120 return chmod ((const char *)name, mode) == 0;
1121 #endif // P_VXWORKS
1124 ///////////////////////////////////////////////////////////////////////////////
1125 // PTextFile
1127 BOOL PTextFile::WriteLine (const PString & line)
1130 if (!Write((const char *)line, line.GetLength()))
1131 return FALSE;
1133 char ch = '\n';
1134 return Write(&ch, 1);
1138 BOOL PTextFile::ReadLine (PString & line)
1141 int len = 0;
1142 int ch;
1143 char * base, * ptr;
1145 while (1) {
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);
1151 return FALSE;
1153 if (ch == '\n') {
1154 *ptr = '\0';
1155 line.MakeMinimumSize();
1156 return TRUE;
1158 *ptr++ = ch;
1163 ///////////////////////////////////////////////////////////////////////////////
1164 // PFilePath
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)
1179 : PString()
1181 if (prefix == NULL)
1182 prefix = "tmp";
1184 PDirectory s(dir);
1185 if (dir == NULL)
1186 s = PDirectory("/tmp");
1188 #ifdef P_VXWORKS
1189 int number = 0;
1190 for (;;) {
1191 *this = s + prefix + psprintf("%06x", number++);
1192 if (!PFile::Exists(*this))
1193 break;
1195 #else
1196 PString p;
1197 srandom(getpid());
1198 for (;;) {
1199 *this = s + prefix + psprintf("%i_%06x", getpid(), random() % 1000000);
1200 if (!PFile::Exists(*this))
1201 break;
1203 #endif // P_VXWORKS
1207 void PFilePath::AssignContents(const PContainer & cont)
1209 PString::AssignContents(cont);
1210 PString::AssignContents(CanonicaliseFilename(*this));
1214 PString PFilePath::GetPath() const
1217 int i;
1219 PAssert((i = FindLast('/')) != P_MAX_INDEX, PInvalidArrayIndex);
1220 return Left(i+1);
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);
1238 if (p < 0 || l < 2)
1239 return PString("");
1240 else
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);
1250 else
1251 *this += type;
1255 PString PFilePath::GetFileName() const
1258 int i;
1260 if ((i = FindLast('/')) == P_MAX_INDEX)
1261 return *this;
1262 else
1263 return Right(GetLength()-i-1);
1267 PDirectory PFilePath::GetDirectory() const
1269 int i;
1271 if ((i = FindLast('/')) == P_MAX_INDEX)
1272 return "./";
1273 else
1274 return Left(i);
1278 BOOL PFilePath::IsValid(char c)
1280 return c != '/';
1284 BOOL PFilePath::IsValid(const PString & str)
1286 return str.Find('/') == P_MAX_INDEX;
1290 ///////////////////////////////////////////////////////////////////////////////
1291 // PConsoleChannel
1293 PConsoleChannel::PConsoleChannel()
1298 PConsoleChannel::PConsoleChannel(ConsoleType type)
1300 Open(type);
1304 BOOL PConsoleChannel::Open(ConsoleType type)
1306 switch (type) {
1307 case StandardInput :
1308 os_handle = 0;
1309 return TRUE;
1311 case StandardOutput :
1312 os_handle = 1;
1313 return TRUE;
1315 case StandardError :
1316 os_handle = 2;
1317 return TRUE;
1320 return FALSE;
1324 PString PConsoleChannel::GetName() const
1326 #ifdef P_VXWORKS
1327 PAssertAlways("PConsoleChannel::GetName - Not implemented for VxWorks");
1328 return PString("Not Implemented");
1329 #else
1330 return ttyname(os_handle);
1331 #endif // P_VXWORKS
1335 BOOL PConsoleChannel::Close()
1337 os_handle = -1;
1338 return TRUE;
1342 //////////////////////////////////////////////////////
1344 // PTime
1347 PTime::PTime()
1349 #ifdef P_VXWORKS
1350 struct timespec ts;
1351 clock_gettime(0,&ts);
1352 theTime = ts.tv_sec;
1353 microseconds = ts.tv_sec*10000 + ts.tv_nsec/100000L;
1354 #else
1355 struct timeval tv;
1356 gettimeofday(&tv, NULL);
1357 theTime = tv.tv_sec;
1358 microseconds = tv.tv_usec;
1359 #endif // P_VXWORKS
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)
1368 char buf[30];
1369 struct tm t;
1370 memset(&t, 0, sizeof(t));
1371 t.tm_hour = 20;
1372 t.tm_min = 12;
1373 t.tm_sec = 11;
1374 strftime(buf, sizeof(buf), "%X", &t);
1375 return strstr(buf, "20") != NULL;
1376 #else
1377 #warning No AMPM implementation
1378 return FALSE;
1379 #endif
1383 PString PTime::GetTimeAM()
1385 #if defined(P_USE_LANGINFO)
1386 return PString(nl_langinfo(AM_STR));
1387 #elif defined(P_USE_STRFTIME)
1388 char buf[30];
1389 struct tm t;
1390 memset(&t, 0, sizeof(t));
1391 t.tm_hour = 10;
1392 t.tm_min = 12;
1393 t.tm_sec = 11;
1394 strftime(buf, sizeof(buf), "%p", &t);
1395 return buf;
1396 #else
1397 #warning Using default AM string
1398 return "AM";
1399 #endif
1403 PString PTime::GetTimePM()
1405 #if defined(P_USE_LANGINFO)
1406 return PString(nl_langinfo(PM_STR));
1407 #elif defined(P_USE_STRFTIME)
1408 char buf[30];
1409 struct tm t;
1410 memset(&t, 0, sizeof(t));
1411 t.tm_hour = 20;
1412 t.tm_min = 12;
1413 t.tm_sec = 11;
1414 strftime(buf, sizeof(buf), "%p", &t);
1415 return buf;
1416 #else
1417 #warning Using default PM string
1418 return "PM";
1419 #endif
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;
1430 # endif
1431 char buffer[2];
1432 while (*p == '%' || isalpha(*p))
1433 p++;
1434 buffer[0] = *p;
1435 buffer[1] = '\0';
1436 return PString(buffer);
1437 #elif defined(P_USE_STRFTIME)
1438 char buf[30];
1439 struct tm t;
1440 memset(&t, 0, sizeof(t));
1441 t.tm_hour = 10;
1442 t.tm_min = 11;
1443 t.tm_sec = 12;
1444 strftime(buf, sizeof(buf), "%X", &t);
1445 char * sp = strstr(buf, "11") + 2;
1446 char * ep = sp;
1447 while (*ep != '\0' && !isdigit(*ep))
1448 ep++;
1449 return PString(sp, ep-sp);
1450 #else
1451 #warning Using default time separator
1452 return ":";
1453 #endif
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);
1461 # else
1462 char * p = _time_info->date;
1463 # endif
1465 while (*p == '%')
1466 p++;
1467 switch (tolower(*p)) {
1468 case 'd':
1469 return DayMonthYear;
1470 case 'y':
1471 return YearMonthDay;
1472 case 'm':
1473 default:
1474 break;
1476 return MonthDayYear;
1478 #elif defined(P_USE_STRFTIME)
1479 char buf[30];
1480 struct tm t;
1481 memset(&t, 0, sizeof(t));
1482 t.tm_mday = 22;
1483 t.tm_mon = 10;
1484 t.tm_year = 99;
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;
1494 #else
1495 #warning Using default date order
1496 return DayMonthYear;
1497 #endif
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);
1505 # else
1506 char * p = _time_info->date;
1507 # endif
1508 char buffer[2];
1509 while (*p == '%' || isalpha(*p))
1510 p++;
1511 buffer[0] = *p;
1512 buffer[1] = '\0';
1513 return PString(buffer);
1514 #elif defined(P_USE_STRFTIME)
1515 char buf[30];
1516 struct tm t;
1517 memset(&t, 0, sizeof(t));
1518 t.tm_mday = 22;
1519 t.tm_mon = 10;
1520 t.tm_year = 99;
1521 strftime(buf, sizeof(buf), "%x", &t);
1522 char * sp = strstr(buf, "22") + 2;
1523 char * ep = sp;
1524 while (*ep != '\0' && !isdigit(*ep))
1525 ep++;
1526 return PString(sp, ep-sp);
1527 #else
1528 #warning Using default date separator
1529 return "/";
1530 #endif
1533 PString PTime::GetDayName(PTime::Weekdays day, NameType type)
1535 #if defined(P_USE_LANGINFO)
1536 return PString(
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)
1546 char buf[30];
1547 struct tm t;
1548 memset(&t, 0, sizeof(t));
1549 t.tm_wday = day;
1550 strftime(buf, sizeof(buf), type == Abbreviated ? "%a" : "%A", &t);
1551 return buf;
1552 #else
1553 #warning Using default day names
1554 static char *defaultNames[] = {
1555 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
1556 "Saturday"
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]);
1564 #endif
1567 PString PTime::GetMonthName(PTime::Months month, NameType type)
1569 #if defined(P_USE_LANGINFO)
1570 return PString(
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)
1578 char buf[30];
1579 struct tm t;
1580 memset(&t, 0, sizeof(t));
1581 t.tm_mon = month-1;
1582 strftime(buf, sizeof(buf), type == Abbreviated ? "%b" : "%B", &t);
1583 return buf;
1584 #else
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]);
1596 #endif
1600 BOOL PTime::IsDaylightSavings()
1602 time_t theTime = ::time(NULL);
1603 struct tm ts;
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)
1612 return tz;
1613 else
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)
1616 time_t t;
1617 time(&t);
1618 struct tm ts;
1619 struct tm * tm = os_localtime(&t, &ts);
1620 int tz = tm->tm_gmtoff/60;
1621 if (type == StandardTime && tm->tm_isdst)
1622 return tz-60;
1623 if (type != StandardTime && !tm->tm_isdst)
1624 return tz + 60;
1625 return tz;
1626 #elif defined(P_SUN4)
1627 struct timeb tb;
1628 ftime(&tb);
1629 if (type == StandardTime || tb.dstflag == 0)
1630 return -tb.timezone;
1631 else
1632 return -tb.timezone + 60;
1633 #else
1634 #warning No timezone information
1635 return 0;
1636 #endif
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];
1643 if (str != NULL)
1644 return str;
1645 return PString();
1646 #elif defined(P_USE_STRFTIME)
1647 char buf[30];
1648 struct tm t;
1649 memset(&t, 0, sizeof(t));
1650 t.tm_isdst = type != StandardTime;
1651 strftime(buf, sizeof(buf), "%Z", &t);
1652 return buf;
1653 #else
1654 #warning No timezone name information
1655 return PString();
1656 #endif
1659 // note that PX_tm is local storage inside the PTime instance
1661 #ifdef P_PTHREADS
1662 struct tm * PTime::os_localtime(const time_t * clock, struct tm * ts)
1664 return ::localtime_r(clock, ts);
1666 #else
1667 struct tm * PTime::os_localtime(const time_t * clock, struct tm *)
1669 return ::localtime(clock);
1671 #endif
1673 #ifdef P_PTHREADS
1674 struct tm * PTime::os_gmtime(const time_t * clock, struct tm * ts)
1676 return ::gmtime_r(clock, ts);
1678 #else
1679 struct tm * PTime::os_gmtime(const time_t * clock, struct tm *)
1681 return ::gmtime(clock);
1683 #endif
1685 // End Of File ///////////////////////////////////////////////////////////////