osutils.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:52k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * osutils.cxx
  3.  *
  4.  * Operating System utilities.
  5.  *
  6.  * Portable Windows Library
  7.  *
  8.  * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
  9.  *
  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/
  14.  *
  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.
  19.  *
  20.  * The Original Code is Portable Windows Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
  25.  * All Rights Reserved.
  26.  *
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * $Log: osutils.cxx,v $
  30.  * Revision 1.144  2000/06/26 11:17:20  robertj
  31.  * Nucleus++ port (incomplete).
  32.  *
  33.  * Revision 1.143  2000/06/26 09:27:16  robertj
  34.  * Added ability to get at the PTraceStream without timestamps etc, use UINT_MAX trace level.
  35.  *
  36.  * Revision 1.142  2000/06/02 01:38:07  craigs
  37.  * Fixed typos
  38.  *
  39.  * Revision 1.141  2000/06/02 01:35:56  craigs
  40.  * Added more guards for NULL PStrings in PConfigArg handling
  41.  *
  42.  * Revision 1.140  2000/05/25 14:45:07  robertj
  43.  * Fixed detection of real argument over configured value.
  44.  *
  45.  * Revision 1.139  2000/05/25 13:47:51  robertj
  46.  * Fixed warning with GNU.
  47.  *
  48.  * Revision 1.138  2000/05/25 11:05:55  robertj
  49.  * Added PConfigArgs class so can save program arguments to config files.
  50.  *
  51.  * Revision 1.137  2000/05/05 10:08:29  robertj
  52.  * Fixed some GNU compiler warnings
  53.  *
  54.  * Revision 1.136  2000/04/28 06:58:50  robertj
  55.  * Fixed bug introduced when added Ashley Untts fix, forgot to take out old code!
  56.  *
  57.  * Revision 1.135  2000/04/27 04:19:27  robertj
  58.  * Fixed bug in restarting free running timers, thanks Ashley Unitt.
  59.  *
  60.  * Revision 1.134  2000/04/03 18:42:40  robertj
  61.  * Added function to determine if PProcess instance is initialised.
  62.  *
  63.  * Revision 1.133  2000/03/29 20:12:00  robertj
  64.  * Fixed GNU C++ warning
  65.  *
  66.  * Revision 1.132  2000/03/29 01:55:52  robertj
  67.  * Fixed infinite recursion on PProcess::Current() = NULL assertion.
  68.  *
  69.  * Revision 1.131  2000/03/02 05:43:12  robertj
  70.  * Fixed handling of NULL pointer on current thread in PTRACE output.
  71.  *
  72.  * Revision 1.130  2000/02/29 12:26:14  robertj
  73.  * Added named threads to tracing, thanks to Dave Harvey
  74.  *
  75.  * Revision 1.129  2000/02/17 11:34:28  robertj
  76.  * Changed PTRACE output to help line up text after filename output.
  77.  *
  78.  * Revision 1.128  2000/01/06 14:09:42  robertj
  79.  * Fixed problems with starting up timers,losing up to 10 seconds
  80.  *
  81.  * Revision 1.127  1999/10/19 09:21:30  robertj
  82.  * Added functions to get current trace options and level.
  83.  *
  84.  * Revision 1.126  1999/10/14 08:08:27  robertj
  85.  * Fixed problem, assuring millisecond accuracy in timestamp of trace output.
  86.  *
  87.  * Revision 1.125  1999/09/14 13:02:52  robertj
  88.  * Fixed PTRACE to PSYSTEMLOG conversion problem under Unix.
  89.  *
  90.  * Revision 1.124  1999/09/13 13:15:07  robertj
  91.  * Changed PTRACE so will output to system log in PServiceProcess applications.
  92.  *
  93.  * Revision 1.123  1999/08/22 12:54:35  robertj
  94.  * Fixed warnings about inlines on older GNU compiler
  95.  *
  96.  * Revision 1.122  1999/06/23 14:19:46  robertj
  97.  * Fixed core dump problem with SIGINT/SIGTERM terminating process.
  98.  *
  99.  * Revision 1.121  1999/06/14 07:59:38  robertj
  100.  * Enhanced tracing again to add options to trace output (timestamps etc).
  101.  *
  102.  * Revision 1.120  1999/04/26 08:06:51  robertj
  103.  * Added missing function in cooperative threading.
  104.  *
  105.  * Revision 1.119  1999/03/01 13:51:30  craigs
  106.  * Fixed ugly little bug in the cooperative multithreading that meant that threads blocked
  107.  * on timers didn't always get rescheduled.
  108.  *
  109.  * Revision 1.118  1999/02/23 10:13:31  robertj
  110.  * Changed trace to only diplay filename and not whole path.
  111.  *
  112.  * Revision 1.117  1999/02/23 07:11:27  robertj
  113.  * Improved trace facility adding trace levels and #define to remove all trace code.
  114.  *
  115.  * Revision 1.116  1998/11/30 12:45:54  robertj
  116.  * Fissioned into pchannel.cxx and pconfig.cxx
  117.  *
  118.  * Revision 1.115  1998/11/24 01:17:33  robertj
  119.  * Type discrepency between declaration and definition for PFile::SetPosition
  120.  *
  121.  * Revision 1.114  1998/11/06 02:37:53  robertj
  122.  * Fixed the fix for semaphore timeout race condition.
  123.  *
  124.  * Revision 1.113  1998/11/03 10:52:19  robertj
  125.  * Fixed bug in semaphores with timeout saying timed out when really signalled.
  126.  *
  127.  * Revision 1.112  1998/11/03 03:44:05  robertj
  128.  * Fixed missng strings on multiple parameters of same letter.
  129.  *
  130.  * Revision 1.111  1998/11/02 10:13:01  robertj
  131.  * Removed GNU warning.
  132.  *
  133.  * Revision 1.110  1998/11/01 04:56:53  robertj
  134.  * Added BOOl return value to Parse() to indicate there are parameters available.
  135.  *
  136.  * Revision 1.109  1998/10/31 14:02:20  robertj
  137.  * Removed StartImmediate capability as causes race condition in preemptive version.
  138.  *
  139.  * Revision 1.108  1998/10/31 12:47:10  robertj
  140.  * Added conditional mutex and read/write mutex thread synchronisation objects.
  141.  *
  142.  * Revision 1.107  1998/10/30 12:24:15  robertj
  143.  * Added ability to get all key values as a dictionary.
  144.  * Fixed warnings in GNU C.
  145.  *
  146.  * Revision 1.106  1998/10/30 11:22:15  robertj
  147.  * Added constructors that take strings as well as const char *'s.
  148.  *
  149.  * Revision 1.105  1998/10/30 05:25:09  robertj
  150.  * Allow user to shift past some arguments before parsing for the first time.
  151.  *
  152.  * Revision 1.104  1998/10/29 05:35:17  robertj
  153.  * Fixed porblem with GetCount() == 0 if do not call Parse() function.
  154.  *
  155.  * Revision 1.103  1998/10/28 03:26:43  robertj
  156.  * Added multi character arguments (-abc style) and options precede parameters mode.
  157.  *
  158.  * Revision 1.102  1998/10/28 00:59:49  robertj
  159.  * New improved argument parsing.
  160.  *
  161.  * Revision 1.101  1998/10/19 00:19:59  robertj
  162.  * Moved error and trace stream functions to common code.
  163.  *
  164.  * Revision 1.100  1998/10/18 14:28:45  robertj
  165.  * Renamed argv/argc to eliminate accidental usage.
  166.  *
  167.  * Revision 1.99  1998/10/13 14:06:28  robertj
  168.  * Complete rewrite of memory leak detection code.
  169.  *
  170.  * Revision 1.98  1998/09/24 07:23:54  robertj
  171.  * Moved structured fiel into separate module so don't need silly implementation file for GNU C.
  172.  *
  173.  * Revision 1.97  1998/09/23 06:22:24  robertj
  174.  * Added open source copyright license.
  175.  *
  176.  * Revision 1.96  1998/06/13 15:11:56  robertj
  177.  * Added stack check in Yield().
  178.  * Added immediate schedule of semaphore timeout thread.
  179.  *
  180.  * Revision 1.95  1998/05/30 13:28:18  robertj
  181.  * Changed memory check code so global statics are not included in leak check.
  182.  * Fixed deadlock in cooperative threading.
  183.  * Added PSyncPointAck class.
  184.  *
  185.  * Revision 1.94  1998/05/25 09:05:56  robertj
  186.  * Fixed close of channels on destruction.
  187.  *
  188.  * Revision 1.93  1998/04/07 13:33:33  robertj
  189.  * Changed startup code to support PApplication class.
  190.  *
  191.  * Revision 1.92  1998/03/29 06:16:45  robertj
  192.  * Rearranged initialisation sequence so PProcess descendent constructors can do "things".
  193.  *
  194.  * Revision 1.91  1998/03/20 03:18:17  robertj
  195.  * Added special classes for specific sepahores, PMutex and PSyncPoint.
  196.  *
  197.  * Revision 1.90  1998/02/05 13:33:12  robertj
  198.  * Fixed close of non-autodelete PIndirectChannels
  199.  *
  200.  * Revision 1.89  1998/02/03 06:19:55  robertj
  201.  * Added new function to read a block with minimum number of bytes.
  202.  *
  203.  * Revision 1.88  1998/01/26 00:47:13  robertj
  204.  * Added functions to get/set 64bit integers from a PConfig.
  205.  *
  206.  * Revision 1.87  1998/01/04 07:22:16  robertj
  207.  * Fixed bug in thread deletion not removing it from active thread list.
  208.  *
  209.  * Revision 1.86  1997/10/10 10:41:22  robertj
  210.  * Fixed problem with cooperative threading and Sleep() function returning immediately.
  211.  *
  212.  * Revision 1.85  1997/08/28 12:49:00  robertj
  213.  * Fixed possible assert on exit of application.
  214.  *
  215.  * Revision 1.84  1997/07/08 13:08:12  robertj
  216.  * DLL support.
  217.  *
  218.  * Revision 1.83  1997/04/27 05:50:15  robertj
  219.  * DLL support.
  220.  *
  221.  * Revision 1.82  1997/02/09 04:05:56  robertj
  222.  * Changed PProcess::Current() from pointer to reference.
  223.  *
  224.  * Revision 1.81  1997/02/05 11:51:42  robertj
  225.  * Changed current process function to return reference and validate objects descendancy.
  226.  *
  227.  * Revision 1.80  1996/12/21 05:54:38  robertj
  228.  * Fixed possible deadlock in timers.
  229.  *
  230.  * Revision 1.79  1996/12/05 11:44:22  craigs
  231.  * Made indirect close from different thread less likely to have
  232.  * race condition
  233.  *
  234.  * Revision 1.78  1996/11/30 12:08:42  robertj
  235.  * Removed extraneous compiler warning.
  236.  *
  237.  * Revision 1.77  1996/11/10 21:05:43  robertj
  238.  * Fixed bug of missing flush in close of indirect channel.
  239.  *
  240.  * Revision 1.76  1996/10/08 13:07:07  robertj
  241.  * Fixed bug in indirect channel being reopened double deleting subchannel.
  242.  *
  243.  * Revision 1.75  1996/09/14 13:09:37  robertj
  244.  * Major upgrade:
  245.  *   rearranged sockets to help support IPX.
  246.  *   added indirect channel class and moved all protocols to descend from it,
  247.  *   separating the protocol from the low level byte transport.
  248.  *
  249.  * Revision 1.74  1996/08/11 06:53:04  robertj
  250.  * Fixed bug in Sleep() function (nonpreemptive version).
  251.  *
  252.  * Revision 1.73  1996/07/27 04:12:09  robertj
  253.  * Fixed bug in timer thread going into busy loop instead of blocking.
  254.  *
  255.  * Revision 1.72  1996/07/15 10:36:12  robertj
  256.  * Fixed bug in timer on startup, getting LARGE times timing out prematurely.
  257.  *
  258.  * Revision 1.71  1996/06/28 13:22:43  robertj
  259.  * Rewrite of timers to make OnTimeout more thread safe.
  260.  *
  261.  * Revision 1.70  1996/06/13 13:31:05  robertj
  262.  * Rewrite of auto-delete threads, fixes Windows95 total crash.
  263.  *
  264.  * Revision 1.69  1996/06/03 10:01:31  robertj
  265.  * Fixed GNU support bug fix for the fix.
  266.  *
  267.  * Revision 1.68  1996/06/01 05:03:37  robertj
  268.  * Fixed GNU compiler having difficulty with PTimeInterval *this.
  269.  *
  270.  * Revision 1.67  1996/05/26 03:46:56  robertj
  271.  * Compatibility to GNU 2.7.x
  272.  *
  273.  * Revision 1.66  1996/05/23 23:05:07  robertj
  274.  * Fixed process filename on MSOS platforms.
  275.  *
  276.  * Revision 1.65  1996/05/23 09:56:57  robertj
  277.  * Added mutex to timer list.
  278.  *
  279.  * Revision 1.64  1996/05/18 09:18:33  robertj
  280.  * Added mutex to timer list.
  281.  *
  282.  * Revision 1.63  1996/05/09 12:19:00  robertj
  283.  * Resolved C++ problems with 64 bit PTimeInterval for Mac platform.
  284.  *
  285.  * Revision 1.62  1996/04/14 02:53:34  robertj
  286.  * Split serial and pipe channel into separate compilation units for Linux executable size reduction.
  287.  *
  288.  * Revision 1.61  1996/04/10 12:51:29  robertj
  289.  * Fixed startup race condtion in timer thread.
  290.  *
  291.  * Revision 1.60  1996/04/09 03:32:58  robertj
  292.  * Fixed bug in config GetTime() cannot use PTime(0) in western hemisphere.
  293.  *
  294.  * Revision 1.59  1996/04/02 11:29:19  robertj
  295.  * Eliminated printing of patch level in version when there isn't one.
  296.  *
  297.  * Revision 1.58  1996/03/31 09:06:14  robertj
  298.  * Fixed WriteString() so works with sockets.
  299.  * Changed PPipeSokcet argument string list to array.
  300.  *
  301.  * Revision 1.57  1996/03/16 04:51:50  robertj
  302.  * Fixed yet another bug in the scheduler.
  303.  *
  304.  * Revision 1.56  1996/03/12 11:30:50  robertj
  305.  * Moved PProcess destructor to platform dependent code.
  306.  *
  307.  * Revision 1.55  1996/03/05 14:05:51  robertj
  308.  * Fixed some more bugs in scheduling.
  309.  *
  310.  * Revision 1.54  1996/03/04 12:22:46  robertj
  311.  * Fixed threading for unix stack check and loop list start point.
  312.  *
  313.  * Revision 1.53  1996/03/03 07:39:51  robertj
  314.  * Fixed bug in thread scheduler for correct termination of "current" thread.
  315.  *
  316.  * Revision 1.52  1996/03/02 03:24:48  robertj
  317.  * Changed timer thread to update timers periodically, this allows timers to be
  318.  *    views dynamically by other threads.
  319.  * Added automatic deletion of thread object instances on thread completion.
  320.  *
  321.  * Revision 1.51  1996/02/25 11:15:27  robertj
  322.  * Added platform dependent Construct function to PProcess.
  323.  *
  324.  * Revision 1.50  1996/02/25 03:09:46  robertj
  325.  * Added consts to all GetXxxx functions in PConfig.
  326.  *
  327.  * Revision 1.49  1996/02/15 14:44:09  robertj
  328.  * Used string constructor for PTime, more "efficient".
  329.  *
  330.  * Revision 1.48  1996/02/13 12:59:30  robertj
  331.  * Changed GetTimeZone() so can specify standard/daylight time.
  332.  * Split PTime into separate module after major change to ReadFrom().
  333.  *
  334.  * Revision 1.47  1996/02/08 12:26:55  robertj
  335.  * Changed time for full support of time zones.
  336.  *
  337.  * Revision 1.46  1996/02/03 11:06:49  robertj
  338.  * Added string constructor for times, parses date/time from string.
  339.  *
  340.  * Revision 1.45  1996/01/28 14:09:39  robertj
  341.  * Fixed bug in time reading function for dates before 1980.
  342.  * Fixed bug in time reading, was out by one month.
  343.  * Added time functions to PConfig.
  344.  *
  345.  * Revision 1.44  1996/01/28 02:52:04  robertj
  346.  * Added assert into all Compare functions to assure comparison between compatible objects.
  347.  *
  348.  * Revision 1.43  1996/01/23 13:16:30  robertj
  349.  * Mac Metrowerks compiler support.
  350.  * Fixed timers so background thread not created if a windows app.
  351.  *
  352.  * Revision 1.42  1996/01/03 23:15:39  robertj
  353.  * Fixed some PTime bugs.
  354.  *
  355.  * Revision 1.41  1996/01/03 11:09:35  robertj
  356.  * Added Universal Time and Time Zones to PTime class.
  357.  *
  358.  * Revision 1.39  1995/12/23 03:40:40  robertj
  359.  * Changed version number system
  360.  *
  361.  * Revision 1.38  1995/12/10 11:41:12  robertj
  362.  * Added extra user information to processes and applications.
  363.  * Implemented timer support in text only applications with platform threads.
  364.  * Fixed bug in non-platform threads and semaphore timeouts.
  365.  *
  366.  * Revision 1.37  1995/11/21 11:50:57  robertj
  367.  * Added timeout on semaphore wait.
  368.  *
  369.  * Revision 1.36  1995/11/09 12:22:58  robertj
  370.  * Fixed bug in stream when reading an FF (get EOF).
  371.  *
  372.  * Revision 1.35  1995/07/31 12:09:25  robertj
  373.  * Added semaphore class.
  374.  * Removed PContainer from PChannel ancestor.
  375.  *
  376.  * Revision 1.34  1995/06/04 12:41:08  robertj
  377.  * Fixed bug in accessing argument strings with no argument.
  378.  *
  379.  * Revision 1.33  1995/04/25 11:30:06  robertj
  380.  * Fixed Borland compiler warnings.
  381.  *
  382.  * Revision 1.32  1995/04/22 00:51:00  robertj
  383.  * Changed file path strings to use PFilePath object.
  384.  * Changed semantics of Rename().
  385.  *
  386.  * Revision 1.31  1995/04/02 09:27:31  robertj
  387.  * Added "balloon" help.
  388.  *
  389.  * Revision 1.30  1995/04/01 08:30:58  robertj
  390.  * Fixed bug in timeout code of timers.
  391.  *
  392.  * Revision 1.29  1995/01/27 11:15:17  robertj
  393.  * Removed enum to int warning from GCC.
  394.  *
  395.  * Revision 1.28  1995/01/18  09:02:43  robertj
  396.  * Added notifier to timer.
  397.  *
  398.  * Revision 1.27  1995/01/15  04:57:15  robertj
  399.  * Implemented PTime::ReadFrom.
  400.  * Fixed flush of iostream at end of file.
  401.  *
  402.  * Revision 1.26  1995/01/11  09:45:14  robertj
  403.  * Documentation and normalisation.
  404.  *
  405.  * Revision 1.25  1995/01/10  11:44:15  robertj
  406.  * Removed PString parameter in stdarg function for GNU C++ compatibility.
  407.  *
  408.  * Revision 1.24  1995/01/09  12:31:51  robertj
  409.  * Removed unnecesary return value from I/O functions.
  410.  *
  411.  * Revision 1.23  1994/12/12  10:09:24  robertj
  412.  * Fixed flotain point configuration variable format.
  413.  *
  414.  * Revision 1.22  1994/11/28  12:38:23  robertj
  415.  * Async write functions should have const pointer.
  416.  *
  417.  * Revision 1.21  1994/10/30  11:36:58  robertj
  418.  * Fixed missing space in tine format string.
  419.  *
  420.  * Revision 1.20  1994/10/23  03:46:41  robertj
  421.  * Shortened OS error assert.
  422.  *
  423.  * Revision 1.19  1994/09/25  10:51:04  robertj
  424.  * Fixed error conversion code to use common function.
  425.  * Added pipe channel.
  426.  *
  427.  * Revision 1.18  1994/08/21  23:43:02  robertj
  428.  * Moved meta-string transmitter from PModem to PChannel.
  429.  * Added SuspendBlock state to cooperative multi-threading to fix logic fault.
  430.  * Added "force" option to Remove/Rename etc to override write protection.
  431.  * Added common entry point to convert OS error to PChannel error.
  432.  *
  433.  * Revision 1.17  1994/08/04  12:57:10  robertj
  434.  * Changed CheckBlock() to better name.
  435.  * Moved timer porcessing so is done at every Yield().
  436.  *
  437.  * Revision 1.16  1994/08/01  03:39:42  robertj
  438.  * Fixed temporary variable problem with GNU C++
  439.  *
  440.  * Revision 1.15  1994/07/27  05:58:07  robertj
  441.  * Synchronisation.
  442.  *
  443.  * Revision 1.14  1994/07/25  03:39:22  robertj
  444.  * Fixed problems with C++ temporary variables.
  445.  *
  446.  * Revision 1.13  1994/07/21  12:33:49  robertj
  447.  * Moved cooperative threads to common.
  448.  *
  449.  * Revision 1.12  1994/07/17  10:46:06  robertj
  450.  * Fixed timer bug.
  451.  * Moved handle from file to channel.
  452.  * Changed args to use container classes.
  453.  *
  454.  * Revision 1.11  1994/07/02  03:03:49  robertj
  455.  * Time interval and timer redesign.
  456.  *
  457.  * Revision 1.10  1994/06/25  11:55:15  robertj
  458.  * Unix version synchronisation.
  459.  *
  460.  * Revision 1.9  1994/04/20  12:17:44  robertj
  461.  * assert changes
  462.  *
  463.  * Revision 1.8  1994/04/01  14:05:06  robertj
  464.  * Text file streams
  465.  *
  466.  * Revision 1.7  1994/03/07  07:47:00  robertj
  467.  * Major upgrade
  468.  *
  469.  * Revision 1.6  1994/01/03  04:42:23  robertj
  470.  * Mass changes to common container classes and interactors etc etc etc.
  471.  *
  472.  * Revision 1.5  1993/12/31  06:53:02  robertj
  473.  * Made inlines optional for debugging purposes.
  474.  *
  475.  * Revision 1.4  1993/12/29  04:41:26  robertj
  476.  * Mac port.
  477.  *
  478.  * Revision 1.3  1993/11/20  17:26:28  robertj
  479.  * Removed separate osutil.h
  480.  *
  481.  * Revision 1.2  1993/08/31  03:38:02  robertj
  482.  * G++ needs explicit casts for char * / void * interchange.
  483.  *
  484.  * Revision 1.1  1993/08/27  18:17:47  robertj
  485.  * Initial revision
  486.  *
  487.  */
  488. #include <ptlib.h>
  489. #include <ptlib/svcproc.h>
  490. #include <ctype.h>
  491. #ifndef __NUCLEUS_PLUS__
  492. static ostream * PErrorStream = &cerr;
  493. #else
  494. static ostream * PErrorStream = 0L;
  495. #endif
  496. ostream & PGetErrorStream()
  497. {
  498.   return *PErrorStream;
  499. }
  500. void PSetErrorStream(ostream * s)
  501. {
  502. #ifndef __NUCLEUS_PLUS__
  503.   PErrorStream = s != NULL ? s : &cerr;
  504. #else
  505.   PErrorStream = s;
  506. #endif
  507. }
  508. ///////////////////////////////////////////////////////////////////////////////
  509. #ifndef __NUCLEUS_PLUS__
  510. static ostream * PTraceStream = &cerr;
  511. #else
  512. static ostream * PTraceStream = 0L;
  513. #endif
  514. static unsigned PTraceOptions = PTrace::FileAndLine;
  515. static unsigned PTraceLevelThreshold = 0;
  516. static unsigned PTraceBlockIndentLevel = 0;
  517. static PTimeInterval ApplicationStartTick = PTimer::Tick();
  518. void PTrace::SetStream(ostream * s)
  519. {
  520. #ifndef __NUCLEUS_PLUS__
  521.   PTraceStream = s != NULL ? s : &cerr;
  522. #else
  523.   PTraceStream = s;
  524. #endif
  525. }
  526. void PTrace::SetOptions(unsigned options)
  527. {
  528.   PTraceOptions |= options;
  529. }
  530. void PTrace::ClearOptions(unsigned options)
  531. {
  532.   PTraceOptions &= ~options;
  533. }
  534. unsigned PTrace::GetOptions()
  535. {
  536.   return PTraceOptions;
  537. }
  538. void PTrace::SetLevel(unsigned level)
  539. {
  540.   PTraceLevelThreshold = level;
  541. }
  542. unsigned PTrace::GetLevel()
  543. {
  544.   return PTraceLevelThreshold;
  545. }
  546. BOOL PTrace::CanTrace(unsigned level)
  547. {
  548.   return level <= PTraceLevelThreshold;
  549. }
  550. static PMutex & PTraceMutex()
  551. {
  552.   static PMutex mutex;
  553.   return mutex;
  554. }
  555. ostream & PTrace::Begin(unsigned level, const char * fileName, int lineNum)
  556. {
  557.   PTraceMutex().Wait();
  558.   if (level == UINT_MAX)
  559.     return *PTraceStream;
  560.   if ((PTraceOptions&SystemLogStream) != 0) {
  561.     unsigned lvl = level+PSystemLog::Warning;
  562.     if (lvl >= PSystemLog::NumLogLevels)
  563.       lvl = PSystemLog::NumLogLevels-1;
  564.     ((PSystemLog*)PTraceStream)->SetLevel((PSystemLog::Level)lvl);
  565.   }
  566.   else {
  567.     if ((PTraceOptions&DateAndTime) != 0) {
  568.       PTime now;
  569.       *PTraceStream << now.AsString("yyyy/MM/dd hh:mm:sst");
  570.     }
  571.     if ((PTraceOptions&Timestamp) != 0)
  572.       *PTraceStream << setprecision(3) << setw(10) << (PTimer::Tick()-ApplicationStartTick) << 't';
  573.     if ((PTraceOptions&Thread) != 0) {
  574.       PThread * thread = PThread::Current();
  575.       if (thread == NULL)
  576.         *PTraceStream << setw(23) << "<<unknown>>";
  577.       else {
  578.         PString name = thread->GetThreadName();
  579.         if (!name)
  580.           *PTraceStream << setw(23) << name.Left(23);
  581.         else {
  582.           name = thread->GetClass();
  583.           if ((PTraceOptions&ThreadAddress) != 0)
  584.             *PTraceStream << setw(23) << name.Left(23);
  585.           else
  586.             *PTraceStream << setw(15) << name.Left(15) << ':'
  587.                           << hex << setfill('0')
  588.                           << setw(7) << (unsigned)thread
  589.                           << dec << setfill(' ');
  590.         }
  591.       }
  592.       *PTraceStream << 't';
  593.     }
  594.     if ((PTraceOptions&ThreadAddress) != 0)
  595.       *PTraceStream << hex << setfill('0')
  596.                     << setw(7) << (unsigned)PThread::Current()
  597.                     << dec << setfill(' ') << 't';
  598.   }
  599.   if ((PTraceOptions&TraceLevel) != 0)
  600.     *PTraceStream << level << 't';
  601.   if ((PTraceOptions&FileAndLine) != 0 && fileName != NULL) {
  602.     const char * file = strrchr(fileName, '/');
  603.     if (file != NULL)
  604.       file++;
  605.     else {
  606.       file = strrchr(fileName, '\');
  607.       if (file != NULL)
  608.         file++;
  609.       else
  610.         file = fileName;
  611.     }
  612.     *PTraceStream << setw(16) << file << '(' << lineNum << ")t";
  613.   }
  614.   return *PTraceStream;
  615. }
  616. ostream & PTrace::End(ostream & s)
  617. {
  618.   if (s.rdbuf()->out_waiting() > 0) {
  619.     if ((PTraceOptions&SystemLogStream) != 0)
  620.       s.flush();
  621.     else
  622.       s << endl;
  623.   }
  624.   PTraceMutex().Signal();
  625.   return s;
  626. }
  627. PTrace::Block::Block(const char * fileName, int lineNum, const char * traceName)
  628. {
  629.   file = fileName;
  630.   line = lineNum;
  631.   name = traceName;
  632.   PTraceBlockIndentLevel += 2;
  633.   if ((PTraceOptions&Blocks) != 0) {
  634.     ostream & s = PTrace::Begin(1, file, line);
  635.     for (unsigned i = 0; i < PTraceBlockIndentLevel; i++)
  636.       s << '=';
  637.     s << "> " << name << PTrace::End;
  638.   }
  639. }
  640. PTrace::Block::~Block()
  641. {
  642.   if ((PTraceOptions&Blocks) != 0) {
  643.     ostream & s = PTrace::Begin(1, file, line);
  644.     s << '<';
  645.     for (unsigned i = 0; i < PTraceBlockIndentLevel; i++)
  646.       s << '=';
  647.     s << ' ' << name << PTrace::End;
  648.   }
  649.   PTraceBlockIndentLevel -= 2;
  650. }
  651. ///////////////////////////////////////////////////////////////////////////////
  652. // PDirectory
  653. void PDirectory::CloneContents(const PDirectory * d)
  654. {
  655.   CopyContents(*d);
  656. }
  657. ///////////////////////////////////////////////////////////////////////////////
  658. // PTimer
  659. PTimer::PTimer(long millisecs, int seconds, int minutes, int hours, int days)
  660.   : resetTime(millisecs, seconds, minutes, hours, days)
  661. {
  662.   state = Stopped;
  663.   timeoutThread = NULL;
  664.   StartRunning(TRUE);
  665. }
  666. PTimer::PTimer(const PTimeInterval & time)
  667.   : resetTime(time)
  668. {
  669.   state = Stopped;
  670.   timeoutThread = NULL;
  671.   StartRunning(TRUE);
  672. }
  673. PTimer & PTimer::operator=(DWORD milliseconds)
  674. {
  675.   resetTime = (PInt64)milliseconds;
  676.   StartRunning(oneshot);
  677.   return *this;
  678. }
  679. PTimer & PTimer::operator=(const PTimeInterval & time)
  680. {
  681.   resetTime = time;
  682.   StartRunning(oneshot);
  683.   return *this;
  684. }
  685. PTimer::~PTimer()
  686. {
  687.   PAssert(timeoutThread == NULL || PThread::Current() != timeoutThread, "Timer destroyed in OnTimeout()");
  688.   if (IsRunning())
  689.     PProcess::Current().GetTimerList()->RemoveTimer(this);
  690. }
  691. void PTimer::RunContinuous(const PTimeInterval & time)
  692. {
  693.   resetTime = time;
  694.   StartRunning(FALSE);
  695. }
  696. void PTimer::StartRunning(BOOL once)
  697. {
  698.   if (IsRunning() && timeoutThread == NULL)
  699.     PProcess::Current().GetTimerList()->RemoveTimer(this);
  700.   PTimeInterval::operator=(resetTime);
  701.   oneshot = once;
  702.   state = (*this) != 0 ? Starting : Stopped;
  703.   if (IsRunning()) {
  704.     if (timeoutThread == NULL)
  705.       PProcess::Current().GetTimerList()->AppendTimer(this);
  706. #if defined(P_PLATFORM_HAS_THREADS)
  707.     else
  708.       PProcess::Current().SignalTimerChange();
  709. #endif
  710.   }
  711. }
  712. void PTimer::Stop()
  713. {
  714.   if (IsRunning() && timeoutThread == NULL)
  715.     PProcess::Current().GetTimerList()->RemoveTimer(this);
  716.   state = Stopped;
  717.   SetInterval(0);
  718. }
  719. void PTimer::Pause()
  720. {
  721.   if (IsRunning()) {
  722.     if (timeoutThread == NULL)
  723.       PProcess::Current().GetTimerList()->RemoveTimer(this);
  724.     state = Paused;
  725.   }
  726. }
  727. void PTimer::Resume()
  728. {
  729.   if (state == Paused) {
  730.     if (timeoutThread == NULL)
  731.       PProcess::Current().GetTimerList()->AppendTimer(this);
  732.     state = Starting;
  733.   }
  734. }
  735. void PTimer::OnTimeout()
  736. {
  737.   if (!callback.IsNULL())
  738.     callback(*this, IsRunning());
  739. }
  740. BOOL PTimer::Process(const PTimeInterval & delta, PTimeInterval & minTimeLeft)
  741. {
  742.   if (state == Starting) {
  743.     state = Running;
  744.     if (resetTime < minTimeLeft)
  745.       minTimeLeft = resetTime;
  746.     return FALSE;
  747.   }
  748.   operator-=(delta);
  749.   if (milliseconds > 0) {
  750.     if (milliseconds < minTimeLeft.GetMilliSeconds())
  751.       minTimeLeft = milliseconds;
  752.     return FALSE;
  753.   }
  754.   timeoutThread = PThread::Current();
  755.   if (oneshot) {
  756.     operator=(PTimeInterval(0));
  757.     state = Stopped;
  758.   }
  759.   else {
  760.     operator=(resetTime);
  761.     if (resetTime < minTimeLeft)
  762.       minTimeLeft = resetTime;
  763.   }
  764.   return TRUE;
  765. }
  766. ///////////////////////////////////////////////////////////////////////////////
  767. // PTimerList
  768. PTimerList::PTimerList()
  769. {
  770.   DisallowDeleteObjects();
  771. }
  772. void PTimerList::AppendTimer(PTimer * timer)
  773. {
  774.   mutex.Wait();
  775.   PInternalTimerList::InsertAt(0, timer);
  776.   mutex.Signal();
  777. #if defined(P_PLATFORM_HAS_THREADS)
  778.   PProcess::Current().SignalTimerChange();
  779. #endif
  780. }
  781. void PTimerList::RemoveTimer(PTimer * timer)
  782. {
  783.   mutex.Wait();
  784.   PInternalTimerList::Remove(timer);
  785.   mutex.Signal();
  786. #if defined(P_PLATFORM_HAS_THREADS)
  787.   PProcess::Current().SignalTimerChange();
  788. #endif
  789. }
  790. PTimeInterval PTimerList::Process()
  791. {
  792.   PINDEX i;
  793.   PTimeInterval minTimeLeft = PMaxTimeInterval;
  794.   PInternalTimerList timeouts;
  795.   timeouts.DisallowDeleteObjects();
  796.   mutex.Wait();
  797.   PTimeInterval now = PTimer::Tick();
  798.   PTimeInterval sampleTime;
  799.   if (lastSample == 0)
  800.     sampleTime = 0;
  801.   else {
  802.     sampleTime = now - lastSample;
  803.     if (now < lastSample)
  804.       sampleTime += PMaxTimeInterval;
  805.   }
  806.   lastSample = now;
  807.   for (i = 0; i < GetSize(); i++)
  808.     if ((*this)[i].Process(sampleTime, minTimeLeft))
  809.       timeouts.Append(RemoveAt(i--));
  810.   mutex.Signal();
  811.   for (i = 0; i < timeouts.GetSize(); i++)
  812.     timeouts[i].OnTimeout();
  813.   mutex.Wait();
  814.   for (i = 0; i < timeouts.GetSize(); i++) {
  815.     timeouts[i].timeoutThread = NULL;
  816.     if (timeouts[i].IsRunning())
  817.       Append(timeouts.GetAt(i));
  818.   }
  819.   mutex.Signal();
  820.   return minTimeLeft;
  821. }
  822. ///////////////////////////////////////////////////////////////////////////////
  823. // PArgList
  824. PArgList::PArgList(const char * theArgStr,
  825.                    const char * theArgumentSpec,
  826.                    BOOL optionsBeforeParams)
  827. {
  828.   // get the program arguments
  829.   if (theArgStr != NULL)
  830.     SetArgs(theArgStr);
  831.   // if we got an argument spec - so process them
  832.   if (theArgumentSpec != NULL)
  833.     Parse(theArgumentSpec, optionsBeforeParams);
  834. }
  835. PArgList::PArgList(const PString & theArgStr,
  836.                    const char * argumentSpecPtr,
  837.                    BOOL optionsBeforeParams)
  838. {
  839.   // get the program arguments
  840.   SetArgs(theArgStr);
  841.   // if we got an argument spec - so process them
  842.   if (argumentSpecPtr != NULL)
  843.     Parse(argumentSpecPtr, optionsBeforeParams);
  844. }
  845. PArgList::PArgList(const PString & theArgStr,
  846.                    const PString & argumentSpecStr,
  847.                    BOOL optionsBeforeParams)
  848. {
  849.   // get the program arguments
  850.   SetArgs(theArgStr);
  851.   // if we got an argument spec - so process them
  852.   Parse(argumentSpecStr, optionsBeforeParams);
  853. }
  854. PArgList::PArgList(int theArgc, char ** theArgv,
  855.                    const char * theArgumentSpec,
  856.                    BOOL optionsBeforeParams)
  857. {
  858.   // get the program arguments
  859.   SetArgs(theArgc, theArgv);
  860.   // if we got an argument spec - so process them
  861.   if (theArgumentSpec != NULL)
  862.     Parse(theArgumentSpec, optionsBeforeParams);
  863. }
  864. PArgList::PArgList(int theArgc, char ** theArgv,
  865.                    const PString & theArgumentSpec,
  866.                    BOOL optionsBeforeParams)
  867. {
  868.   // get the program name and path
  869.   SetArgs(theArgc, theArgv);
  870.   // we got an argument spec - so process them
  871.   Parse(theArgumentSpec, optionsBeforeParams);
  872. }
  873. void PArgList::SetArgs(const PString & argStr)
  874. {
  875.   argumentArray.SetSize(0);
  876.   const char * str = argStr;
  877.   for (;;) {
  878.     while (isspace(*str)) // Skip leading whitespace
  879.       str++;
  880.     if (*str == '')
  881.       break;
  882.     PString & arg = argumentArray[argumentArray.GetSize()];
  883.     while (*str != '' && !isspace(*str)) {
  884.       switch (*str) {
  885.         case '"' :
  886.           str++;
  887.           while (*str != '' && *str != '"')
  888.             arg += *str++;
  889.           if (*str != '')
  890.             str++;
  891.           break;
  892.         case ''' :
  893.           str++;
  894.           while (*str != '' && *str != ''')
  895.             arg += *str++;
  896.           if (*str != '')
  897.             str++;
  898.           break;
  899.         default :
  900.           if (str[0] == '\' && str[1] != '')
  901.             str++;
  902.           arg += *str++;
  903.       }
  904.     }
  905.   }
  906.   SetArgs(argumentArray);
  907. }
  908. void PArgList::SetArgs(const PStringArray & theArgs)
  909. {
  910.   argumentArray = theArgs;
  911.   shift = 0;
  912.   optionLetters = "";
  913.   optionNames.SetSize(0);
  914.   parameterIndex.SetSize(argumentArray.GetSize());
  915.   for (PINDEX i = 0; i < argumentArray.GetSize(); i++)
  916.     parameterIndex[i] = i;
  917. }
  918. BOOL PArgList::Parse(const char * spec, BOOL optionsBeforeParams)
  919. {
  920.   PAssertNULL(spec);
  921.   // Find starting point, start at shift if first Parse() call.
  922.   PINDEX arg = optionLetters.IsEmpty() ? shift : 0;
  923.   // If not in parse all mode, have been parsed before, and had some parameters
  924.   // from last time, then start argument parsing somewhere along instead of start.
  925.   if (optionsBeforeParams && !optionLetters && parameterIndex.GetSize() > 0)
  926.     arg = parameterIndex[parameterIndex.GetSize()-1] + 1;
  927.   // Parse the option specification
  928.   optionLetters = "";
  929.   optionNames.SetSize(0);
  930.   PIntArray canHaveOptionString;
  931.   PINDEX codeCount = 0;
  932.   while (*spec != '') {
  933.     if (*spec == '-')
  934.       optionLetters += ' ';
  935.     else
  936.       optionLetters += *spec++;
  937.     if (*spec == '-') {
  938.       const char * base = ++spec;
  939.       while (*spec != '' && *spec != '.' && *spec != ':' && *spec != ';')
  940.         spec++;
  941.       optionNames[codeCount] = PString(base, spec-base);
  942.       if (*spec == '.')
  943.         spec++;
  944.     }
  945.     if (*spec == ':' || *spec == ';') {
  946.       canHaveOptionString.SetSize(codeCount+1);
  947.       canHaveOptionString[codeCount] = *spec == ':' ? 2 : 1;
  948.       spec++;
  949.     }
  950.     codeCount++;
  951.   }
  952.   // Clear and reset size of option information
  953.   optionCount.SetSize(0);
  954.   optionCount.SetSize(codeCount);
  955.   optionString.SetSize(0);
  956.   optionString.SetSize(codeCount);
  957.   // Clear parameter indexes
  958.   parameterIndex.SetSize(0);
  959.   shift = 0;
  960.   // Now work through the arguments and split out the options
  961.   PINDEX param = 0;
  962.   BOOL hadMinusMinus = FALSE;
  963.   while (arg < argumentArray.GetSize()) {
  964.     const PString & argStr = argumentArray[arg];
  965.     if (hadMinusMinus || argStr[0] != '-' || argStr[1] == '') {
  966.       // have a parameter string
  967.       parameterIndex.SetSize(param+1);
  968.       parameterIndex[param++] = arg;
  969.     }
  970.     else if (optionsBeforeParams && parameterIndex.GetSize() > 0)
  971.       break;
  972.     else if (argStr == "--") // ALL remaining args are parameters not options
  973.       hadMinusMinus = TRUE;
  974.     else if (argStr[1] == '-')
  975.       ParseOption(optionNames.GetValuesIndex(argStr.Mid(2)), 0, arg, canHaveOptionString);
  976.     else {
  977.       for (PINDEX i = 1; i < argStr.GetLength(); i++)
  978.         if (ParseOption(optionLetters.Find(argStr[i]), i+1, arg, canHaveOptionString))
  979.           break;
  980.     }
  981.     arg++;
  982.   }
  983.   return param > 0;
  984. }
  985. BOOL PArgList::ParseOption(PINDEX idx, PINDEX offset, PINDEX & arg,
  986.                            const PIntArray & canHaveOptionString)
  987. {
  988.   if (idx == P_MAX_INDEX) {
  989.     UnknownOption(argumentArray[arg]);
  990.     return FALSE;
  991.   }
  992.   optionCount[idx]++;
  993.   if (canHaveOptionString[idx] == 0)
  994.     return FALSE;
  995.   if (!optionString[idx])
  996.     optionString[idx] += 'n';
  997.   if (offset != 0 &&
  998.         (canHaveOptionString[idx] == 1 || argumentArray[arg][offset] != '')) {
  999.     optionString[idx] += argumentArray[arg].Mid(offset);
  1000.     return TRUE;
  1001.   }
  1002.   if (++arg >= argumentArray.GetSize())
  1003.     return FALSE;
  1004.   optionString[idx] += argumentArray[arg];
  1005.   return TRUE;
  1006. }
  1007. PINDEX PArgList::GetOptionCount(char option) const
  1008. {
  1009.   return GetOptionCountByIndex(optionLetters.Find(option));
  1010. }
  1011. PINDEX PArgList::GetOptionCount(const char * option) const
  1012. {
  1013.   return GetOptionCountByIndex(optionNames.GetValuesIndex(PString(option)));
  1014. }
  1015. PINDEX PArgList::GetOptionCount(const PString & option) const
  1016. {
  1017.   return GetOptionCountByIndex(optionNames.GetValuesIndex(option));
  1018. }
  1019. PINDEX PArgList::GetOptionCountByIndex(PINDEX idx) const
  1020. {
  1021.   if (idx < optionCount.GetSize())
  1022.     return optionCount[idx];
  1023.   return 0;
  1024. }
  1025. PString PArgList::GetOptionString(char option, const char * dflt) const
  1026. {
  1027.   return GetOptionStringByIndex(optionLetters.Find(option), dflt);
  1028. }
  1029. PString PArgList::GetOptionString(const char * option, const char * dflt) const
  1030. {
  1031.   return GetOptionStringByIndex(optionNames.GetValuesIndex(PString(option)), dflt);
  1032. }
  1033. PString PArgList::GetOptionString(const PString & option, const char * dflt) const
  1034. {
  1035.   return GetOptionStringByIndex(optionNames.GetValuesIndex(option), dflt);
  1036. }
  1037. PString PArgList::GetOptionStringByIndex(PINDEX idx, const char * dflt) const
  1038. {
  1039.   if (idx < optionString.GetSize() && optionString.GetAt(idx) != NULL)
  1040.     return optionString[idx];
  1041.   if (dflt != NULL)
  1042.     return dflt;
  1043.   return PString();
  1044. }
  1045. PString PArgList::GetParameter(PINDEX num) const
  1046. {
  1047.   int idx = shift+(int)num;
  1048.   if (idx >= 0 && idx < (int)parameterIndex.GetSize())
  1049.     return argumentArray[parameterIndex[idx]];
  1050.   IllegalArgumentIndex(idx);
  1051.   return PString();
  1052. }
  1053. void PArgList::Shift(int sh) 
  1054. {
  1055.   shift += sh;
  1056.   if (shift < 0)
  1057.     shift = 0;
  1058.   else if (shift >= (int)parameterIndex.GetSize())
  1059.     shift = parameterIndex.GetSize() - 1;
  1060. }
  1061. void PArgList::IllegalArgumentIndex(PINDEX idx) const
  1062. {
  1063.   PError << "attempt to access undefined argument at index "
  1064.          << idx << endl;
  1065. }
  1066.  
  1067. void PArgList::UnknownOption(const PString & option) const
  1068. {
  1069.   PError << "unknown option "" << option << ""n";
  1070. }
  1071. void PArgList::MissingArgument(const PString & option) const
  1072. {
  1073.   PError << "option "" << option << "" requires argumentn";
  1074. }
  1075. ///////////////////////////////////////////////////////////////////////////////
  1076. // PConfigArgs
  1077. PConfigArgs::PConfigArgs(const PArgList & args)
  1078.   : PArgList(args),
  1079.     sectionName(config.GetDefaultSection()),
  1080.     negationPrefix("no-")
  1081. {
  1082. }
  1083. PINDEX PConfigArgs::GetOptionCount(char option) const
  1084. {
  1085.   PINDEX count;
  1086.   if ((count = PArgList::GetOptionCount(option)) > 0)
  1087.     return count;
  1088.   PString stropt = CharToString(option);
  1089.   if (stropt.IsEmpty())
  1090.     return 0;
  1091.   return GetOptionCount(stropt);
  1092. }
  1093. PINDEX PConfigArgs::GetOptionCount(const char * option) const
  1094. {
  1095.   return GetOptionCount(PString(option));
  1096. }
  1097. PINDEX PConfigArgs::GetOptionCount(const PString & option) const
  1098. {
  1099.   // if specified on the command line, use that option
  1100.   PINDEX count = PArgList::GetOptionCount(option);
  1101.   if (count > 0)
  1102.     return count;
  1103.   // if user has specified "no-option", then ignore config file
  1104.   if (PArgList::GetOptionCount(negationPrefix + option) > 0)
  1105.     return 0;
  1106.   return config.HasKey(sectionName, option) ? 1 : 0;
  1107. }
  1108. PString PConfigArgs::GetOptionString(char option, const char * dflt) const
  1109. {
  1110.   if (PArgList::GetOptionCount(option) > 0)
  1111.     return PArgList::GetOptionString(option, dflt);
  1112.   PString stropt = CharToString(option);
  1113.   if (stropt.IsEmpty()) {
  1114.     if (dflt != NULL)
  1115.       return dflt;
  1116.     return PString();
  1117.   }
  1118.   return GetOptionString(stropt, dflt);
  1119. }
  1120. PString PConfigArgs::GetOptionString(const char * option, const char * dflt) const
  1121. {
  1122.   return GetOptionString(PString(option), dflt);
  1123. }
  1124. PString PConfigArgs::GetOptionString(const PString & option, const char * dflt) const
  1125. {
  1126.   // if specified on the command line, use that option
  1127.   if (PArgList::GetOptionCount(option) > 0)
  1128.     return PArgList::GetOptionString(option, dflt);
  1129.   // if user has specified "no-option", then ignore config file
  1130.   if (PArgList::HasOption(negationPrefix + option)) {
  1131.     if (dflt != NULL)
  1132.       return dflt;
  1133.     return PString();
  1134.   }
  1135.   return config.GetString(sectionName, option, dflt != NULL ? dflt : "");
  1136. }
  1137. void PConfigArgs::Save(const PString & saveOptionName)
  1138. {
  1139.   if (PArgList::GetOptionCount(saveOptionName) == 0)
  1140.     return;
  1141.   config.DeleteSection(sectionName);
  1142.   for (PINDEX i = 0; i < optionCount.GetSize(); i++) {
  1143.     PString optionName = optionNames[i];
  1144.     if (optionCount[i] > 0 && optionName != saveOptionName) {
  1145.       if (optionString.GetAt(i) != NULL)
  1146.         config.SetString(sectionName, optionName, optionString[i]);
  1147.       else
  1148.         config.SetBoolean(sectionName, optionName, TRUE);
  1149.     }
  1150.   }
  1151. }
  1152. PString PConfigArgs::CharToString(char ch) const
  1153. {
  1154.   PINDEX index = optionLetters.Find(ch);
  1155.   if (index == P_MAX_INDEX)
  1156.     return PString();
  1157.   if (optionNames.GetAt(index) == NULL)
  1158.     return PString();
  1159.   return optionNames[index];
  1160. }
  1161. ///////////////////////////////////////////////////////////////////////////////
  1162. // PProcess
  1163. static PProcess * PProcessInstance;
  1164. int PProcess::p_argc;
  1165. char ** PProcess::p_argv;
  1166. char ** PProcess::p_envp;
  1167. #ifndef P_PLATFORM_HAS_THREADS
  1168. static BOOL PProcessTerminating = FALSE;
  1169. #endif
  1170. PProcess::PProcess(const char * manuf, const char * name,
  1171.                            WORD major, WORD minor, CodeStatus stat, WORD build)
  1172.   : manufacturer(manuf), productName(name)
  1173. {
  1174.   PProcessInstance = this;
  1175.   terminationValue = 0;
  1176.   majorVersion = major;
  1177.   minorVersion = minor;
  1178.   status = stat;
  1179.   buildNumber = build;
  1180.   if (p_argv != 0 && p_argc > 0) {
  1181.     arguments.SetArgs(p_argc-1, p_argv+1);
  1182.     executableFile = PString(p_argv[0]);
  1183.     if (!PFile::Exists(executableFile))
  1184.       executableFile += ".exe";
  1185.     if (productName.IsEmpty())
  1186.       productName = executableFile.GetTitle().ToLower();
  1187.   }
  1188.   InitialiseProcessThread();
  1189.   Construct();
  1190. }
  1191. int PProcess::_main(void *)
  1192. {
  1193.   Main();
  1194.   return terminationValue;
  1195. }
  1196. void PProcess::PreInitialise(int c, char ** v, char ** e)
  1197. {
  1198.   p_argc = c;
  1199.   p_argv = v;
  1200.   p_envp = e;
  1201. }
  1202. PProcess & PProcess::Current()
  1203. {
  1204.   if (PProcessInstance == NULL) {
  1205.     cerr << "Catastrophic failure, PProcess::Current() = NULL!!n";
  1206. #if defined(_MSC_VER) && defined(_DEBUG)
  1207.     __asm int 3;
  1208. #endif
  1209.     _exit(1);
  1210.   }
  1211.   return *PProcessInstance;
  1212. }
  1213. BOOL PProcess::IsInitialised()
  1214. {
  1215.   return PProcessInstance != NULL;
  1216. }
  1217. PObject::Comparison PProcess::Compare(const PObject & obj) const
  1218. {
  1219.   PAssert(obj.IsDescendant(PProcess::Class()), PInvalidCast);
  1220.   return productName.Compare(((const PProcess &)obj).productName);
  1221. }
  1222. void PProcess::Terminate()
  1223. {
  1224. #ifdef _WINDLL
  1225.   FatalExit(terminationValue);
  1226. #else
  1227. #ifndef P_PLATFORM_HAS_THREADS
  1228.   // Can only terminate process from the processes thread
  1229.   if (currentThread == this)
  1230.     exit(terminationValue);
  1231.   else
  1232.     PProcessTerminating = TRUE;
  1233. #else
  1234.   exit(terminationValue);
  1235. #endif
  1236. #endif
  1237. }
  1238. PString PProcess::GetThreadName() const
  1239. {
  1240.   return GetName(); 
  1241. }
  1242.  
  1243.  
  1244. void PProcess::SetThreadName(const PString & /*name*/)
  1245. {
  1246. }
  1247. PString PProcess::GetVersion(BOOL full) const
  1248. {
  1249.   const char * const statusLetter[NumCodeStatuses] =
  1250.     { "alpha", "beta", "pl" };
  1251.   return psprintf(full && buildNumber != 0 ? "%u.%u%s%u" : "%u.%u",
  1252.                 majorVersion, minorVersion, statusLetter[status], buildNumber);
  1253. }
  1254. ///////////////////////////////////////////////////////////////////////////////
  1255. // PThread
  1256. void PThread::PrintOn(ostream & strm) const
  1257. {
  1258.   PString name = GetThreadName();
  1259.   if (name.IsEmpty())
  1260.     name.sprintf("%s<%08x>", GetClass(), (int)this);
  1261.   strm << name;
  1262. }
  1263. PString PThread::GetThreadName() const
  1264. {
  1265.   return threadName; 
  1266. }
  1267.  
  1268.  
  1269. void PThread::SetThreadName(const PString & name)
  1270. {
  1271.   threadName = name; 
  1272. }
  1273. #ifndef P_PLATFORM_HAS_THREADS
  1274. void PThread::InitialiseProcessThread()
  1275. {
  1276.   basePriority = NormalPriority;  // User settable priority
  1277.   dynamicPriority = 0;            // Only thing running
  1278.   suspendCount = 0;               // Not suspended (would not be a good idea)
  1279.   ClearBlock();                   // No I/O blocking function
  1280.   status = Running;               // Thread is already running
  1281.   stackBase = NULL;
  1282.   link = this;
  1283.   ((PProcess*)this)->currentThread = this;
  1284. }
  1285. PThread::PThread(PINDEX stackSize,
  1286.                  AutoDeleteFlag deletion,
  1287.                  Priority priorityLevel,
  1288.                  const PString & name)
  1289.   : threadName(name)
  1290. {
  1291.   autoDelete = deletion == AutoDeleteThread;
  1292.   basePriority = priorityLevel;   // Threads user settable priority level
  1293.   dynamicPriority = 0;            // Run immediately
  1294.   suspendCount = 1;
  1295.   AllocateStack(stackSize);
  1296.   PAssert(stackBase != NULL, "Insufficient near heap for thread");
  1297.   status = Terminated; // Set to this so Restart() works
  1298.   Restart();
  1299. }
  1300. void PThread::Restart()
  1301. {
  1302.   if (status != Terminated) // Is already running
  1303.     return;
  1304.   ClearBlock();             // No I/O blocking function
  1305.   PThread * current = Current();
  1306.   link = current->link;
  1307.   current->link = this;
  1308.   status = Starting;
  1309. }
  1310. void PThread::Terminate()
  1311. {
  1312.   if (link == this || status == Terminated)
  1313.     return;   // Is only thread or already terminated
  1314.   if (status == Running) {
  1315.     status = Terminating;
  1316.     Yield(); // Never returns from here
  1317.   }
  1318.   PThread * prev = PThread::Current();
  1319.   while (prev->link != this)
  1320.     prev = prev->link;
  1321.   prev->link = link;   // Unlink it from the list
  1322.   status = Terminated;
  1323. }
  1324. void PThread::WaitForTermination() const
  1325. {
  1326.   while (!IsTerminated())
  1327.     Yield();
  1328. }
  1329. BOOL PThread::WaitForTermination(const PTimeInterval & maxWait) const
  1330. {
  1331.   PTimer timeout = maxWait;
  1332.   while (!IsTerminated()) {
  1333.     if (timeout == 0)
  1334.       return FALSE;
  1335.     Yield();
  1336.   }
  1337.   return TRUE;
  1338. }
  1339. void PThread::Suspend(BOOL susp)
  1340. {
  1341.   // Suspend/Resume the thread
  1342.   if (susp)
  1343.     suspendCount++;
  1344.   else
  1345.     suspendCount--;
  1346.   switch (status) {
  1347.     case Running : // Suspending itself, yield to next thread
  1348.       if (IsSuspended()) {
  1349.         status = Suspended;
  1350.         Yield();
  1351.       }
  1352.       break;
  1353.     case Waiting :
  1354.       if (IsSuspended())
  1355.         status = Suspended;
  1356.       break;
  1357.     case BlockedIO :
  1358.       if (IsSuspended())
  1359.         status = SuspendedBlockIO;
  1360.       break;
  1361.     case BlockedSem :
  1362.       if (IsSuspended())
  1363.         status = SuspendedBlockSem;
  1364.       break;
  1365.     case Suspended :
  1366.       if (!IsSuspended())
  1367.         status = Waiting;
  1368.       break;
  1369.     case SuspendedBlockIO :
  1370.       if (!IsSuspended())
  1371.         status = BlockedIO;
  1372.       break;
  1373.     case SuspendedBlockSem :
  1374.       if (!IsSuspended())
  1375.         status = BlockedSem;
  1376.       break;
  1377.     default :
  1378.       break;
  1379.   }
  1380. }
  1381. void PThread::Sleep(const PTimeInterval & time)
  1382. {
  1383.   sleepTimer = time;
  1384.   if (time == PMaxTimeInterval)
  1385.     sleepTimer.Pause();
  1386.   switch (status) {
  1387.     case Running : // Suspending itself, yield to next thread
  1388.       status = Sleeping;
  1389.       Yield();
  1390.       break;
  1391.     case Waiting :
  1392.     case Suspended :
  1393.       status = Sleeping;
  1394.       break;
  1395.     default :
  1396.       break;
  1397.   }
  1398. }
  1399. void PThread::BeginThread()
  1400. {
  1401.   if (IsSuspended()) { // Begins suspended
  1402.     status = Suspended;
  1403.     Yield();
  1404.   }
  1405.   else
  1406.     status = Running;
  1407.   Main();
  1408.   status = Terminating;
  1409.   Yield(); // Never returns from here
  1410. }
  1411. void PThread::Yield()
  1412. {
  1413.   PThread * current = PProcessInstance->currentThread;
  1414.   if (current == PProcessInstance) {
  1415.     PProcessInstance->GetTimerList()->Process();
  1416.     if (current->link == current)
  1417.       return;
  1418.   }
  1419.   else {
  1420.     char stackUsed;
  1421.     if (&stackUsed < current->stackBase) {
  1422.       char * buf = (char *)malloc(1000);
  1423.       sprintf(buf, "Stack overflow!n"
  1424.                    "n"
  1425.                    "Thread: 0x%08x - %sn"
  1426.                    "Stack top  : 0x%08xn"
  1427.                    "Stack base : 0x%08xn"
  1428.                    "Stack frame: 0x%08xn"
  1429.                    "n",
  1430.               (int)current, current->GetClass(),
  1431.               (int)current->stackTop,
  1432.               (int)current->stackBase,
  1433.               (int)&stackUsed);
  1434.       PAssertAlways(buf);
  1435.       PError << "Aborting." << endl;
  1436.       _exit(1);
  1437.     }
  1438.   }
  1439.   if (current->status == Running && current->basePriority == HighestPriority)
  1440.     return;
  1441.   do {
  1442.     if (current->status == Running)
  1443.       current->status = Waiting;
  1444.     static const int dynamicLevel[NumPriorities] = { -1, 3, 1, 0, 0 };
  1445.     current->dynamicPriority = dynamicLevel[current->basePriority];
  1446.     PThread * next = NULL; // Next thread to be scheduled
  1447.     PThread * prev = current; // Need the thread in the previous link
  1448.     PThread * start = current;  // Need thread in list that is the "start"
  1449.     PThread * thread = current->link;
  1450.     BOOL pass = 0;
  1451.     BOOL canUseLowest = TRUE;
  1452.     for (;;) {
  1453.       if (PProcessTerminating) {
  1454.         next = PProcessInstance;
  1455.         next->status = Running;
  1456.         break;
  1457.       }
  1458.       switch (thread->status) {
  1459.         case Waiting :
  1460.           if (thread->dynamicPriority == 0) {
  1461.             next = thread;
  1462.             next->status = Running;
  1463.           }
  1464.           else if (thread->dynamicPriority > 0) {
  1465.             thread->dynamicPriority--;
  1466.             canUseLowest = FALSE;
  1467.           }
  1468.           else if (pass > 1 && canUseLowest)
  1469.             thread->dynamicPriority++;
  1470.           break;
  1471.         case Sleeping :
  1472.           if (thread->sleepTimer == 0) {
  1473.             if (thread->IsSuspended())
  1474.               thread->status = Suspended;
  1475.             else {
  1476.               thread->status = Running;
  1477.               next = thread;
  1478.             }
  1479.           }
  1480.           break;
  1481.         case BlockedIO :
  1482.           if (thread->IsNoLongerBlocked()) {
  1483.             if (PProcessTerminating)
  1484.               next = PProcessInstance;
  1485.             else {
  1486.               thread->ClearBlock();
  1487.               next = thread;
  1488.             }
  1489.             next->status = Running;
  1490.           }
  1491.           break;
  1492.         case BlockedSem :
  1493.         case SuspendedBlockSem :
  1494.           if (thread->blockingSemaphore->timeout == 0) {
  1495.             thread->blockingSemaphore->PSemaphore::Signal();
  1496.             thread->blockingSemaphore->timeout = 0;
  1497.             if (thread->status == Waiting) {
  1498.               next = thread;
  1499.               next->status = Running;
  1500.             }
  1501.           }
  1502.           break;
  1503.         case Starting :
  1504.           if (!thread->IsSuspended())
  1505.             next = thread;
  1506.           break;
  1507.         case Terminating :
  1508.           if (thread == current)         // Cannot self terminate
  1509.             next = PProcessInstance;     // So switch to process thread first
  1510.           else {
  1511.             prev->link = thread->link;   // Unlink it from the list
  1512.             if (thread == start)         // If unlinking the "start" thread
  1513.               start = prev;              //    then we better make it still in list
  1514.             thread->status = Terminated; // Flag thread as terminated
  1515.             if (thread->autoDelete)
  1516.               delete thread;             // Destroy if auto-delete
  1517.             thread = prev;
  1518.           }
  1519.           break;
  1520.         default :
  1521.           break;
  1522.       }
  1523.       if (next != NULL)  // Have a thread to run
  1524.         break;
  1525.       // Need to have previous thread so can unlink a terminating thread
  1526.       prev = thread;
  1527.       thread = thread->link;
  1528.       if (thread == start) {
  1529.         pass++;
  1530.         if (pass > 3) // Everything is blocked
  1531.           PProcessInstance->OperatingSystemYield();
  1532.       }
  1533.     }
  1534.     PProcessInstance->currentThread = next;
  1535.     next->SwitchContext(current);
  1536.     // Could get here with a self terminating thread, so go around again if all
  1537.     // we did was switch stacks, and do not actually have a running thread.
  1538.   } while (PProcessInstance->currentThread->status != Running);
  1539.   if (PProcessTerminating) {
  1540.     PProcessTerminating = FALSE;
  1541.     if (PProcessInstance->IsDescendant(PServiceProcess::Class()))
  1542.       ((PServiceProcess *)PProcessInstance)->OnStop();
  1543.     exit(PProcessInstance->terminationValue);
  1544.   }
  1545. }
  1546. #endif
  1547. ///////////////////////////////////////////////////////////////////////////////
  1548. // PSemaphore
  1549. #ifndef P_PLATFORM_HAS_THREADS
  1550. PSemaphore::PSemaphore(unsigned initial, unsigned maxCount)
  1551. {
  1552.   PAssert(maxCount > 0, "Invalid semaphore maximum.");
  1553.   if (initial > maxCount)
  1554.     initial = maxCount;
  1555.   currentCount = initial;
  1556.   maximumCount = maxCount;
  1557. }
  1558. PSemaphore::~PSemaphore()
  1559. {
  1560.   PAssert(blockedThreads.IsEmpty(),
  1561.                         "Semaphore destroyed while still has blocked threads");
  1562. }
  1563. void PSemaphore::Wait()
  1564. {
  1565.   Wait(PMaxTimeInterval);
  1566. }
  1567. BOOL PSemaphore::Wait(const PTimeInterval & time)
  1568. {
  1569.   if (currentCount > 0)
  1570.     currentCount--;
  1571.   else {
  1572.     PThread * thread = PThread::Current();
  1573.     blockedThreads.Enqueue(thread);
  1574.     thread->blockingSemaphore = this;
  1575.     thread->status = PThread::BlockedSem;
  1576.     timeout = time;
  1577.     if (time == PMaxTimeInterval)
  1578.       timeout.Pause();
  1579.     PThread::Yield();
  1580.     if (timeout == 0)
  1581.       return FALSE;
  1582.   }
  1583.   return TRUE;
  1584. }
  1585. void PSemaphore::Signal()
  1586. {
  1587.   if (blockedThreads.GetSize() > 0) {
  1588.     PThread * thread = blockedThreads.Dequeue();
  1589.     switch (thread->status) {
  1590.       case PThread::BlockedSem :
  1591.         thread->status = PThread::Waiting;
  1592.         break;
  1593.       case PThread::SuspendedBlockSem :
  1594.         thread->status = PThread::Suspended;
  1595.         break;
  1596.       default:
  1597.         PAssertAlways("Semaphore unblock of thread that is not blocked");
  1598.     }
  1599.     thread->sleepTimer = 0;
  1600.     timeout = PMaxTimeInterval;
  1601.     timeout.Pause();
  1602.   }
  1603.   else if (currentCount < maximumCount)
  1604.     currentCount++;
  1605. }
  1606. BOOL PSemaphore::WillBlock() const
  1607. {
  1608.   return currentCount == 0;
  1609. }
  1610. PMutex::PMutex()
  1611.   : PSemaphore(1, 1)
  1612. {
  1613. }
  1614. PSyncPoint::PSyncPoint()
  1615.   : PSemaphore(0, 1)
  1616. {
  1617. }
  1618. #endif
  1619. void PSyncPointAck::Signal()
  1620. {
  1621.   PSyncPoint::Signal();
  1622.   ack.Wait();
  1623. }
  1624. void PSyncPointAck::Signal(const PTimeInterval & wait)
  1625. {
  1626.   PSyncPoint::Signal();
  1627.   ack.Wait(wait);
  1628. }
  1629. void PSyncPointAck::Acknowledge()
  1630. {
  1631.   ack.Signal();
  1632. }
  1633. void PCondMutex::WaitCondition()
  1634. {
  1635.   for (;;) {
  1636.     Wait();
  1637.     if (Condition())
  1638.       return;
  1639.     PMutex::Signal();
  1640.     OnWait();
  1641.     syncPoint.Wait();
  1642.   }
  1643. }
  1644. void PCondMutex::Signal()
  1645. {
  1646.   if (Condition())
  1647.     syncPoint.Signal();
  1648.   PMutex::Signal();
  1649. }
  1650. void PCondMutex::OnWait()
  1651. {
  1652.   // Do nothing
  1653. }
  1654. PIntCondMutex::PIntCondMutex(int val, int targ, Operation op)
  1655. {
  1656.   value = val;
  1657.   target = targ;
  1658.   operation = op;
  1659. }
  1660. void PIntCondMutex::PrintOn(ostream & strm) const
  1661. {
  1662.   strm << '(' << value;
  1663.   switch (operation) {
  1664.     case LT :
  1665.       strm << " < ";
  1666.     case LE :
  1667.       strm << " <= ";
  1668.     case GE :
  1669.       strm << " >= ";
  1670.     case GT :
  1671.       strm << " > ";
  1672.     default:
  1673.       strm << " == ";
  1674.   }
  1675.   strm << target << ')';
  1676. }
  1677. BOOL PIntCondMutex::Condition()
  1678. {
  1679.   switch (operation) {
  1680.     case LT :
  1681.       return value < target;
  1682.     case LE :
  1683.       return value <= target;
  1684.     case GE :
  1685.       return value >= target;
  1686.     case GT :
  1687.       return value > target;
  1688.     default :
  1689.       break;
  1690.   }
  1691.   return value == target;
  1692. }
  1693. PIntCondMutex & PIntCondMutex::operator=(int newval)
  1694. {
  1695.   Wait();
  1696.   value = newval;
  1697.   Signal();
  1698.   return *this;
  1699. }
  1700. PIntCondMutex & PIntCondMutex::operator++()
  1701. {
  1702.   Wait();
  1703.   value++;
  1704.   Signal();
  1705.   return *this;
  1706. }
  1707. PIntCondMutex & PIntCondMutex::operator+=(int inc)
  1708. {
  1709.   Wait();
  1710.   value += inc;
  1711.   Signal();
  1712.   return *this;
  1713. }
  1714. PIntCondMutex & PIntCondMutex::operator--()
  1715. {
  1716.   Wait();
  1717.   value--;
  1718.   Signal();
  1719.   return *this;
  1720. }
  1721. PIntCondMutex & PIntCondMutex::operator-=(int dec)
  1722. {
  1723.   Wait();
  1724.   value -= dec;
  1725.   Signal();
  1726.   return *this;
  1727. }
  1728. void PReadWriteMutex::StartRead()
  1729. {
  1730.   starvationPreventer.Wait();
  1731.   starvationPreventer.Signal();
  1732.   ++readers;
  1733. }
  1734. void PReadWriteMutex::EndRead()
  1735. {
  1736.   --readers;
  1737. }
  1738. void PReadWriteMutex::StartWrite()
  1739. {
  1740.   starvationPreventer.Wait();
  1741.   readers.WaitCondition();
  1742. }
  1743. void PReadWriteMutex::EndWrite()
  1744. {
  1745.   starvationPreventer.Signal();
  1746.   readers.Signal();
  1747. }
  1748. // End Of File ///////////////////////////////////////////////////////////////