Uncommented beaudio code
[pwlib.git] / src / ptlib / unix / osutil.cxx
blobbcc59351cb3d1ca3fafe5b49e3aa0cfe5ec0c94d
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.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
120 * BeOS port changes.
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
153 * BeOS port changes.
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
165 * FreeBSD port.
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.
187 #define _OSUTIL_CXX
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"
204 #if defined(P_LINUX)
205 #ifndef _REENTRANT
206 #define _REENTRANT
207 #endif
208 #elif defined(P_SOLARIS)
209 #define _POSIX_PTHREAD_SEMANTICS
210 #endif
212 #include <ptlib.h>
215 #include <fcntl.h>
216 #ifdef P_VXWORKS
217 #include <sys/times.h>
218 #else
219 #include <time.h>
220 #include <sys/time.h>
221 #endif
222 #include <ctype.h>
224 #if defined(P_LINUX)
226 #include <mntent.h>
227 #include <sys/vfs.h>
229 #define P_HAS_READDIR_R
231 #if (__GNUC_MINOR__ < 7 && __GNUC__ < 3)
232 #include <localeinfo.h>
233 #else
234 #define P_USE_LANGINFO
235 #endif
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
246 #elif defined(P_AIX)
247 #define P_USE_STRFTIME
249 #include <fstab.h>
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>
270 #include <stdio.h>
271 #include <mntent.h>
273 #elif defined(P_VXWORKS)
274 #define P_USE_STRFTIME
276 #elif defined(P_RTEMS)
277 #define P_USE_STRFTIME
278 #include <time.h>
279 #include <stdio.h>
280 #define random() rand()
281 #define srandom(a) srand(a)
283 #elif defined(P_QNX)
284 #include <sys/dcmd_blk.h>
285 #include <sys/statvfs.h>
286 #define P_USE_STRFTIME
287 #endif
289 #ifdef P_USE_LANGINFO
290 #include <langinfo.h>
291 #endif
293 #define LINE_SIZE_STEP 100
295 #define DEFAULT_FILE_MODE (S_IRUSR|S_IWUSR|S_IROTH|S_IRGRP)
297 #if !P_USE_INLINES
298 #include "ptlib/osutil.inl"
299 #ifdef _WIN32
300 #include "ptlib/win32/ptlib/ptlib.inl"
301 #else
302 #include "ptlib/unix/ptlib/ptlib.inl"
303 #endif
304 #endif
306 #ifdef P_SUN4
307 extern "C" {
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" };
315 #endif
317 #define new PNEW
320 int PX_NewHandle(const char * clsName, int fd)
322 if (fd < 0)
323 return fd;
325 static int lowWaterMark = INT_MAX;
326 static int highWaterMark = 0;
327 if (fd > highWaterMark) {
328 highWaterMark = fd;
329 lowWaterMark = fd;
331 int maxHandles = PProcess::Current().GetMaxHandles();
332 if (fd < (maxHandles-maxHandles/20))
333 PTRACE(4, "PWLib\tFile handle high water mark set: " << fd << ' ' << clsName);
334 else
335 PTRACE(1, "PWLib\tFile handle high water mark within 5% of maximum: " << fd << ' ' << clsName);
338 if (fd < lowWaterMark) {
339 lowWaterMark = fd;
340 PTRACE(4, "PWLib\tFile handle low water mark set: " << fd << ' ' << clsName);
343 return fd;
347 static PString CanonicaliseDirectory (const PString & path)
350 PString canonical_path;
352 if (path[0] == '/')
353 canonical_path = '/';
354 else {
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;
364 const char * end;
366 for (;;) {
367 // ignore slashes
368 while (*ptr == '/' && *ptr != '\0')
369 ptr++;
371 // finished if end of string
372 if (*ptr == '\0')
373 break;
375 // collect non-slash characters
376 end = ptr;
377 while (*end != '/' && *end != '\0')
378 end++;
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;
385 if (last_char > 0)
386 canonical_path = canonical_path.Left(canonical_path.FindLast('/', last_char-1)+1);
387 } else if (element == "." || element == "") {
388 } else {
389 canonical_path += element;
390 canonical_path += '/';
392 ptr = end;
395 return canonical_path;
399 static PString CanonicaliseFilename(const PString & filename)
401 if (filename.IsEmpty())
402 return filename;
404 PINDEX p;
405 PString dirname;
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] == '/')
411 p++;
412 } else
413 p = 0;
415 return CanonicaliseDirectory(dirname) + filename(p, P_MAX_INDEX);
419 PInt64 PString::AsInt64(unsigned base) const
421 char * dummy;
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);
426 #else
427 return strtoq(theArray, &dummy, base);
428 #endif
431 PUInt64 PString::AsUnsigned64(unsigned base) const
433 char * dummy;
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);
438 #else
439 return strtouq(theArray, &dummy, base);
440 #endif
444 ///////////////////////////////////////////////////////////////////////////////
446 // timer
449 PTimeInterval PTimer::Tick()
452 #ifdef P_VXWORKS
453 struct timespec ts;
454 clock_gettime(0,&ts);
455 return (int)(ts.tv_sec*10000) + ts.tv_nsec/100000L;
456 #else
457 struct timeval tv;
458 ::gettimeofday (&tv, NULL);
459 return (PInt64)(tv.tv_sec) * 1000 + tv.tv_usec/1000L;
460 #endif // P_VXWORKS
465 ///////////////////////////////////////////////////////////////////////////////
467 // PDirectory
470 void PDirectory::CopyContents(const PDirectory & d)
472 if (d.entryInfo == NULL)
473 entryInfo = NULL;
474 else {
475 entryInfo = new PFileInfo;
476 *entryInfo = *d.entryInfo;
478 directory = NULL;
479 entryBuffer = NULL;
482 void PDirectory::Close()
484 if (directory != NULL) {
485 PAssert(closedir(directory) == 0, POperatingSystemError);
486 directory = NULL;
489 if (entryBuffer != NULL) {
490 free(entryBuffer);
491 entryBuffer = NULL;
494 if (entryInfo != NULL) {
495 delete entryInfo;
496 entryInfo = NULL;
500 void PDirectory::Construct ()
503 directory = NULL;
504 entryBuffer = NULL;
505 entryInfo = NULL;
507 PString::AssignContents(CanonicaliseDirectory(*this));
510 BOOL PDirectory::Open(int ScanMask)
513 if (directory != NULL)
514 Close();
516 scanMask = ScanMask;
518 if ((directory = opendir(theArray)) == NULL)
519 return FALSE;
521 entryBuffer = (struct dirent *)malloc(sizeof(struct dirent) + P_MAX_PATH);
522 entryInfo = new PFileInfo;
524 if (Next())
525 return TRUE;
527 Close();
528 return FALSE;
532 BOOL PDirectory::Next()
534 if (directory == NULL)
535 return FALSE;
537 do {
538 do {
539 struct dirent * entryPtr;
540 entryBuffer->d_name[0] = '\0';
541 #ifdef P_HAS_READDIR_R
542 if (::readdir_r(directory, entryBuffer, &entryPtr) != 0)
543 return FALSE;
544 if (entryPtr != entryBuffer)
545 return FALSE;
546 #else
547 if ((entryPtr = readdir(directory)) == NULL)
548 return FALSE;
549 *entryBuffer = *entryPtr;
550 strcpy(entryBuffer->d_name, entryPtr->d_name);
551 #endif
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)
556 continue;
558 if (scanMask == PFileInfo::AllPermissions)
559 return TRUE;
560 } while ((entryInfo->type & scanMask) == 0);
562 return TRUE;
566 BOOL PDirectory::IsSubDir() const
568 if (entryInfo == NULL)
569 return FALSE;
571 return entryInfo->type == PFileInfo::SubDirectory;
574 BOOL PDirectory::Restart(int newScanMask)
576 scanMask = newScanMask;
577 if (directory != NULL)
578 rewinddir(directory);
579 return TRUE;
582 PString PDirectory::GetEntryName() const
584 if (entryBuffer == NULL)
585 return PString();
587 return entryBuffer->d_name;
591 BOOL PDirectory::GetInfo(PFileInfo & info) const
593 info = *entryInfo;
594 return TRUE;
598 BOOL PDirectory::Exists(const PString & p)
600 struct stat sbuf;
601 if (stat((const char *)p, &sbuf) != 0)
602 return FALSE;
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;
612 PString str = p;
613 if (p[last] == '/')
614 str = p.Left(last);
615 #ifdef P_VXWORKS
616 return mkdir(str) == 0;
617 #else
618 return mkdir(str, perm) == 0;
619 #endif
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
631 PString volume;
633 #if defined(P_QNX)
634 int fd;
635 char mounton[257];
637 if ((fd = open(operator+("."), O_RDONLY)) != -1) {
638 mounton[256] = 0;
639 devctl(fd, DCMD_FSYS_MOUNTED_ON, mounton, 256, 0);
640 close(fd);
641 volume = strdup(mounton);
644 #else
645 struct stat status;
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");
652 if (fp != NULL) {
653 struct mntent * mnt;
654 while ((mnt = getmntent(fp)) != NULL) {
655 if (stat(mnt->mnt_dir, &status) != -1 && status.st_dev == my_dev) {
656 volume = mnt->mnt_fsname;
657 break;
661 endmntent(fp);
663 #elif defined(P_SOLARIS)
665 FILE * fp = fopen("/etc/mnttab", "r");
666 if (fp != NULL) {
667 struct mnttab mnt;
668 while (getmntent(fp, &mnt) == 0) {
669 if (stat(mnt.mnt_mountp, &status) != -1 && status.st_dev == my_dev) {
670 volume = mnt.mnt_special;
671 break;
675 fclose(fp);
677 #elif defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_MACOS)
679 struct statfs * mnt;
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;
684 break;
688 #elif defined (P_AIX)
690 struct fstab * fs;
691 setfsent();
692 while ((fs = getfsent()) != NULL) {
693 if (stat(fs->fs_file, &status) != -1 && status.st_dev == my_dev) {
694 volume = fs->fs_spec;
695 break;
698 endfsent();
700 #elif defined (P_VXWORKS)
702 PAssertAlways("Get Volume - not implemented for VxWorks");
703 return PString::Empty();
705 #else
706 #warning Platform requires implemetation of GetVolume()
708 #endif
710 #endif
712 return volume;
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)
719 struct statfs fs;
721 if (statfs(operator+("."), &fs) == -1)
722 return FALSE;
724 clusterSize = fs.f_bsize;
725 total = fs.f_blocks*(PInt64)fs.f_bsize;
726 free = fs.f_bavail*(PInt64)fs.f_bsize;
727 return TRUE;
729 #elif defined(P_AIX) || defined(P_VXWORKS)
731 struct statfs fs;
732 if (statfs((char *) ((const char *)operator+(".") ), &fs) == -1)
733 return FALSE;
735 clusterSize = fs.f_bsize;
736 total = fs.f_blocks*(PInt64)fs.f_bsize;
737 free = fs.f_bavail*(PInt64)fs.f_bsize;
738 return TRUE;
740 #elif defined(P_SOLARIS)
742 struct statvfs buf;
743 if (statvfs(operator+("."), &buf) != 0)
744 return FALSE;
746 clusterSize = buf.f_frsize;
747 total = buf.f_blocks * buf.f_frsize;
748 free = buf.f_bfree * buf.f_frsize;
750 return TRUE;
752 #elif defined(P_IRIX)
754 struct statfs fs;
756 if (statfs(operator+("."), &fs, sizeof(struct statfs), 0) == -1)
757 return FALSE;
759 clusterSize = fs.f_bsize;
760 total = fs.f_blocks*(PInt64)fs.f_bsize;
761 free = fs.f_bfree*(PInt64)fs.f_bsize;
762 return TRUE;
764 #elif defined(P_QNX)
766 struct statvfs fs;
768 if (statvfs(operator+("."), &fs) == -1)
769 return FALSE;
771 clusterSize = fs.f_bsize;
772 total = fs.f_blocks*(PInt64)fs.f_bsize;
773 free = fs.f_bavail*(PInt64)fs.f_bsize;
774 return TRUE;
776 #else
778 #warning Platform requires implemetation of GetVolumeSpace()
779 return FALSE;
781 #endif
784 PDirectory PDirectory::GetParent() const
786 if (IsRoot())
787 return *this;
789 return *this + "..";
792 PStringArray PDirectory::GetPath() const
794 PStringArray path;
796 if (IsEmpty())
797 return path;
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++) {
805 if (!tokens[i])
806 path[count++] = tokens[i];
809 path.SetSize(count);
811 return path;
815 ///////////////////////////////////////////////////////////////////////////////
817 // PFile
820 void PFile::SetFilePath(const PString & newName)
822 PINDEX p;
824 if ((p = newName.FindLast('/')) == P_MAX_INDEX)
825 path = CanonicaliseDirectory("") + newName;
826 else
827 path = CanonicaliseDirectory(newName(0,p)) + newName(p+1, P_MAX_INDEX);
831 BOOL PFile::Open(OpenMode mode, int opt)
834 Close();
835 clear();
837 if (opt > 0)
838 removeOnClose = (opt & Temporary) != 0;
840 if (path.IsEmpty()) {
841 char templateStr[3+6+1];
842 strcpy(templateStr, "PWL");
843 #ifndef P_VXWORKS
844 #ifdef P_RTEMS
845 _reent _reent_data;
846 memset(&_reent_data, 0, sizeof(_reent_data));
847 os_handle = _mkstemp_r(&_reent_data, templateStr);
848 #else
849 os_handle = mkstemp(templateStr);
850 #endif // P_RTEMS
851 if (!ConvertOSError(os_handle))
852 return FALSE;
854 } else {
855 #else
856 static int number = 0;
857 sprintf(templateStr+3, "%06d", number++);
858 path = templateStr;
861 #endif // !P_VXWORKS
862 int oflags = 0;
863 switch (mode) {
864 case ReadOnly :
865 oflags |= O_RDONLY;
866 if (opt == ModeDefault)
867 opt = MustExist;
868 break;
869 case WriteOnly :
870 oflags |= O_WRONLY;
871 if (opt == ModeDefault)
872 opt = Create|Truncate;
873 break;
874 case ReadWrite :
875 oflags |= O_RDWR;
876 if (opt == ModeDefault)
877 opt = Create;
878 break;
880 default :
881 PAssertAlways(PInvalidParameter);
883 if ((opt&Create) != 0)
884 oflags |= O_CREAT;
885 if ((opt&Exclusive) != 0)
886 oflags |= O_EXCL;
887 if ((opt&Truncate) != 0)
888 oflags |= O_TRUNC;
891 if (!ConvertOSError(os_handle = PX_NewHandle(GetClass(), ::open(path, oflags, DEFAULT_FILE_MODE))))
892 return FALSE;
895 #ifndef P_VXWORKS
896 return ConvertOSError(::fcntl(os_handle, F_SETFD, 1));
897 #else
898 return TRUE;
899 #endif
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) {
912 errno = EINVAL;
913 return FALSE;
916 if (rename(oldname, oldname.GetPath() + newname) == 0)
917 return TRUE;
919 if (!force || errno == ENOENT || !Exists(newname))
920 return FALSE;
922 if (!Remove(newname, TRUE))
923 return FALSE;
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)
935 return TRUE;
937 if (errno == EXDEV)
938 return Copy(from, to, force) && Remove(from);
940 if (force && errno == EEXIST)
941 if (Remove(to, TRUE))
942 if (rename(from, to) == 0)
943 return TRUE;
945 return FALSE;
949 BOOL PFile::Exists(const PFilePath & name)
951 #ifdef P_VXWORKS
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();
957 if(exists == TRUE)
958 file.Close();
959 return exists;
960 #else
961 return access(name, 0) == 0;
962 #endif // P_VXWORKS
966 BOOL PFile::Access(const PFilePath & name, OpenMode mode)
968 #ifdef P_VXWORKS
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();
974 if(access == TRUE)
975 file.Close();
976 return access;
977 #else
978 int accmode;
980 switch (mode) {
981 case ReadOnly :
982 accmode = R_OK;
983 break;
985 case WriteOnly :
986 accmode = W_OK;
987 break;
989 default :
990 accmode = R_OK | W_OK;
993 return access(name, accmode) == 0;
994 #endif // P_VXWORKS
998 BOOL PFile::GetInfo(const PFilePath & name, PFileInfo & status)
1000 status.type = PFileInfo::UnknownFileType;
1002 struct stat s;
1003 #ifdef P_VXWORKS
1004 if (stat(name, &s) != OK)
1005 #else
1006 if (lstat(name, &s) != 0)
1007 #endif // P_VXWORKS
1008 return FALSE;
1010 #ifndef P_VXWORKS
1011 if (S_ISLNK(s.st_mode)) {
1012 status.type = PFileInfo::SymbolicLink;
1013 if (stat(name, &s) != 0) {
1014 status.created = 0;
1015 status.modified = 0;
1016 status.accessed = 0;
1017 status.size = 0;
1018 status.permissions = PFileInfo::AllPermissions;
1019 return TRUE;
1022 else
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;
1045 return TRUE;
1049 BOOL PFile::SetPermissions(const PFilePath & name, int permissions)
1052 mode_t mode = 0;
1054 mode |= S_IROTH;
1055 mode |= S_IRGRP;
1057 if (permissions & PFileInfo::WorldExecute)
1058 mode |= S_IXOTH;
1059 if (permissions & PFileInfo::WorldWrite)
1060 mode |= S_IWOTH;
1061 if (permissions & PFileInfo::WorldRead)
1062 mode |= S_IROTH;
1064 if (permissions & PFileInfo::GroupExecute)
1065 mode |= S_IXGRP;
1066 if (permissions & PFileInfo::GroupWrite)
1067 mode |= S_IWGRP;
1068 if (permissions & PFileInfo::GroupRead)
1069 mode |= S_IRGRP;
1071 if (permissions & PFileInfo::UserExecute)
1072 mode |= S_IXUSR;
1073 if (permissions & PFileInfo::UserWrite)
1074 mode |= S_IWUSR;
1075 if (permissions & PFileInfo::UserRead)
1076 mode |= S_IRUSR;
1078 #ifdef P_VXWORKS
1079 PFile file(name, ReadOnly, MustExist);
1080 if (file.IsOpen())
1081 return (::ioctl(file.GetHandle(), FIOATTRIBSET, mode) >= 0);
1083 return FALSE;
1084 #else
1085 return chmod ((const char *)name, mode) == 0;
1086 #endif // P_VXWORKS
1089 ///////////////////////////////////////////////////////////////////////////////
1090 // PTextFile
1092 BOOL PTextFile::WriteLine (const PString & line)
1095 if (!Write((const char *)line, line.GetLength()))
1096 return FALSE;
1098 char ch = '\n';
1099 return Write(&ch, 1);
1103 BOOL PTextFile::ReadLine (PString & line)
1106 int len = 0;
1107 int ch;
1108 char * base, * ptr;
1110 while (1) {
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);
1116 return FALSE;
1118 if (ch == '\n') {
1119 *ptr = '\0';
1120 line.MakeMinimumSize();
1121 return TRUE;
1123 *ptr++ = ch;
1128 ///////////////////////////////////////////////////////////////////////////////
1129 // PFilePath
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)
1144 : PString()
1146 if (prefix == NULL)
1147 prefix = "tmp";
1149 PDirectory s(dir);
1150 if (dir == NULL)
1151 s = PDirectory("/tmp");
1153 #ifdef P_VXWORKS
1154 int number = 0;
1155 for (;;) {
1156 *this = s + prefix + psprintf("%06x", number++);
1157 if (!PFile::Exists(*this))
1158 break;
1160 #else
1161 PString p;
1162 srandom(getpid());
1163 for (;;) {
1164 *this = s + prefix + psprintf("%i_%06x", getpid(), random() % 1000000);
1165 if (!PFile::Exists(*this))
1166 break;
1168 #endif // P_VXWORKS
1172 void PFilePath::AssignContents(const PContainer & cont)
1174 PString::AssignContents(cont);
1175 PString::AssignContents(CanonicaliseFilename(*this));
1179 PString PFilePath::GetPath() const
1182 int i;
1184 PAssert((i = FindLast('/')) != P_MAX_INDEX, PInvalidArrayIndex);
1185 return Left(i+1);
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);
1203 if (p < 0 || l < 2)
1204 return PString("");
1205 else
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);
1215 else
1216 *this += type;
1220 PString PFilePath::GetFileName() const
1223 int i;
1225 if ((i = FindLast('/')) == P_MAX_INDEX)
1226 return *this;
1227 else
1228 return Right(GetLength()-i-1);
1232 PDirectory PFilePath::GetDirectory() const
1234 int i;
1236 if ((i = FindLast('/')) == P_MAX_INDEX)
1237 return "./";
1238 else
1239 return Left(i);
1243 BOOL PFilePath::IsValid(char c)
1245 return c != '/';
1249 BOOL PFilePath::IsValid(const PString & str)
1251 return str.Find('/') == P_MAX_INDEX;
1255 ///////////////////////////////////////////////////////////////////////////////
1256 // PConsoleChannel
1258 PConsoleChannel::PConsoleChannel()
1263 PConsoleChannel::PConsoleChannel(ConsoleType type)
1265 Open(type);
1269 BOOL PConsoleChannel::Open(ConsoleType type)
1271 switch (type) {
1272 case StandardInput :
1273 os_handle = 0;
1274 return TRUE;
1276 case StandardOutput :
1277 os_handle = 1;
1278 return TRUE;
1280 case StandardError :
1281 os_handle = 2;
1282 return TRUE;
1285 return FALSE;
1289 PString PConsoleChannel::GetName() const
1291 #ifdef P_VXWORKS
1292 PAssertAlways("PConsoleChannel::GetName - Not implemented for VxWorks");
1293 return PString("Not Implemented");
1294 #else
1295 return ttyname(os_handle);
1296 #endif // P_VXWORKS
1300 BOOL PConsoleChannel::Close()
1302 os_handle = -1;
1303 return TRUE;
1307 //////////////////////////////////////////////////////
1309 // PTime
1312 PTime::PTime()
1314 #ifdef P_VXWORKS
1315 struct timespec ts;
1316 clock_gettime(0,&ts);
1317 theTime = ts.tv_sec;
1318 microseconds = ts.tv_sec*10000 + ts.tv_nsec/100000L;
1319 #else
1320 struct timeval tv;
1321 gettimeofday(&tv, NULL);
1322 theTime = tv.tv_sec;
1323 microseconds = tv.tv_usec;
1324 #endif // P_VXWORKS
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)
1333 char buf[30];
1334 struct tm t;
1335 memset(&t, 0, sizeof(t));
1336 t.tm_hour = 20;
1337 t.tm_min = 12;
1338 t.tm_sec = 11;
1339 strftime(buf, sizeof(buf), "%X", &t);
1340 return strstr(buf, "20") != NULL;
1341 #else
1342 #warning No AMPM implementation
1343 return FALSE;
1344 #endif
1348 PString PTime::GetTimeAM()
1350 #if defined(P_USE_LANGINFO)
1351 return PString(nl_langinfo(AM_STR));
1352 #elif defined(P_USE_STRFTIME)
1353 char buf[30];
1354 struct tm t;
1355 memset(&t, 0, sizeof(t));
1356 t.tm_hour = 10;
1357 t.tm_min = 12;
1358 t.tm_sec = 11;
1359 strftime(buf, sizeof(buf), "%p", &t);
1360 return buf;
1361 #else
1362 #warning Using default AM string
1363 return "AM";
1364 #endif
1368 PString PTime::GetTimePM()
1370 #if defined(P_USE_LANGINFO)
1371 return PString(nl_langinfo(PM_STR));
1372 #elif defined(P_USE_STRFTIME)
1373 char buf[30];
1374 struct tm t;
1375 memset(&t, 0, sizeof(t));
1376 t.tm_hour = 20;
1377 t.tm_min = 12;
1378 t.tm_sec = 11;
1379 strftime(buf, sizeof(buf), "%p", &t);
1380 return buf;
1381 #else
1382 #warning Using default PM string
1383 return "PM";
1384 #endif
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;
1395 # endif
1396 char buffer[2];
1397 while (*p == '%' || isalpha(*p))
1398 p++;
1399 buffer[0] = *p;
1400 buffer[1] = '\0';
1401 return PString(buffer);
1402 #elif defined(P_USE_STRFTIME)
1403 char buf[30];
1404 struct tm t;
1405 memset(&t, 0, sizeof(t));
1406 t.tm_hour = 10;
1407 t.tm_min = 11;
1408 t.tm_sec = 12;
1409 strftime(buf, sizeof(buf), "%X", &t);
1410 char * sp = strstr(buf, "11") + 2;
1411 char * ep = sp;
1412 while (*ep != '\0' && !isdigit(*ep))
1413 ep++;
1414 return PString(sp, ep-sp);
1415 #else
1416 #warning Using default time separator
1417 return ":";
1418 #endif
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);
1426 # else
1427 char * p = _time_info->date;
1428 # endif
1430 while (*p == '%')
1431 p++;
1432 switch (tolower(*p)) {
1433 case 'd':
1434 return DayMonthYear;
1435 case 'y':
1436 return YearMonthDay;
1437 case 'm':
1438 default:
1439 break;
1441 return MonthDayYear;
1443 #elif defined(P_USE_STRFTIME)
1444 char buf[30];
1445 struct tm t;
1446 memset(&t, 0, sizeof(t));
1447 t.tm_mday = 22;
1448 t.tm_mon = 10;
1449 t.tm_year = 99;
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;
1459 #else
1460 #warning Using default date order
1461 return DayMonthYear;
1462 #endif
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);
1470 # else
1471 char * p = _time_info->date;
1472 # endif
1473 char buffer[2];
1474 while (*p == '%' || isalpha(*p))
1475 p++;
1476 buffer[0] = *p;
1477 buffer[1] = '\0';
1478 return PString(buffer);
1479 #elif defined(P_USE_STRFTIME)
1480 char buf[30];
1481 struct tm t;
1482 memset(&t, 0, sizeof(t));
1483 t.tm_mday = 22;
1484 t.tm_mon = 10;
1485 t.tm_year = 99;
1486 strftime(buf, sizeof(buf), "%x", &t);
1487 char * sp = strstr(buf, "22") + 2;
1488 char * ep = sp;
1489 while (*ep != '\0' && !isdigit(*ep))
1490 ep++;
1491 return PString(sp, ep-sp);
1492 #else
1493 #warning Using default date separator
1494 return "/";
1495 #endif
1498 PString PTime::GetDayName(PTime::Weekdays day, NameType type)
1500 #if defined(P_USE_LANGINFO)
1501 return PString(
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)
1511 char buf[30];
1512 struct tm t;
1513 memset(&t, 0, sizeof(t));
1514 t.tm_wday = day;
1515 strftime(buf, sizeof(buf), type == Abbreviated ? "%a" : "%A", &t);
1516 return buf;
1517 #else
1518 #warning Using default day names
1519 static char *defaultNames[] = {
1520 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
1521 "Saturday"
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]);
1529 #endif
1532 PString PTime::GetMonthName(PTime::Months month, NameType type)
1534 #if defined(P_USE_LANGINFO)
1535 return PString(
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)
1543 char buf[30];
1544 struct tm t;
1545 memset(&t, 0, sizeof(t));
1546 t.tm_mon = month-1;
1547 strftime(buf, sizeof(buf), type == Abbreviated ? "%b" : "%B", &t);
1548 return buf;
1549 #else
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]);
1561 #endif
1565 BOOL PTime::IsDaylightSavings()
1567 time_t theTime = ::time(NULL);
1568 struct tm ts;
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)
1577 return tz;
1578 else
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)
1581 time_t t;
1582 time(&t);
1583 struct tm ts;
1584 struct tm * tm = os_localtime(&t, &ts);
1585 int tz = tm->tm_gmtoff/60;
1586 if (type == StandardTime && tm->tm_isdst)
1587 return tz-60;
1588 if (type != StandardTime && !tm->tm_isdst)
1589 return tz + 60;
1590 return tz;
1591 #elif defined(P_SUN4)
1592 struct timeb tb;
1593 ftime(&tb);
1594 if (type == StandardTime || tb.dstflag == 0)
1595 return -tb.timezone;
1596 else
1597 return -tb.timezone + 60;
1598 #else
1599 #warning No timezone information
1600 return 0;
1601 #endif
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];
1608 if (str != NULL)
1609 return str;
1610 return PString();
1611 #elif defined(P_USE_STRFTIME)
1612 char buf[30];
1613 struct tm t;
1614 memset(&t, 0, sizeof(t));
1615 t.tm_isdst = type != StandardTime;
1616 strftime(buf, sizeof(buf), "%Z", &t);
1617 return buf;
1618 #else
1619 #warning No timezone name information
1620 return PString();
1621 #endif
1624 // note that PX_tm is local storage inside the PTime instance
1626 #ifdef P_PTHREADS
1627 struct tm * PTime::os_localtime(const time_t * clock, struct tm * ts)
1629 #ifdef P_MACOSX
1630 #warning LOCALTIME_R NOT DEFINED
1631 return ::localtime(clock);
1632 #else
1633 return ::localtime_r(clock, ts);
1634 #endif
1636 #else
1637 struct tm * PTime::os_localtime(const time_t * clock, struct tm *)
1639 return ::localtime(clock);
1641 #endif
1643 #ifdef P_PTHREADS
1644 struct tm * PTime::os_gmtime(const time_t * clock, struct tm * ts)
1646 #ifdef P_MACOSX
1647 #warning GMTIME_R NOT DEFINED
1648 return ::gmtime(clock);
1649 #else
1650 return ::gmtime_r(clock, ts);
1651 #endif
1653 #else
1654 struct tm * PTime::os_gmtime(const time_t * clock, struct tm *)
1656 return ::gmtime(clock);
1658 #endif
1660 // End Of File ///////////////////////////////////////////////////////////////