Another update from the internal CVS repository /m/src. RDF_19990305_BASE
authorwtc%netscape.com
Fri, 05 Mar 1999 22:32:56 +0000
changeset 489 34073f036ca6
parent 488 9a9b4cd4edeb
child 490 028a6f737270
child 491 91c3f3b19cc4
push idunknown
push userunknown
push dateunknown
Another update from the internal CVS repository /m/src.
lib/tests/event.c
lib/tests/windows/winevent.c
pr/src/misc/pratom.c
pr/src/pthreads/ptthread.c
pr/src/threads/prrwlock.c
pr/tests/Makefile
pr/tests/README.TXT
pr/tests/runtests.ksh
pr/tests/socket.c
pr/tests/testfile.c
pr/tests/timetest.c
pr/tests/y2k.c
--- a/lib/tests/event.c
+++ b/lib/tests/event.c
@@ -315,29 +315,35 @@ static void Help( void )
             "where: -h gives this message\n"
             "       -d sets debug mode (a no-op here)\n"
         );    
 } /* end Help() */
 
 PRIntn main(PRIntn argc, char **argv )
 {
     PLOptStatus os;
-  	PLOptState *opt = PL_CreateOptState(argc, argv, "dh");
+  	PLOptState *opt = PL_CreateOptState(argc, argv, "dhmt:i:");
 
 
 	while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
     {
 		if (PL_OPT_BAD == os) continue;
         switch (opt->option)
         {
         case 'm':  /* use monitored event queue */
             useMonitoredQueue = PR_TRUE;
             break;
         case 'd':  /* debug mode (noop) */
             break;
+        case 't':  /* needs guidance */
+            numThreads = atol(opt->value);
+            break;
+        case 'i':  /* needs guidance */
+            iterations = atol(opt->value);
+            break;
         case 'h':  /* needs guidance */
         default:
             Help();
             return 2;
         }
     }
 	PL_DestroyOptState(opt);
 
--- a/lib/tests/windows/winevent.c
+++ b/lib/tests/windows/winevent.c
@@ -270,18 +270,17 @@ static void PR_CALLBACK TimerThread( voi
 }    
 
 static char *startMessage = "Poppad: NSPR Windows GUI and event test program.\n"
                             "Every 1 second gets a '.'.\n"
                             "The test self terminates in less than a minute\n"
                             "You should be able to type in the window.\n\n";
 
 static char *stopMessage = "\n\nIf you saw a series of dots being emitted in the window\n"
-                           " at one second intervals, the test worked.\n\n"
-                           "Begin Test for multiple event queues.\n\n";
+                           " at one second intervals, the test worked.\n\n";
 
 /*
 ** HandlePadEvent() -- gets called because of PostEvent
 */
 static void PR_CALLBACK HandlePadEvent( PadEvent *padEvent )
 {
     char *cp;
     static const long lineLimit = 10;   /* limit on number of '.' per line */
--- a/pr/src/misc/pratom.c
+++ b/pr/src/misc/pratom.c
@@ -65,22 +65,22 @@ static pthread_mutex_t static_atomic_loc
         PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
         PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
         PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
         PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
         PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER };
 
 #ifdef DEBUG
 static PRInt32 static_hash_lock_counts[DEFAULT_ATOMIC_LOCKS];
-static PRInt32 *hash_lock_counts;
+static PRInt32 *hash_lock_counts = static_hash_lock_counts;
 #endif
 
 static PRUint32	num_atomic_locks = DEFAULT_ATOMIC_LOCKS;
-static pthread_mutex_t *atomic_locks = NULL;
-static PRUint32 atomic_hash_mask;
+static pthread_mutex_t *atomic_locks = static_atomic_locks;
+static PRUint32 atomic_hash_mask = DEFAULT_ATOMIC_LOCKS - 1;
 
 #define _PR_HASH_FOR_LOCK(ptr) 							\
 			((PRUint32) (((PRUptrdiff) (ptr) >> 2)	^	\
 						((PRUptrdiff) (ptr) >> 8)) &	\
 						atomic_hash_mask)
 
 void _PR_MD_INIT_ATOMIC()
 {
@@ -122,30 +122,30 @@ PRIntn lock_count;
 		if (atomic_locks) {
 			hash_lock_counts = PR_CALLOC(num_atomic_locks * sizeof(PRInt32));
 			if (hash_lock_counts == NULL) {
 				PR_DELETE(atomic_locks);
 				atomic_locks = NULL;
 			}
 		}
 #endif
-	}
-	if (atomic_locks == NULL) {
-		/*
-		 *	Use statically allocated locks
-		 */
-		atomic_locks = static_atomic_locks;
-		num_atomic_locks = DEFAULT_ATOMIC_LOCKS;
-#ifdef DEBUG
-		hash_lock_counts = static_hash_lock_counts;
-#endif
+		if (atomic_locks == NULL) {
+			/*
+			 *	Use statically allocated locks
+			 */
+			atomic_locks = static_atomic_locks;
+			num_atomic_locks = DEFAULT_ATOMIC_LOCKS;
+	#ifdef DEBUG
+			hash_lock_counts = static_hash_lock_counts;
+	#endif
+		}
+		atomic_hash_mask = num_atomic_locks - 1;
 	}
 	PR_ASSERT(PR_FloorLog2(num_atomic_locks) ==
 								PR_CeilingLog2(num_atomic_locks));
-	atomic_hash_mask = num_atomic_locks - 1;
 }
 
 PRInt32
 _PR_MD_ATOMIC_INCREMENT(PRInt32 *val)
 {
     PRInt32 rv;
     PRInt32 idx = _PR_HASH_FOR_LOCK(val);
 
--- a/pr/src/pthreads/ptthread.c
+++ b/pr/src/pthreads/ptthread.c
@@ -845,26 +845,16 @@ void _PR_InitThreads(
      * and holding PRThread references are actually holding pointers to
      * nothing.
      */
     rv = PTHREAD_KEY_CREATE(&pt_book.key, _pt_thread_death);
     PR_ASSERT(0 == rv);
     rv = pthread_setspecific(pt_book.key, thred);
     PR_ASSERT(0 == rv);    
     PR_SetThreadPriority(thred, priority);
-
-    /*
-     * Linux pthreads use SIGUSR1 and SIGUSR2 internally, which
-     * conflict with the use of these two signals in our GC support.
-     * So we don't know how to support GC on Linux pthreads.
-     */
-#if !defined(LINUX) && !defined(FREEBSD) && !defined(NETBSD) && !defined(OPENBSD)
-	init_pthread_gc_support();
-#endif
-
 }  /* _PR_InitThreads */
 
 PR_IMPLEMENT(PRStatus) PR_Cleanup()
 {
     PRThread *me = PR_CurrentThread();
     PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_Cleanup: shutting down NSPR"));
     PR_ASSERT(me->state & PT_THREAD_PRIMORD);
     if (me->state & PT_THREAD_PRIMORD)
@@ -953,24 +943,29 @@ static sigset_t javagc_intsoff_sigmask;
 
 /* a bogus signal mask for forcing a timed wait */
 /* Not so bogus in AIX as we really do a sigwait */
 static sigset_t sigwait_set;
 
 static struct timespec onemillisec = {0, 1000000L};
 static struct timespec hundredmillisec = {0, 100000000L};
 
-#endif /* defined(_PR_DCETHREADS) */
-
 static void suspend_signal_handler(PRIntn sig);
 
 #ifdef PT_NO_SIGTIMEDWAIT
 static void null_signal_handler(PRIntn sig);
 #endif
 
+#endif /* defined(_PR_DCETHREADS) */
+
+/*
+ * Linux pthreads use SIGUSR1 and SIGUSR2 internally, which
+ * conflict with the use of these two signals in our GC support.
+ * So we don't know how to support GC on Linux pthreads.
+ */
 static void init_pthread_gc_support()
 {
     PRIntn rv;
 
 #if defined(_PR_DCETHREADS)
 	rv = sigemptyset(&javagc_vtalarm_sigmask);
     PR_ASSERT(0 == rv);
 	rv = sigaddset(&javagc_vtalarm_sigmask, SIGVTALRM);
@@ -1283,23 +1278,29 @@ PR_IMPLEMENT(void) PR_ResumeTest(PRThrea
 #endif
 
     thred->suspend &= ~PT_THREAD_RESUMED;
 
     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, (
         "End PR_ResumeTest thred %X tid %X\n", thred, thred->id));
 }  /* PR_ResumeTest */
 
+static pthread_once_t pt_gc_support_control = PTHREAD_ONCE_INIT;
+
 PR_IMPLEMENT(void) PR_SuspendAll()
 {
 #ifdef DEBUG
     PRIntervalTime stime, etime;
 #endif
     PRThread* thred = pt_book.first;
     PRThread *me = PR_CurrentThread();
+    int rv;
+
+    rv = pthread_once(&pt_gc_support_control, init_pthread_gc_support);
+    PR_ASSERT(0 == rv);
     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n"));
     /*
      * Stop all threads which are marked GC able.
      */
     PR_Lock(pt_book.ml);
 #ifdef DEBUG
     suspendAllOn = PR_TRUE;
     stime = PR_IntervalNow();
@@ -1377,26 +1378,30 @@ PR_IMPLEMENT(void *)PR_GetSP(PRThread *t
     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
 	    ("in PR_GetSP thred %X thid = %X, sp = %X \n", 
 	    thred, thred->id, thred->sp));
     return thred->sp;
 }  /* PR_GetSP */
 
 #else /* !defined(_PR_DCETHREADS) */
 
+static pthread_once_t pt_gc_support_control = pthread_once_init;
+
 /*
  * For DCE threads, there is no pthread_kill or a way of suspending or resuming a
  * particular thread.  We will just disable the preemption (virtual timer alarm) and
  * let the executing thread finish the garbage collection.  This stops all other threads
  * (GC able or not) and is very inefficient but there is no other choice.
  */
 PR_IMPLEMENT(void) PR_SuspendAll()
 {
     PRIntn rv;
 
+    rv = pthread_once(&pt_gc_support_control, init_pthread_gc_support);
+    PR_ASSERT(0 == rv);  /* returns -1 on failure */
 #ifdef DEBUG
     suspendAllOn = PR_TRUE;
 #endif
     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n"));
     /* 
      * turn off preemption - i.e add virtual alarm signal to the set of 
      * blocking signals 
      */
--- a/pr/src/threads/prrwlock.c
+++ b/pr/src/threads/prrwlock.c
@@ -84,19 +84,19 @@ static PRUintn	pr_thread_rwlock_alloc_fa
 
 typedef struct thread_rwlock_stack {
 	PRInt32		trs_index;									/* top of stack */
 	PRRWLock	*trs_stack[_PR_RWLOCK_RANK_ORDER_LIMIT];	/* stack of lock
 														 	   pointers */
 
 } thread_rwlock_stack;
 
-static void _PR_SET_THREAD_RWLOCK_RANK(PRThread *me, PRRWLock *rwlock);
-static PRUint32 _PR_GET_THREAD_RWLOCK_RANK(PRThread *me);
-static void _PR_UNSET_THREAD_RWLOCK_RANK(PRThread *me, PRRWLock *rwlock);
+static void _PR_SET_THREAD_RWLOCK_RANK(PRRWLock *rwlock);
+static PRUint32 _PR_GET_THREAD_RWLOCK_RANK(void);
+static void _PR_UNSET_THREAD_RWLOCK_RANK(PRRWLock *rwlock);
 static void _PR_RELEASE_LOCK_STACK(void *lock_stack);
 
 #endif
 
 /*
  * Reader/Writer Locks
  */
 
@@ -194,31 +194,28 @@ PR_DestroyRWLock(PRRWLock *rwlock)
 }
 
 /*
 ** Read-lock the RWLock.
 */
 PR_IMPLEMENT(void)
 PR_RWLock_Rlock(PRRWLock *rwlock)
 {
-#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
-PRThread *me = PR_GetCurrentThread();
-#endif
 #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
 int err;
 #endif
 
 #ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
 	/*
 	 * assert that rank ordering is not violated; the rank of 'rwlock' should
 	 * be equal to or greater than the highest rank of all the locks held by
 	 * the thread.
 	 */
 	PR_ASSERT((rwlock->rw_rank == PR_RWLOCK_RANK_NONE) || 
-					(rwlock->rw_rank >= _PR_GET_THREAD_RWLOCK_RANK(me)));
+					(rwlock->rw_rank >= _PR_GET_THREAD_RWLOCK_RANK()));
 #endif
 
 #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
 	err = RWLOCK_RDLOCK(&rwlock->rw_lock);
 	PR_ASSERT(err == 0);
 #else
 	PR_Lock(rwlock->rw_lock);
 	/*
@@ -237,42 +234,42 @@ int err;
 
 	PR_Unlock(rwlock->rw_lock);
 #endif
 
 #ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
 	/*
 	 * update thread's lock rank
 	 */
-	_PR_SET_THREAD_RWLOCK_RANK(me,rwlock);
+	_PR_SET_THREAD_RWLOCK_RANK(rwlock);
 #endif
 }
 
 /*
 ** Write-lock the RWLock.
 */
 PR_IMPLEMENT(void)
 PR_RWLock_Wlock(PRRWLock *rwlock)
 {
 PRInt32 lock_acquired = 0;
-#if defined(DEBUG) || defined(_PR_RWLOCK_RANK_ORDER_DEBUG)
+#if defined(DEBUG)
 PRThread *me = PR_GetCurrentThread();
 #endif
 #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
 int err;
 #endif
 
 #ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
 	/*
 	 * assert that rank ordering is not violated; the rank of 'rwlock' should
 	 * be equal to or greater than the highest rank of all the locks held by
 	 * the thread.
 	 */
 	PR_ASSERT((rwlock->rw_rank == PR_RWLOCK_RANK_NONE) || 
-					(rwlock->rw_rank >= _PR_GET_THREAD_RWLOCK_RANK(me)));
+					(rwlock->rw_rank >= _PR_GET_THREAD_RWLOCK_RANK()));
 #endif
 
 #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
 	err = RWLOCK_WRLOCK(&rwlock->rw_lock);
 	PR_ASSERT(err == 0);
 #else
 	PR_Lock(rwlock->rw_lock);
 	/*
@@ -283,38 +280,38 @@ int err;
 		PR_WaitCondVar(rwlock->rw_writer_waitq, PR_INTERVAL_NO_TIMEOUT);
 		rwlock->rw_writer_cnt--;
 	}
 	/*
 	 * apply write lock
 	 */
 	rwlock->rw_lock_cnt--;
 	PR_ASSERT(rwlock->rw_lock_cnt == -1);
+#ifdef DEBUG
 	PR_ASSERT(me != NULL);
-#ifdef DEBUG
-    rwlock->rw_owner = me;
+	rwlock->rw_owner = me;
 #endif
 	PR_Unlock(rwlock->rw_lock);
 #endif
 
 #ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
 	/*
 	 * update thread's lock rank
 	 */
-	_PR_SET_THREAD_RWLOCK_RANK(me,rwlock);
+	_PR_SET_THREAD_RWLOCK_RANK(rwlock);
 #endif
 }
 
 /*
 ** Unlock the RW lock.
 */
 PR_IMPLEMENT(void)
 PR_RWLock_Unlock(PRRWLock *rwlock)
 {
-#if defined(DEBUG) || defined(_PR_RWLOCK_RANK_ORDER_DEBUG)
+#if defined(DEBUG)
 PRThread *me = PR_GetCurrentThread();
 #endif
 #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
 int err;
 #endif
 
 #if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
 	err = RWLOCK_UNLOCK(&rwlock->rw_lock);
@@ -359,17 +356,17 @@ int err;
 	}
 	PR_Unlock(rwlock->rw_lock);
 #endif
 
 #ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
 	/*
 	 * update thread's lock rank
 	 */
-	_PR_UNSET_THREAD_RWLOCK_RANK(me, rwlock);
+	_PR_UNSET_THREAD_RWLOCK_RANK(rwlock);
 #endif
 	return;
 }
 
 #ifndef _PR_RWLOCK_RANK_ORDER_DEBUG
 
 void _PR_InitRWLocks(void) { }
 
@@ -390,17 +387,17 @@ void _PR_InitRWLocks(void)
 /*
  * _PR_SET_THREAD_RWLOCK_RANK
  *		Set a thread's lock rank, which is the highest of the ranks of all
  *		the locks held by the thread. Pointers to the locks are added to a
  *		per-thread list, which is anchored off a thread-private data key.
  */
 
 static void
-_PR_SET_THREAD_RWLOCK_RANK(PRThread *me, PRRWLock *rwlock)
+_PR_SET_THREAD_RWLOCK_RANK(PRRWLock *rwlock)
 {
 thread_rwlock_stack *lock_stack;
 PRStatus rv;
 
 	/*
 	 * allocate a lock stack
 	 */
 	if ((lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key)) == NULL) {
@@ -437,17 +434,17 @@ static void
 /*
  * _PR_GET_THREAD_RWLOCK_RANK
  *
  *		return thread's lock rank. If thread-private-data for the lock
  *		stack is not allocated, return PR_RWLOCK_RANK_NONE.
  */
 	
 static PRUint32
-_PR_GET_THREAD_RWLOCK_RANK(PRThread *me)
+_PR_GET_THREAD_RWLOCK_RANK(void)
 {
 	thread_rwlock_stack *lock_stack;
 
 	if ((lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key)) == NULL)
 		return (PR_RWLOCK_RANK_NONE);
 	else
 		return(lock_stack->trs_stack[lock_stack->trs_index - 1]->rw_rank);
 }
@@ -455,17 +452,17 @@ static PRUint32
 /*
  * _PR_UNSET_THREAD_RWLOCK_RANK
  *
  *		remove the rwlock from the lock stack. Since locks may not be
  *		unlocked in a FIFO order, the entire lock stack is searched.
  */
 	
 static void
-_PR_UNSET_THREAD_RWLOCK_RANK(PRThread *me, PRRWLock *rwlock)
+_PR_UNSET_THREAD_RWLOCK_RANK(PRRWLock *rwlock)
 {
 	thread_rwlock_stack *lock_stack;
 	int new_index = 0, index, done = 0;
 
 	lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key);
 
 	PR_ASSERT(lock_stack != NULL);
 
--- a/pr/tests/Makefile
+++ b/pr/tests/Makefile
@@ -139,16 +139,17 @@ CSRCS =             \
 	tmoacc.c        \
 	tmocon.c        \
 	tpd.c			\
 	vercheck.c		\
 	version.c	    \
 	udpsrv.c	    \
 	writev.c        \
 	xnotify.c       \
+	y2k.c           \
 	$(NULL)
 
 ifeq ($(OS_TARGET),OS2)
 CSRCS +=            \
 	sleep.c			\
 	stat.c		    \
 	yield.c         \
 	$(NULL)
new file mode 100644
--- /dev/null
+++ b/pr/tests/README.TXT
@@ -0,0 +1,434 @@
+File: pr/tests/readme
+
+This document describes the test cases in the NSPR directory
+pr/tests.
+
+=====================================================================
+There are some sub-directories here:
+
+dll
+	sources for the .dll(.so) used by test dlltest.c
+
+macbuild
+	MacIntosh project files
+
+server
+	an empty directory. Does anyone remember why?
+
+w16gui
+	Sources for a modified version of the poppad application from
+	Charles Petzold's book "Programming Windows 3.1". These
+	sources were modified to test the library lib/ds/PLEvent.
+	These files are obsolete and will not be maintained.
+	
+	This test was superceded by lib/tests/windows/winevent.c and
+	lib/event.c and is now owned by CPD.
+
+=====================================================================
+The individual files are described here.
+
+The script 'runtests.ksh' enumerates and runs test cases that are
+expected to run on all platforms.
+
+
+accept.c
+	Tests PR_Accept() and related socket functions.
+
+acceptread.c
+	Tests PR_AcceptRead()
+
+alarm.c
+	Tests alarm functions declared in obsolete/pralarm.h.
+	The alarm functions are obsolete, so is this test.
+
+atomic.c
+	Tests Atomic operations defined in pratom.h
+
+attach.c
+	Test PR_AttachThread()
+	Note: This is an NSPR private function.
+
+bigfile.c
+	Test 64bit file offset functions declared in prio.h
+
+bug1test.c
+	Demonstrates a bug on NT.
+
+cleanup.c
+	Tests PR_Cleanup() declared in prinit.h
+
+cltsrv.c
+	Tests many socket functions.
+
+concur.c
+	Tests threading functions and concurrent operations.
+
+cvar.c
+	Tests condition variables.
+
+cvar2.c
+	Tests condition variables. A rather abusive test.
+
+dbmalloc.c
+	Obsolete. Originally for testing debug builds of NSPR's malloc.
+
+dbmalloc1.c
+	Obsolete. Originally for testing debug builds of NSPR's malloc.
+
+dceemu.c
+	Tests special functions for DCE emulation.
+
+depend.c
+	Obsoltet. Tests early spec for library dependency.
+
+dlltest.c
+	Tests dynamic library fucntions. Used with dll/my.c
+
+dtoa.c
+	Tests conversions of double to string.
+
+exit.c
+	Tests PR_ProcessExit() declared in prinit.h
+
+fileio.c
+	Tests NSPR semaphores a bit of file i/o and threading
+	functions.
+
+foreign.c
+	Test auto-attach of a thread created by something other than
+	NSPR.
+
+forktest.c
+	Limited use. Tests unix fork() and related functions.
+
+fsync.c
+	Tests use of PR_Sync() declared in prio.h
+
+getproto.c
+	Tests socket functions PR_GetProtoByName(), etc.
+
+i2l.c
+	Tests LongLong functions for converting 32bit integer to 64bit
+	integer.
+
+initclk.c
+	Tests timing on minimal use of condition variable
+
+inrval.c
+	Tests interval timing functions.
+
+instrumt.c
+	Tests instrumentation functions. prcountr.h prtrace.h
+
+intrupt.c
+	Tests PR_Interrupt()
+
+ioconthr.c
+	Tests i/o continuation mechanism in pthreads.
+
+io_timeout.c
+	Test socket i/o timeouts.
+
+io_timeoutk.c
+	Obsolete. Subsumed in io_timeout.c
+
+io_timeoutu.c
+	Obsolete. Subsumed in io_timeout.c
+
+ipv6.c
+	Tests IPv6. IPv6 is not used by NSPR clients.
+
+join.c
+	Tests PR_JoinThread()
+
+joinkk.c
+	Tests PR_JoinThread()
+
+joinku.c
+	Tests PR_JoinThread()
+
+joinuk.c
+	Tests PR_JoinThread()
+
+joinuu.c
+	Tests PR_JoinThread()
+
+layer.c
+	Tests layered I/O.
+
+lazyinit.c
+	Tests implicit initialization.
+
+lltest.c
+	Tests LongLong (64bit integer) arithmentic and conversions.
+
+lock.c
+	Tests PR_Lock() in heavily threaded environment.
+
+lockfile.c
+	Test PR_Lockfile().
+
+logger.c
+	Tests PR_LOG()
+
+makefile
+	The makefile that builds all the tests
+
+many_cv.c
+	Tests aquiring a large number of condition variables.
+
+multiwait.c
+	???
+
+nbconn.c
+	Test non-blocking connect.
+
+nblayer.c
+	Tests NSPR's layered I/O capability.
+
+nonblock.c
+	Tests operations on non-blocking socket.
+
+op_2long.c
+	Tests PR_Open() where filename is too long.
+
+op_filnf.c
+	Tests PR_Open() where filename is NotFound.
+
+op_filok.c
+	Tests PR_Open() where filename is accessable.
+
+op_noacc.c
+	Tests PR_Open() where file permissions are wrong.
+	Limited use. Windows has no concept of Unix style file permissions.
+
+op_nofil.c
+	Tests PR_Open() where filename does not exist.
+
+parent.c
+	Test parent/child process capability
+
+perf.c
+	Tests and measures context switch times for various thread
+	syncronization functions.
+
+pipeping.c
+	Tests inter-process pipes. Run with pipepong.c
+
+pipepong.c
+	Tests inter-process pipes. Run with pipeping.c
+
+pipeself.c
+	Tests inter-thread pipes.
+
+pollable.c
+	Tests pollable events. prio.h
+
+poll_er.c
+	Tests PR_Poll() where an error is expected.
+
+poll_nm.c
+	Tests PR_Poll() where normal operation is expected.
+
+poll_to.c
+	Tests PR_Poll() where timeout is expected.
+
+prftest.c
+	Tests printf-like formatting.
+
+prftest1.c
+	Obsolete. Subsumed in prftest.c
+
+prftest2.c
+	Obsolete. Subsumed in prftest.c
+
+priotest.c
+	Limited use. Tests NSPR thread dispatching priority.
+
+provider.c
+
+prpoll.c
+	Tests PR_Poll().
+
+prselect.c
+	Obsolete. PR_Select() is obsolete.
+
+prttools.h
+	Unused file.
+
+ranfile.c
+	Tests random file access.
+
+readme
+	This file.
+
+runtests.ksh
+	A korn shell script that runs a set of tests that should run
+	on any of the NSPR supported platforms.
+
+runtests.pl
+	A perl script to run the test cases. This srcipt runs tests
+	common to all platforms and runs tests applicable to specific
+	platforms. Uses file runtests.txt to control execution.
+
+runtests.txt
+	Control file for perl script: runtests.pl
+
+rwlocktest.c
+	Tests Reader/Writer lock
+
+selct_er.c
+	Obsolete. PR_Select() is obsolete.
+
+selct_nm.c
+	Obsolete. PR_Select() is obsolete.
+
+selct_to.c
+	Obsolete. PR_Select() is obsolete.
+
+select2.c
+	Obsolete. PR_Select() is obsolete.
+
+sel_spd.c
+	Obsolete. PR_Select() is obsolete.
+
+sem.c
+	Obsolete. Semaphores are not supported.
+
+server_test.c
+	Tests sockets by simulating a server in loopback mode.
+	Makes its own client threads.
+
+servr_kk.c
+	Tests client/server sockets, threads using system threads.
+
+servr_ku.c
+	Tests client/server sockets, threads using system and user threads.
+
+servr_uk.c
+	Tests client/server sockets, threads using system and user threads.
+
+servr_uu.c
+	Tests client/server sockets, threads user threads.
+
+short_thread.c
+	Tests short-running threads. Useful for testing for race conditions.
+
+sigpipe.c
+	Tests NSPR's SIGPIPE handler. Unix only.
+
+sleep.c
+	Limited use. Tests sleep capability of platform.
+
+socket.c
+	Tests many socket functions.
+
+sockopt.c
+	Tests setting and getting socket options.
+
+sprintf.c
+	Tests sprintf.
+
+sproc_ch.c
+	Obsolete. Tests IRIX sproc-based threads.
+
+sproc_p.c
+	Obsolete. Tests IRIX sproc-based threads.
+
+stack.c
+	Test atomic stack operations.
+
+stat.c
+	Tests performance of getfileinfo() vs. stat()
+
+stdio.c
+	Tests NSPR's handling of stdin, stdout, stderr.
+
+strod.c
+	Tests formatting of double precision floating point.
+
+suspend.c
+	Private interfaces PR_SuspendAll(), PR_ResumeAll(), etc.
+
+switch.c
+	Tests thread switching
+
+system.c
+	Tests PR_GetSystemInfo()
+
+testbit.c
+	Tests bit arrays.
+
+testfile.c
+	Tests many file I/O functions.
+
+threads.c
+	Tests thread caching.
+
+thruput.c
+	Tests socket thruput. Must be run by hand as client/server.
+	Does not self terminate.
+
+time.c
+	Incomplete. Limited use.
+
+timemac.c
+	Test time and date functions. Originally for Mac.
+
+timetest.c
+	Tests time conversion over a wide range of dates.
+
+tmoacc.c
+	Server to tmocon.c and writev.c
+	Do not run it by itself.
+
+tmocon.c
+	Client thread to tmoacc.c
+
+tpd.c
+	Tests thread private data.
+
+udpsrv.c
+	Tests UDP socket functions.
+
+ut_ttools.h
+	unused file.
+
+version.c
+	Extract and print library version data.
+
+vercheck.c
+	Test PR_VersionCheck().
+
+writev.c
+	Tests gather-write on a socket. Requires tmoacc.c
+
+xnotify.c
+	Tests cached monitors.
+
+yield.c
+	Limited use
+
+y2k.c
+	Test to verify NSPR's date functions as Y2K compliant.
+
+dll\Makefile
+	makefile for mygetval.c, mysetval.c
+
+dll\mygetval.c
+	Dynamic library test. See also dlltest.c
+
+dll\mysetval.c
+	Dynamic library test. See also dlltest.c
+
+w16gui\Makefile
+	Obsolete. Tests for lib/ds/PLEvent on Windows 3.1.
+w16gui\popfile.c
+w16gui\popfind.c
+w16gui\popfont.c
+w16gui\poppad.c
+w16gui\poppad.h
+w16gui\poppad.ico
+w16gui\poppad.rc
+w16gui\popprnt0.c
+w16gui\readme.1st
--- a/pr/tests/runtests.ksh
+++ b/pr/tests/runtests.ksh
@@ -1,8 +1,10 @@
+#!/bin/ksh
+
 #
 # The contents of this file are subject to the Netscape Public License
 # Version 1.0 (the "NPL"); you may not use this file except in
 # compliance with the NPL.  You may obtain a copy of the NPL at
 # http://www.mozilla.org/NPL/
 # 
 # Software distributed under the NPL is distributed on an "AS IS" basis,
 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
@@ -156,15 +158,16 @@ xnotify"
 OBJDIR=`basename $PWD`
 echo "\nNSPR Test Results - $OBJDIR\n"
 echo "BEGIN\t\t\t`date`"
 echo "NSPR_TEST_LOGFILE\t${LOGFILE}\n"
 echo "Test\t\t\tResult\n"
 for prog in $TESTS
 do
 echo "$prog\c"
-./$prog >> LOGFILE 2>&1
+./$prog >> ${LOGFILE} 2>&1
 if [ 0 = $? ] ; then
 	echo "\t\t\tPassed";
 else
 	echo "\t\t\tFAILED";
 fi;
 done
+echo "END\t\t\t`date`"
--- a/pr/tests/socket.c
+++ b/pr/tests/socket.c
@@ -29,17 +29,17 @@
 #include "plgetopt.h"
 
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
 #ifdef XP_UNIX
 #include <sys/mman.h>
 #endif
-#if defined(_PR_PTHREADS)
+#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
 #include <pthread.h>
 #endif
 
 #ifdef WINNT
 #include <process.h>
 #endif
 
 static int _debug_on = 0;
@@ -257,17 +257,17 @@ PRThread* create_new_thread(PRThreadType
 							PRThreadPriority priority,
 							PRThreadScope scope,
 							PRThreadState state,
 							PRUint32 stackSize, PRInt32 index)
 {
 PRInt32 native_thread = 0;
 
 	PR_ASSERT(state == PR_UNJOINABLE_THREAD);
-#if defined(_PR_PTHREADS) || defined(WINNT)
+#if (defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)) || defined(WINNT)
 	switch(index %  4) {
 		case 0:
 			scope = (PR_LOCAL_THREAD);
 			break;
 		case 1:
 			scope = (PR_GLOBAL_THREAD);
 			break;
 		case 2:
@@ -276,17 +276,17 @@ PRInt32 native_thread = 0;
 		case 3:
 			native_thread = 1;
 			break;
 		default:
 			PR_ASSERT(!"Invalid scope");
 			break;
 	}
 	if (native_thread) {
-#ifdef _PR_PTHREADS
+#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
 		pthread_t tid;
 		if (!pthread_create(&tid, NULL, start, arg))
 			return((PRThread *) tid);
 		else
 			return (NULL);
 #else
 		HANDLE thandle;
 		
--- a/pr/tests/testfile.c
+++ b/pr/tests/testfile.c
@@ -21,17 +21,17 @@
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #ifdef WIN32
 #include <windows.h>
 #include <process.h>
 #endif
-#if defined(_PR_PTHREADS)
+#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
 #include <pthread.h>
 #endif
 
 #if defined(XP_OS2)
 #define INCL_DOSFILEMGR
 #include <os2.h>
 #ifdef XP_OS2_EMX
 #include <getopt.h>
@@ -106,17 +106,17 @@ PRThread* create_new_thread(PRThreadType
 							PRThreadPriority priority,
 							PRThreadScope scope,
 							PRThreadState state,
 							PRUint32 stackSize, PRInt32 index)
 {
 PRInt32 native_thread = 0;
 
 	PR_ASSERT(state == PR_UNJOINABLE_THREAD);
-#if defined(_PR_PTHREADS) || defined(WINNT)
+#if (defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)) || defined(WINNT)
 	switch(index %  4) {
 		case 0:
 			scope = (PR_LOCAL_THREAD);
 			break;
 		case 1:
 			scope = (PR_GLOBAL_THREAD);
 			break;
 		case 2:
@@ -125,17 +125,17 @@ PRInt32 native_thread = 0;
 		case 3:
 			native_thread = 1;
 			break;
 		default:
 			PR_ASSERT(!"Invalid scope");
 			break;
 	}
 	if (native_thread) {
-#ifdef _PR_PTHREADS
+#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
 		pthread_t tid;
 		printf("creating pthread\n");
 		if (!pthread_create(&tid, NULL, start, arg))
 			return((PRThread *) tid);
 		else
 			return (NULL);
 #else
 		HANDLE thandle;
--- a/pr/tests/timetest.c
+++ b/pr/tests/timetest.c
@@ -44,17 +44,17 @@ int failed_already=0;
 PRBool debug_mode = PR_FALSE;
 
 static char *dayOfWeek[] =
 	{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "???" };
 static char *month[] =
 	{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
 	  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???" };
 
-static void printExplodedTime(const PRExplodedTime *et) {
+static void PrintExplodedTime(const PRExplodedTime *et) {
     PRInt32 totalOffset;
     PRInt32 hourOffset, minOffset;
     const char *sign;
 
     /* Print day of the week, month, day, hour, minute, and second */
     if (debug_mode) printf("%s %s %ld %02ld:%02ld:%02ld ",
 	    dayOfWeek[et->tm_wday], month[et->tm_month], et->tm_mday,
 	    et->tm_hour, et->tm_min, et->tm_sec);
@@ -74,17 +74,17 @@ static void printExplodedTime(const PREx
         if (debug_mode) 
             printf("%s%02ld%02ld ", sign, hourOffset, minOffset);
     }
 
     /* Print year */
     if (debug_mode) printf("%hd", et->tm_year);
 }
 
-static int explodedTimeIsEqual(const PRExplodedTime *et1,
+static int ExplodedTimeIsEqual(const PRExplodedTime *et1,
 	const PRExplodedTime *et2)
 {
     if (et1->tm_usec == et2->tm_usec &&
 	    et1->tm_sec == et2->tm_sec &&
 	    et1->tm_min == et2->tm_min &&
 	    et1->tm_hour == et2->tm_hour &&
 	    et1->tm_mday == et2->tm_mday &&
 	    et1->tm_month == et2->tm_month &&
@@ -195,20 +195,20 @@ int main(int argc, char** argv)
     /* Testing zero PRTime (the epoch) */
     {
 	PRTime t;
 	PRExplodedTime et;
 
 	LL_I2L(t, 0);
 	if (debug_mode) printf("The NSPR epoch is:\n");
         PR_ExplodeTime(t, PR_LocalTimeParameters, &et);
-	printExplodedTime(&et);
+	PrintExplodedTime(&et);
 	if (debug_mode) printf("\n");
 	PR_ExplodeTime(t, PR_GMTParameters, &et);
-	printExplodedTime(&et);
+	PrintExplodedTime(&et);
 	if (debug_mode) printf("\n\n");
 	testParseTimeString(t);
     }
 
     /*
      *************************************************************
      **
      **  Testing PR_Now(), PR_ExplodeTime, and PR_ImplodeTime
@@ -235,31 +235,31 @@ int main(int argc, char** argv)
 
         PR_ExplodeTime(t1, PR_GMTParameters, &et);
         if (et.tm_params.tp_gmt_offset || et.tm_params.tp_dst_offset) {
 	    if (debug_mode) printf("ERROR: UTC has nonzero gmt or dst offset.\n");
 		else failed_already=1;
 	    return 1;
         }
         if (debug_mode) printf("Current UTC is ");
-	printExplodedTime(&et);
+	PrintExplodedTime(&et);
 	if (debug_mode) printf("\n");
 
         t2 = PR_ImplodeTime(&et);
         if (LL_NE(t1, t2)) {
 	    if (debug_mode) printf("ERROR: Explode and implode are NOT inverse.\n");
 		else printf("FAIL\n");
 	    return 1;
         }
 
         /* Next, try converting to local (US Pacific) time */
 
         PR_ExplodeTime(t1, PR_LocalTimeParameters, &et);
         if (debug_mode) printf("Current local time is ");
-	printExplodedTime(&et);
+	PrintExplodedTime(&et);
 	if (debug_mode) printf("\n");
 	if (debug_mode) printf("GMT offset is %ld, DST offset is %ld\n",
 		et.tm_params.tp_gmt_offset, et.tm_params.tp_dst_offset);
         t2 = PR_ImplodeTime(&et);
         if (LL_NE(t1, t2)) {
 	    if (debug_mode) printf("ERROR: Explode and implode are NOT inverse.\n");
 	    return 1;
 	}
@@ -321,17 +321,17 @@ int main(int argc, char** argv)
         et.tm_params.tp_gmt_offset = -8 * 3600;
 	et.tm_params.tp_dst_offset = 0;
 
 	PR_NormalizeTime(&et, PR_USPacificTimeParameters);
 
 	if (debug_mode) {
 	    printf("Thu Jun 12, 1997 23:00:00 PST is ");
 	}
-	printExplodedTime(&et);
+	PrintExplodedTime(&et);
 	if (debug_mode) printf(".\n");
 	if (et.tm_wday == 5) {
 	    if (debug_mode) printf("PASS\n");
         } else {
             if (debug_mode) printf("ERROR: It should be Friday\n");
 			else failed_already=1;
 	    return 1;
 	}
@@ -348,17 +348,17 @@ int main(int argc, char** argv)
         et.tm_params.tp_gmt_offset = -8 * 3600;
 	et.tm_params.tp_dst_offset = 3600;
 
 	PR_NormalizeTime(&et, PR_USPacificTimeParameters);
 
 	if (debug_mode) {
 	    printf("Fri Feb 14, 1997 00:00:00 PDT is ");
 	}
-	printExplodedTime(&et);
+	PrintExplodedTime(&et);
 	if (debug_mode) printf(".\n");
 	if (et.tm_wday == 4) {
 	    if (debug_mode) printf("PASS\n");
         } else {
             if (debug_mode) printf("ERROR: It should be Thursday\n");
 			else failed_already=1;
 	    return 1;
 	}
@@ -372,33 +372,33 @@ int main(int argc, char** argv)
         et.tm_min     = 29;
         et.tm_sec     = 23;
 	et.tm_usec    = 0;
         et.tm_params.tp_gmt_offset = -8 * 3600;  /* PDT */
 	et.tm_params.tp_dst_offset = 3600; 
 
 	PR_NormalizeTime(&et, PR_LocalTimeParameters);
         if (debug_mode) printf("Nov 7 18:29:23 PDT 1996 is ");
-	printExplodedTime(&et);
+	PrintExplodedTime(&et);
 	if (debug_mode) printf(".\n");
 	testParseTimeString(PR_ImplodeTime(&et));
 
         /* What time is Oct. 7, 1995, 18:29:23 PST? */
         et.tm_year    = 1995;
         et.tm_month   = 10 - 1;
         et.tm_mday    = 7;
         et.tm_hour    = 18;
         et.tm_min     = 29;
         et.tm_sec     = 23;
         et.tm_params.tp_gmt_offset = -8 * 3600;  /* PST */
 	et.tm_params.tp_dst_offset = 0;
 
 	PR_NormalizeTime(&et, PR_LocalTimeParameters);
         if (debug_mode) printf("Oct 7 18:29:23 PST 1995 is ");
-	printExplodedTime(&et);
+	PrintExplodedTime(&et);
 	if (debug_mode) printf(".\n");
 	testParseTimeString(PR_ImplodeTime(&et));
 
 	if (debug_mode) printf("Please examine the results\n");
     }
 
     /*
      **************************************************************
@@ -434,17 +434,17 @@ int main(int argc, char** argv)
 	secs = PR_ImplodeTime(&et1);
 	if (LL_GE_ZERO(secs)) {
 	    if (debug_mode)
 		printf("ERROR: April 4, 1917 GMT returns a nonnegative second count\n");
 		failed_already = 1;
 	    return 1;
         }
 	PR_ExplodeTime(secs, PR_LocalTimeParameters, &et2);
-	if (!explodedTimeIsEqual(&et1, &et2)) {
+	if (!ExplodedTimeIsEqual(&et1, &et2)) {
 		if (debug_mode)
 		printf("ERROR: PR_ImplodeTime and PR_ExplodeTime are not inverse for April 4, 1917 GMT\n");
 		failed_already=1;
 	    return 1;
         }
     ttt = PR_ImplodeTime(&et1);
 	testParseTimeString( ttt );
 
@@ -463,17 +463,17 @@ int main(int argc, char** argv)
 	secs = PR_ImplodeTime(&et1);
 	if (!LL_GE_ZERO(secs)) {
 	    if (debug_mode)
 			printf("ERROR: July 4, 2050 GMT returns a negative second count\n");
 		failed_already = 1;
 	    return 1;
         }
 	PR_ExplodeTime(secs, PR_LocalTimeParameters, &et2);
-	if (!explodedTimeIsEqual(&et1, &et2)) {
+	if (!ExplodedTimeIsEqual(&et1, &et2)) {
 	    if (debug_mode)
 		printf("ERROR: PR_ImplodeTime and PR_ExplodeTime are not inverse for July 4, 2050 GMT\n");
 		failed_already=1;
 	    return 1;
         }
 	testParseTimeString(PR_ImplodeTime(&et1));
 
 	if (debug_mode) printf("Test passed for July 4, 2050\n");
@@ -528,49 +528,49 @@ int main(int argc, char** argv)
 		for (min = 0; min < 60; min += 10) {
 	            LL_ADD(usecs, usecs, usecPer10Min);
 		    PR_ExplodeTime(usecs, PR_USPacificTimeParameters, &et1);
 
 		    et2 = et;
 		    et2.tm_usec += 600000000L;
 		    PR_NormalizeTime(&et2, PR_USPacificTimeParameters);
 
-		    if (!explodedTimeIsEqual(&et1, &et2)) {
+		    if (!ExplodedTimeIsEqual(&et1, &et2)) {
 		        if (debug_mode) printf("ERROR: componentwise comparison failed\n");
-			printExplodedTime(&et1);
+			PrintExplodedTime(&et1);
 			if (debug_mode) printf("\n");
-			printExplodedTime(&et2);
+			PrintExplodedTime(&et2);
 			if (debug_mode) printf("\n");
 			failed_already=1;
 		        return 1;
 		    }
 
 		    if (LL_NE(usecs, PR_ImplodeTime(&et1))) { 
                         if (debug_mode)
 					printf("ERROR: PR_ExplodeTime and PR_ImplodeTime are not inverse\n");
-			printExplodedTime(&et1);
+			PrintExplodedTime(&et1);
 			if (debug_mode) printf("\n");
 			failed_already=1;
 		        return 1;
 		    }
 		    testParseTimeString(usecs);
 
 		    if (!dstInEffect && et1.tm_params.tp_dst_offset) {
 		        dstInEffect = 1;
 		        if (debug_mode) printf("DST changeover from ");
-			printExplodedTime(&et);
+			PrintExplodedTime(&et);
 			if (debug_mode) printf(" to ");
-			printExplodedTime(&et1);
+			PrintExplodedTime(&et1);
 			if (debug_mode) printf(".\n");
                     } else if (dstInEffect && !et1.tm_params.tp_dst_offset) {
 		        dstInEffect = 0;
 			if (debug_mode) printf("DST changeover from ");
-			printExplodedTime(&et);
+			PrintExplodedTime(&et);
 			if (debug_mode) printf(" to ");
-			printExplodedTime(&et1);
+			PrintExplodedTime(&et1);
 			if (debug_mode) printf(".\n");
                     }
 
 		    et = et1;
 		}
 	    }
         }
 	if (debug_mode) printf("Test passed\n");
@@ -616,47 +616,47 @@ int main(int argc, char** argv)
 		for (min = 0; min < 60; min += 10) {
 	            LL_ADD(usecs, usecs, usecPer10Min);
 		    PR_ExplodeTime(usecs, PR_LocalTimeParameters, &et1);
 
 		    et2 = et;
 		    et2.tm_usec += 600000000L;
 		    PR_NormalizeTime(&et2, PR_LocalTimeParameters);
 
-		    if (!explodedTimeIsEqual(&et1, &et2)) {
+		    if (!ExplodedTimeIsEqual(&et1, &et2)) {
 		        if (debug_mode) printf("ERROR: componentwise comparison failed\n");
-			printExplodedTime(&et1);
+			PrintExplodedTime(&et1);
 			if (debug_mode) printf("\n");
-			printExplodedTime(&et2);
+			PrintExplodedTime(&et2);
 			if (debug_mode) printf("\n");
 		        return 1;
 		    }
 
 		    if (LL_NE(usecs, PR_ImplodeTime(&et1))) {
                         printf("ERROR: PR_ExplodeTime and PR_ImplodeTime are not inverse\n");
-			printExplodedTime(&et1);
+			PrintExplodedTime(&et1);
 			if (debug_mode) printf("\n");
 			failed_already=1;
 		        return 1;
 		    }
 		    testParseTimeString(usecs);
 
 		    if (!dstInEffect && et1.tm_params.tp_dst_offset) {
 		        dstInEffect = 1;
 		        if (debug_mode) printf("DST changeover from ");
-			printExplodedTime(&et);
+			PrintExplodedTime(&et);
 			if (debug_mode) printf(" to ");
-			printExplodedTime(&et1);
+			PrintExplodedTime(&et1);
 			if (debug_mode) printf(".\n");
                     } else if (dstInEffect && !et1.tm_params.tp_dst_offset) {
 		        dstInEffect = 0;
 			if (debug_mode) printf("DST changeover from ");
-			printExplodedTime(&et);
+			PrintExplodedTime(&et);
 			if (debug_mode) printf(" to ");
-			printExplodedTime(&et1);
+			PrintExplodedTime(&et1);
 			if (debug_mode) printf(".\n");
                     }
 
 		    et = et1;
 		}
 	    }
         }
 	if (debug_mode) printf("Test passed\n");
@@ -701,48 +701,48 @@ int main(int argc, char** argv)
 		for (min = 0; min < 60; min += 10) {
 	            LL_SUB(usecs, usecs, usecPer10Min);
 		    PR_ExplodeTime(usecs, PR_LocalTimeParameters, &et1);
 
 		    et2 = et;
 		    et2.tm_usec -= 600000000L;
 		    PR_NormalizeTime(&et2, PR_LocalTimeParameters);
 
-		    if (!explodedTimeIsEqual(&et1, &et2)) {
+		    if (!ExplodedTimeIsEqual(&et1, &et2)) {
 		        if (debug_mode) printf("ERROR: componentwise comparison failed\n");
-			printExplodedTime(&et1);
+			PrintExplodedTime(&et1);
 			if (debug_mode) printf("\n");
-			printExplodedTime(&et2);
+			PrintExplodedTime(&et2);
 			if (debug_mode) printf("\n");
 		        return 1;
 		    }
 
 		    if (LL_NE(usecs, PR_ImplodeTime(&et1))) {
                    if (debug_mode)
 					printf("ERROR: PR_ExplodeTime and PR_ImplodeTime are not inverse\n");
-			printExplodedTime(&et1);
+			PrintExplodedTime(&et1);
 			if (debug_mode) printf("\n");
 			failed_already=1;
 		        return 1;
 		    }
 		    testParseTimeString(usecs);
 
 		    if (!dstInEffect && et1.tm_params.tp_dst_offset) {
 		        dstInEffect = 1;
 		        if (debug_mode) printf("DST changeover from ");
-			printExplodedTime(&et);
+			PrintExplodedTime(&et);
 			if (debug_mode) printf(" to ");
-			printExplodedTime(&et1);
+			PrintExplodedTime(&et1);
 			if (debug_mode) printf(".\n");
                     } else if (dstInEffect && !et1.tm_params.tp_dst_offset) {
 		        dstInEffect = 0;
 			if (debug_mode) printf("DST changeover from ");
-			printExplodedTime(&et);
+			PrintExplodedTime(&et);
 			if (debug_mode) printf(" to ");
-			printExplodedTime(&et1);
+			PrintExplodedTime(&et1);
 			if (debug_mode) printf(".\n");
                     }
 
 		    et = et1;
 		}
 	    }
         }
     }
new file mode 100644
--- /dev/null
+++ b/pr/tests/y2k.c
@@ -0,0 +1,727 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL.  You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ * 
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ * 
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation.  Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
+ * Reserved.
+ */
+
+/*
+ * file: y2k.c
+ * description: Test for y2k compliance for NSPR.
+ */
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "prinit.h"
+#include "prtime.h"
+#include "prprf.h"
+#include "prlog.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef XP_MAC
+#include "prlog.h"
+#include "macstdlibextras.h"
+extern void SetupMacPrintfLog(char *logFile);
+#endif
+
+int failed_already=0;
+PRBool debug_mode = PR_FALSE;
+
+static char *dayOfWeek[] =
+	{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "???" };
+static char *month[] =
+	{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+	  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???" };
+
+PRLogModuleInfo *lm;
+
+static void PrintExplodedTime(const PRExplodedTime *et) {
+    PRInt32 totalOffset;
+    PRInt32 hourOffset, minOffset;
+    const char *sign;
+
+    /* Print day of the week, month, day, hour, minute, and second */
+    printf("%s %s %2ld %02ld:%02ld:%02ld ",
+	    dayOfWeek[et->tm_wday], month[et->tm_month], et->tm_mday,
+	    et->tm_hour, et->tm_min, et->tm_sec);
+
+    /* Print year */
+    printf("%hd ", et->tm_year);
+
+    /* Print time zone */
+    totalOffset = et->tm_params.tp_gmt_offset + et->tm_params.tp_dst_offset;
+    if (totalOffset == 0) {
+	printf("UTC ");
+    } else {
+        sign = "+";
+        if (totalOffset < 0) {
+	    totalOffset = -totalOffset;
+	    sign = "-";
+        }
+        hourOffset = totalOffset / 3600;
+        minOffset = (totalOffset % 3600) / 60;
+        printf("%s%02ld%02ld ", sign, hourOffset, minOffset);
+    }
+#ifdef PRINT_DETAILS
+	printf("{%d, %d, %d, %d, %d, %d, %d, %d, %d, { %d, %d}}\n",et->tm_usec,
+											et->tm_sec,
+											et->tm_min,
+											et->tm_hour,
+											et->tm_mday,
+											et->tm_month,
+											et->tm_year,
+											et->tm_wday,
+											et->tm_yday,
+											et->tm_params.tp_gmt_offset,
+											et->tm_params.tp_dst_offset);
+#endif
+}
+
+static int ExplodedTimeIsEqual(const PRExplodedTime *et1,
+	const PRExplodedTime *et2)
+{
+    if (et1->tm_usec == et2->tm_usec &&
+	    et1->tm_sec == et2->tm_sec &&
+	    et1->tm_min == et2->tm_min &&
+	    et1->tm_hour == et2->tm_hour &&
+	    et1->tm_mday == et2->tm_mday &&
+	    et1->tm_month == et2->tm_month &&
+	    et1->tm_year == et2->tm_year &&
+	    et1->tm_wday == et2->tm_wday &&
+	    et1->tm_yday == et2->tm_yday &&
+	    et1->tm_params.tp_gmt_offset == et2->tm_params.tp_gmt_offset &&
+	    et1->tm_params.tp_dst_offset == et2->tm_params.tp_dst_offset) {
+        return 1;
+    } else {
+	return 0;
+    }
+}
+
+/*
+ * TEST 1: TestExplodeImplodeTime
+ * Description:
+ * For each given timestamp T (a PRTime value), call PR_ExplodeTime
+ * with GMT, US Pacific, and local time parameters.  Compare the
+ * resulting calendar (exploded) time values with the expected
+ * values.
+ *
+ * Note: the expected local time values depend on the local time
+ * zone.  The local time values stored in this test are for the US
+ * Pacific Time Zone.  If you are running this test in a different
+ * time zone, you need to modify the values in the localt array.
+ * An example is provided below.
+ *
+ * Call PR_ImplodeTime for each of the exploded values and compare
+ * the resulting PRTime values with the original input.
+ * 
+ * This test is run for the values of time T corresponding to the
+ * following dates:
+ * - 12/31/99 - before 2000 
+ * - 01/01/00 - after 2000 
+ * - Leap year - Feb 29, 2000 
+ * - March 1st, 2001 (after 1 year) 
+ * - March 1st, 2005 (after second leap year) 
+ * - 09/09/99 (used by some programs as an end of file marker)
+ *
+ * Call PR_Now, convert to calendar time using PR_ExplodeTime and
+ * manually check the result for correctness. The time should match
+ * the system clock.
+ *
+ * Tested functions: PR_Now, PR_ExplodeTime, PR_ImplodeTime,
+ * PR_LocalTimeParameters, PR_GMTParameters. 
+ */
+
+static PRTime prt[] = {
+    LL_INIT(220405, 2133125120),  /* 946634400000000 */
+    LL_INIT(220425, 2633779200),  /* 946720800000000 */
+    LL_INIT(221612, 2107598848),  /* 951818400000000 */
+    LL_INIT(228975, 663398400),  /* 983440800000000 */
+    LL_INIT(258365, 1974568960),  /* 1109671200000000 */
+    LL_INIT(218132, 1393788928)  /* 936871200000000 */
+};
+
+static PRExplodedTime gmt[] = {
+    { 0, 0, 0, 10, 31, 11, 1999, 5, 364, {0, 0}}, /* 1999/12/31 10:00:00 GMT */
+    { 0, 0, 0, 10, 1, 0, 2000, 6, 0, {0, 0}}, /* 2000/01/01 10:00:00 GMT */
+    { 0, 0, 0, 10, 29, 1, 2000, 2, 59, {0, 0}}, /* 2000/02/29 10:00:00 GMT */
+    { 0, 0, 0, 10, 1, 2, 2001, 4, 59, {0, 0}}, /* 2001/3/1 10:00:00 GMT */
+    { 0, 0, 0, 10, 1, 2, 2005, 2, 59, {0, 0}}, /* 2005/3/1 10:00:00 GMT */
+    { 0, 0, 0, 10, 9, 8, 1999, 4, 251, {0, 0}}  /* 1999/9/9 10:00:00 GMT */
+};
+
+static PRExplodedTime uspt[] = {
+{ 0, 0, 0, 2, 31, 11, 1999, 5, 364, {-28800, 0}}, /* 1999/12/31 2:00:00 PST */
+{ 0, 0, 0, 2, 1, 0, 2000, 6, 0, {-28800, 0}}, /* 2000/01/01 2:00:00 PST */
+{ 0, 0, 0, 2, 29, 1, 2000, 2, 59, {-28800, 0}}, /* 2000/02/29 2:00:00 PST */
+{ 0, 0, 0, 2, 1, 2, 2001, 4, 59, {-28800, 0}}, /* 2001/3/1 2:00:00 PST */
+{ 0, 0, 0, 2, 1, 2, 2005, 2, 59, {-28800, 0}}, /* 2005/3/1 2:00:00 PST */
+{ 0, 0, 0, 3, 9, 8, 1999, 4, 251, {-28800, 3600}}  /* 1999/9/9 3:00:00 PDT */
+};
+
+/*
+ * This test assumes that we are in US Pacific Time Zone.
+ * If you are running this test in a different time zone,
+ * you need to modify the localt array and fill in the
+ * expected results.  The localt array for US Eastern Time
+ * Zone is provided as an example.
+ */
+static PRExplodedTime localt[] = {
+{ 0, 0, 0, 2, 31, 11, 1999, 5, 364, {-28800, 0}}, /* 1999/12/31 2:00:00 PST */
+{ 0, 0, 0, 2, 1, 0, 2000, 6, 0, {-28800, 0}}, /* 2000/01/01 2:00:00 PST */
+{ 0, 0, 0, 2, 29, 1, 2000, 2, 59, {-28800, 0}}, /* 2000/02/29 2:00:00 PST */
+{ 0, 0, 0, 2, 1, 2, 2001, 4, 59, {-28800, 0}}, /* 2001/3/1 2:00:00 PST */
+{ 0, 0, 0, 2, 1, 2, 2005, 2, 59, {-28800, 0}}, /* 2005/3/1 2:00:00 PST */
+{ 0, 0, 0, 3, 9, 8, 1999, 4, 251, {-28800, 3600}}  /* 1999/9/9 3:00:00 PDT */
+};
+
+#ifdef US_EASTERN_TIME
+static PRExplodedTime localt[] = {
+{ 0, 0, 0, 5, 31, 11, 1999, 5, 364, {-18000, 0}}, /* 1999/12/31 2:00:00 EST */
+{ 0, 0, 0, 5, 1, 0, 2000, 6, 0, {-18000, 0}}, /* 2000/01/01 2:00:00 EST */
+{ 0, 0, 0, 5, 29, 1, 2000, 2, 59, {-18000, 0}}, /* 2000/02/29 2:00:00 EST */
+{ 0, 0, 0, 5, 1, 2, 2001, 4, 59, {-18000, 0}}, /* 2001/3/1 2:00:00 EST */
+{ 0, 0, 0, 5, 1, 2, 2005, 2, 59, {-18000, 0}}, /* 2005/3/1 2:00:00 EST */
+{ 0, 0, 0, 6, 9, 8, 1999, 4, 251, {-18000, 3600}}  /* 1999/9/9 3:00:00 EDT */
+};
+#endif
+
+static PRStatus TestExplodeImplodeTime(void)
+{
+    PRTime prt_tmp;
+    PRTime now;
+    int idx;
+    int array_size = sizeof(prt) / sizeof(PRTime);
+    PRExplodedTime et_tmp;
+    char buf[1024];
+
+    for (idx = 0; idx < array_size; idx++) {
+        PR_snprintf(buf, sizeof(buf), "%lld", prt[idx]);
+        if (debug_mode) printf("Time stamp %s\n", buf); 
+        PR_ExplodeTime(prt[idx], PR_GMTParameters, &et_tmp);
+        if (!ExplodedTimeIsEqual(&et_tmp, &gmt[idx])) {
+            fprintf(stderr, "GMT not equal\n");
+            exit(1);
+        }
+        prt_tmp = PR_ImplodeTime(&et_tmp);
+        if (LL_NE(prt_tmp, prt[idx])) {
+            fprintf(stderr, "PRTime not equal\n");
+            exit(1);
+        }
+        if (debug_mode) {
+            printf("GMT: ");
+            PrintExplodedTime(&et_tmp);
+            printf("\n");
+        }
+
+        PR_ExplodeTime(prt[idx], PR_USPacificTimeParameters, &et_tmp);
+        if (!ExplodedTimeIsEqual(&et_tmp, &uspt[idx])) {
+            fprintf(stderr, "US Pacific Time not equal\n");
+            exit(1);
+        }
+        prt_tmp = PR_ImplodeTime(&et_tmp);
+        if (LL_NE(prt_tmp, prt[idx])) {
+            fprintf(stderr, "PRTime not equal\n");
+            exit(1);
+        }
+        if (debug_mode) {
+            printf("US Pacific Time: ");
+            PrintExplodedTime(&et_tmp);
+            printf("\n");
+        }
+
+        PR_ExplodeTime(prt[idx], PR_LocalTimeParameters, &et_tmp);
+        if (!ExplodedTimeIsEqual(&et_tmp, &localt[idx])) {
+            fprintf(stderr, "not equal\n");
+            exit(1);
+        }
+        prt_tmp = PR_ImplodeTime(&et_tmp);
+        if (LL_NE(prt_tmp, prt[idx])) {
+            fprintf(stderr, "not equal\n");
+            exit(1);
+        }
+        if (debug_mode) {
+            printf("Local time:");
+            PrintExplodedTime(&et_tmp);
+            printf("\n\n");
+        }
+    }
+
+    now = PR_Now();
+    PR_ExplodeTime(now, PR_GMTParameters, &et_tmp);
+    printf("Current GMT is ");
+    PrintExplodedTime(&et_tmp);
+    printf("\n");
+    prt_tmp = PR_ImplodeTime(&et_tmp);
+    if (LL_NE(prt_tmp, now)) {
+        fprintf(stderr, "not equal\n");
+        exit(1);
+    }
+    PR_ExplodeTime(now, PR_USPacificTimeParameters, &et_tmp);
+    printf("Current US Pacific Time is ");
+    PrintExplodedTime(&et_tmp);
+    printf("\n");
+    prt_tmp = PR_ImplodeTime(&et_tmp);
+    if (LL_NE(prt_tmp, now)) {
+        fprintf(stderr, "not equal\n");
+        exit(1);
+    }
+    PR_ExplodeTime(now, PR_LocalTimeParameters, &et_tmp);
+    printf("Current local time is ");
+    PrintExplodedTime(&et_tmp);
+    printf("\n");
+    prt_tmp = PR_ImplodeTime(&et_tmp);
+    if (LL_NE(prt_tmp, now)) {
+        fprintf(stderr, "not equal\n");
+        exit(1);
+    }
+    printf("Please verify the results\n\n");
+
+    if (debug_mode) printf("Test 1 passed\n");
+    return PR_SUCCESS;
+}
+/* End of Test 1: TestExplodeImplodeTime */
+
+/*
+ * Test 2: Normalize Time
+ */
+
+/*
+ * time increment for addition to PRExplodeTime
+ */
+typedef struct time_increment {
+	PRInt32 ti_usec;
+	PRInt32 ti_sec;
+	PRInt32 ti_min;
+	PRInt32 ti_hour;
+} time_increment_t;
+
+/*
+ * Data for testing PR_Normalize
+ *		Add the increment to base_time, normalize it to GMT and US Pacific
+ *		Time zone.
+ */
+typedef struct normalize_test_data {
+    PRExplodedTime		base_time; 
+    time_increment_t  	increment;
+    PRExplodedTime		expected_gmt_time;
+    PRExplodedTime		expected_uspt_time;
+} normalize_test_data_t;
+
+
+/*
+ * Test data -	the base time values cover dates of interest including y2k - 1,
+ *				y2k + 1, y2k leap year, y2k leap date + 1year,
+ *				y2k leap date + 4 years
+ */
+normalize_test_data_t normalize_test_array[] = {
+  /*usec sec min hour  mday  mo  year  wday yday {gmtoff, dstoff }*/
+
+	/* Fri 12/31/1999 19:32:48 PST */
+	{{0, 48, 32, 19, 31, 11, 1999, 5, 364, { -28800, 0}},
+    {0, 0, 30, 20},
+	{0, 48, 2, 0, 2, 0, 2000, 0, 1, { 0, 0}},	/*Sun Jan 2 00:02:48 UTC 2000*/
+	{0, 48, 2, 16, 1, 0, 2000, 6, 0, { -28800, 0}},/* Sat Jan 1 16:02:48
+														PST 2000*/
+	},
+	/* Fri 99-12-31 23:59:02 GMT */
+	{{0, 2, 59, 23, 31, 11, 1999, 5, 364, { 0, 0}},
+    {0, 0, 45, 0},
+	{0, 2, 44, 0, 1, 0, 2000, 6, 0, { 0, 0}},/* Sat Jan 1 00:44:02 UTC 2000*/
+	{0, 2, 44, 16, 31, 11, 1999, 5, 364, { -28800, 0}}/*Fri Dec 31 16:44:02
+														PST 1999*/
+	},
+	/* 99-12-25 12:00:00 GMT */
+	{{0, 0, 0, 12, 25, 11, 1999, 6, 358, { 0, 0}},
+    {0, 0, 0, 364 * 24},
+	{0, 0, 0, 12, 23, 11, 2000, 6, 357, { 0, 0}},/*Sat Dec 23 12:00:00
+													2000 UTC*/
+	{0, 0, 0, 4, 23, 11, 2000, 6, 357, { -28800, 0}}/*Sat Dec 23 04:00:00
+														2000 -0800*/
+	},
+	/* 00-01-1 00:00:00 PST */
+    {{0, 0, 0, 0, 1, 0, 2000, 6, 0, { -28800, 0}},
+    {0, 0, 0, 48},
+    {0, 0, 0, 8, 3, 0, 2000, 1, 2, { 0, 0}},/*Mon Jan  3 08:00:00 2000 UTC*/
+    {0, 0, 0, 0, 3, 0, 2000, 1, 2, { -28800, 0}}/*Mon Jan  3 00:00:00 2000
+																-0800*/
+	},
+	/* 00-01-10 12:00:00 PST */
+    {{0, 0, 0, 12, 10, 0, 2000, 1, 9, { -28800, 0}},
+    {0, 0, 0, 364 * 5 * 24},
+    {0, 0, 0, 20, 3, 0, 2005, 1, 2, { 0, 0}},/*Mon Jan  3 20:00:00 2005 UTC */
+    {0, 0, 0, 12, 3, 0, 2005, 1, 2, { -28800, 0}}/*Mon Jan  3 12:00:00
+														2005 -0800*/
+	},
+	/* 00-02-28 15:39 GMT */
+	{{0, 0, 39, 15, 28, 1, 2000, 1, 58, { 0, 0}},
+    {0,  0, 0, 24},
+	{0, 0, 39, 15, 29, 1, 2000, 2, 59, { 0, 0}}, /*Tue Feb 29 15:39:00 2000
+														UTC*/
+	{0, 0, 39, 7, 29, 1, 2000, 2, 59, { -28800, 0}}/*Tue Feb 29 07:39:00
+														2000 -0800*/
+	},
+	/* 01-03-01 12:00 PST */
+    {{0, 0, 0, 12, 3, 0, 2001, 3, 2, { -28800, 0}},/*Wed Jan 3 12:00:00
+													-0800 2001*/
+    {0, 30, 30,45},
+    {0, 30, 30, 17, 5, 0, 2001, 5, 4, { 0, 0}}, /*Fri Jan  5 17:30:30 2001
+													UTC*/
+    {0, 30, 30, 9, 5, 0, 2001, 5, 4, { -28800, 0}} /*Fri Jan  5 09:30:30
+														2001 -0800*/
+	},
+	/* 2004-04-26 12:00 GMT */
+	{{0, 0, 0, 20, 3, 0, 2001, 3, 2, { 0, 0}},
+    {0, 0, 30,0},
+	{0, 0, 30, 20, 3, 0, 2001, 3, 2, { 0, 0}},/*Wed Jan  3 20:30:00 2001 UTC*/ 
+    {0, 0, 30, 12, 3, 0, 2001, 3, 2, { -28800, 0}}/*Wed Jan  3 12:30:00
+														2001 -0800*/
+	},
+	/* 99-09-09 00:00 GMT */
+	{{0, 0, 0, 0, 9, 8, 1999, 4, 251, { 0, 0}},
+    {0, 0, 0, 12},
+    {0, 0, 0, 12, 9, 8, 1999, 4, 251, { 0, 0}},/*Thu Sep  9 12:00:00 1999 UTC*/
+    {0, 0, 0, 5, 9, 8, 1999, 4, 251, { -28800, 3600}}/*Thu Sep  9 05:00:00
+														1999 -0700*/
+	}
+};
+
+void add_time_increment(PRExplodedTime *et1, time_increment_t *it)
+{
+	et1->tm_usec += it->ti_usec;
+	et1->tm_sec	+= it->ti_sec;
+	et1->tm_min += it->ti_min;
+	et1->tm_hour += it->ti_hour;
+}
+
+/*
+** TestNormalizeTime() -- Test PR_NormalizeTime()
+**		For each data item, add the time increment to the base_time and then
+**		normalize it for GMT and local time zones. This test assumes that
+**		the local time zone is the Pacific Time Zone. The normalized values
+**		should match the expected values in the data item.
+**
+*/
+PRStatus TestNormalizeTime(void)
+{
+int idx, count;
+normalize_test_data_t *itemp;
+time_increment_t *itp;
+
+	count = sizeof(normalize_test_array)/sizeof(normalize_test_array[0]);
+	for (idx = 0; idx < count; idx++) {
+		itemp = &normalize_test_array[idx];
+		if (debug_mode) {
+			printf("%2d. %15s",idx +1,"Base time: ");
+			PrintExplodedTime(&itemp->base_time);
+			printf("\n");
+		}
+		itp = &itemp->increment;
+		if (debug_mode) {
+			printf("%20s %2d hrs %2d min %3d sec\n","Add",itp->ti_hour,
+												itp->ti_min, itp->ti_sec);
+		}
+		add_time_increment(&itemp->base_time, &itemp->increment);
+		PR_NormalizeTime(&itemp->base_time, PR_LocalTimeParameters);
+		if (debug_mode) {
+			printf("%19s","PST time: ");
+			PrintExplodedTime(&itemp->base_time);
+			printf("\n");
+		}
+		if (!ExplodedTimeIsEqual(&itemp->base_time,
+									&itemp->expected_uspt_time)) {
+			printf("PR_NormalizeTime failed\n");
+			if (debug_mode)
+				PrintExplodedTime(&itemp->expected_uspt_time);
+			return PR_FAILURE;
+		}
+		PR_NormalizeTime(&itemp->base_time, PR_GMTParameters);
+		if (debug_mode) {
+			printf("%19s","GMT time: ");
+			PrintExplodedTime(&itemp->base_time);
+			printf("\n");
+		}
+
+		if (!ExplodedTimeIsEqual(&itemp->base_time,
+									&itemp->expected_gmt_time)) {
+			printf("PR_NormalizeTime failed\n");
+			return PR_FAILURE;
+		}
+	}
+	return PR_SUCCESS;
+}
+
+
+/*
+** ParseTest. Structure defining a string time and a matching exploded time
+**
+*/
+typedef struct ParseTest
+{
+    char            *sDate;     /* string to be converted using PR_ParseTimeString() */
+    PRExplodedTime  et;         /* expected result of the conversion */
+} ParseTest;
+
+static ParseTest parseArray[] = 
+{
+    /*                                  |<----- expected result ------------------------------------------->| */
+    /* "string to test"                   usec     sec min hour   day  mo  year  wday julian {gmtoff, dstoff }*/
+    { "1 Jan 1970 00:00:00",            { 000000,  00, 00, 00,     1,   0, 1970, 4,     0,   {-28800, 0 }}},
+    { "1-Jan-1970 00:00:00",            { 000000,  00, 00, 00,     1,   0, 1970, 4,     0,   {-28800, 0 }}},
+    { "01-Jan-1970 00:00:00",           { 000000,  00, 00, 00,     1,   0, 1970, 4,     0,   {-28800, 0 }}},
+    { "January 1, 1970",                { 000000,  00, 00, 00,     1,   0, 1970, 4,     0,   {-28800, 0 }}},
+    { "January 1, 1970 00:00",          { 000000,  00, 00, 00,     1,   0, 1970, 4,     0,   {-28800, 0 }}},
+    { "January 01, 1970 00:00",         { 000000,  00, 00, 00,     1,   0, 1970, 4,     0,   {-28800, 0 }}},
+    { "January 01 1970 00:00",          { 000000,  00, 00, 00,     1,   0, 1970, 4,     0,   {-28800, 0 }}},
+    { "January 01 1970 00:00:00",       { 000000,  00, 00, 00,     1,   0, 1970, 4,     0,   {-28800, 0 }}},
+    { "01-01-1970",                     { 000000,  00, 00, 00,     1,   0, 1970, 4,     0,   {-28800, 0 }}},
+    { "01/01/1970",                     { 000000,  00, 00, 00,     1,   0, 1970, 4,     0,   {-28800, 0 }}},
+    { "01/01/70",                       { 000000,  00, 00, 00,     1,   0, 1970, 4,     0,   {-28800, 0 }}},
+    { "01/01/70 00:00:00",              { 000000,  00, 00, 00,     1,   0, 1970, 4,     0,   {-28800, 0 }}},
+    { "70/01/01 00:00:00",              { 000000,  00, 00, 00,     1,   0, 1970, 4,     0,   {-28800, 0 }}},
+    { "70/1/1 00:00:",                  { 000000,  00, 00, 00,     1,   0, 1970, 4,     0,   {-28800, 0 }}},
+    { "00:00 Thursday, January 1, 1970",{ 000000,  00, 00, 00,     1,   0, 1970, 4,     0,   {-28800, 0 }}},
+    { "1-Jan-70 00:00:00",              { 000000,  00, 00, 00,     1,   0, 1970, 4,     0,   {-28800, 0 }}},
+
+    /* 31-Dec-1969 */
+    { "31 Dec 1969 00:00:00",           { 000000,  00, 00, 00,    31,  11, 1969, 3,   364,   {-28800, 0 }}},
+    { "12/31/69    00:00:00",           { 000000,  00, 00, 00,    31,  11, 2069, 2,   364,   {-28800, 0 }}},
+    { "12/31/1969  00:00:00",           { 000000,  00, 00, 00,    31,  11, 1969, 3,   364,   {-28800, 0 }}},
+    { "12-31-69    00:00:00",           { 000000,  00, 00, 00,    31,  11, 2069, 2,   364,   {-28800, 0 }}},
+    { "12-31-1969  00:00:00",           { 000000,  00, 00, 00,    31,  11, 1969, 3,   364,   {-28800, 0 }}},
+
+    /* 31-Dec-1999 */
+    { "31 Dec 1999 00:00:00",           { 000000,  00, 00, 00,    31,  11, 1999, 5,   364,   {-28800, 0 }}},
+    { "12/31/99    00:00:00",           { 000000,  00, 00, 00,    31,  11, 1999, 5,   364,   {-28800, 0 }}},
+    { "12/31/1999  00:00:00",           { 000000,  00, 00, 00,    31,  11, 1999, 5,   364,   {-28800, 0 }}},
+    { "12-31-99    00:00:00",           { 000000,  00, 00, 00,    31,  11, 1999, 5,   364,   {-28800, 0 }}},
+    { "12-31-1999  00:00:00",           { 000000,  00, 00, 00,    31,  11, 1999, 5,   364,   {-28800, 0 }}},
+
+    /* 01-Jan-2000 */
+    { "01 Jan 2000 00:00:00",           { 000000,  00, 00, 00,     1,   0, 2000, 6,     0,   {-28800, 0 }}},
+    { "1/1/00      00:00:00",           { 000000,  00, 00, 00,     1,   0, 2000, 6,     0,   {-28800, 0 }}},
+    { "1/1/2000    00:00:00",           { 000000,  00, 00, 00,     1,   0, 2000, 6,     0,   {-28800, 0 }}},
+    { "1-1-00      00:00:00",           { 000000,  00, 00, 00,     1,   0, 2000, 6,     0,   {-28800, 0 }}},
+    { "1-1-2000    00:00:00",           { 000000,  00, 00, 00,     1,   0, 2000, 6,     0,   {-28800, 0 }}},
+    { "01-01-00    00:00:00",           { 000000,  00, 00, 00,     1,   0, 2000, 6,     0,   {-28800, 0 }}},
+    { "01-01-2000  00:00:00",           { 000000,  00, 00, 00,     1,   0, 2000, 6,     0,   {-28800, 0 }}},
+
+    /* 29-Feb-2000 */
+    { "29 Feb 2000 00:00:00",           { 000000,  00, 00, 00,    29,   1, 2000, 2,    59,   {-28800, 0 }}},
+    { "2/29/00     00:00:00",           { 000000,  00, 00, 00,    29,   1, 2000, 2,    59,   {-28800, 0 }}},
+    { "2/29/2000   00:00:00",           { 000000,  00, 00, 00,    29,   1, 2000, 2,    59,   {-28800, 0 }}},
+    { "2-29-00     00:00:00",           { 000000,  00, 00, 00,    29,   1, 2000, 2,    59,   {-28800, 0 }}},
+    { "2-29-2000   00:00:00",           { 000000,  00, 00, 00,    29,   1, 2000, 2,    59,   {-28800, 0 }}},
+    { "02-29-00    00:00:00",           { 000000,  00, 00, 00,    29,   1, 2000, 2,    59,   {-28800, 0 }}},
+    { "02-29-2000  00:00:00",           { 000000,  00, 00, 00,    29,   1, 2000, 2,    59,   {-28800, 0 }}},
+
+    /* 01-Mar-2000 */
+    { "01 Mar 2000 00:00:00",           { 000000,  00, 00, 00,     1,   2, 2000, 3,    60,   {-28800, 0 }}},
+    { "3/1/00      00:00:00",           { 000000,  00, 00, 00,     1,   2, 2000, 3,    60,   {-28800, 0 }}},
+    { "3/1/2000    00:00:00",           { 000000,  00, 00, 00,     1,   2, 2000, 3,    60,   {-28800, 0 }}},
+    { "3-1-00      00:00:00",           { 000000,  00, 00, 00,     1,   2, 2000, 3,    60,   {-28800, 0 }}},
+    { "03-01-00    00:00:00",           { 000000,  00, 00, 00,     1,   2, 2000, 3,    60,   {-28800, 0 }}},
+    { "03-01-2000  00:00:00",           { 000000,  00, 00, 00,     1,   2, 2000, 3,    60,   {-28800, 0 }}},
+
+    /* 01-Mar-2001 */
+    { "01 Mar 2001 00:00:00",           { 000000,  00, 00, 00,     1,   2, 2001, 4,    59,   {-28800, 0 }}},
+    { "3/1/01      00:00:00",           { 000000,  00, 00, 00,     1,   2, 2001, 4,    59,   {-28800, 0 }}},
+    { "3/1/2001    00:00:00",           { 000000,  00, 00, 00,     1,   2, 2001, 4,    59,   {-28800, 0 }}},
+    { "3-1-01      00:00:00",           { 000000,  00, 00, 00,     1,   2, 2001, 4,    59,   {-28800, 0 }}},
+    { "3-1-2001    00:00:00",           { 000000,  00, 00, 00,     1,   2, 2001, 4,    59,   {-28800, 0 }}},
+    { "03-01-01    00:00:00",           { 000000,  00, 00, 00,     1,   2, 2001, 4,    59,   {-28800, 0 }}},
+    { "03-01-2001  00:00:00",           { 000000,  00, 00, 00,     1,   2, 2001, 4,    59,   {-28800, 0 }}},
+
+    /* 29-Feb-2004 */
+    { "29 Feb 2004 00:00:00",           { 000000,  00, 00, 00,    29,   1, 2004, 0,    59,   {-28800, 0 }}},
+    { "2/29/04     00:00:00",           { 000000,  00, 00, 00,    29,   1, 2004, 0,    59,   {-28800, 0 }}},
+    { "2/29/2004   00:00:00",           { 000000,  00, 00, 00,    29,   1, 2004, 0,    59,   {-28800, 0 }}},
+    { "2-29-04     00:00:00",           { 000000,  00, 00, 00,    29,   1, 2004, 0,    59,   {-28800, 0 }}},
+    { "2-29-2004   00:00:00",           { 000000,  00, 00, 00,    29,   1, 2004, 0,    59,   {-28800, 0 }}},
+
+    /* 01-Mar-2004 */
+    { "01 Mar 2004 00:00:00",           { 000000,  00, 00, 00,     1,   2, 2004, 1,    60,   {-28800, 0 }}},
+    { "3/1/04      00:00:00",           { 000000,  00, 00, 00,     1,   2, 2004, 1,    60,   {-28800, 0 }}},
+    { "3/1/2004    00:00:00",           { 000000,  00, 00, 00,     1,   2, 2004, 1,    60,   {-28800, 0 }}},
+    { "3-1-04      00:00:00",           { 000000,  00, 00, 00,     1,   2, 2004, 1,    60,   {-28800, 0 }}},
+    { "3-1-2004    00:00:00",           { 000000,  00, 00, 00,     1,   2, 2004, 1,    60,   {-28800, 0 }}},
+    { "03-01-04    00:00:00",           { 000000,  00, 00, 00,     1,   2, 2004, 1,    60,   {-28800, 0 }}},
+    { "03-01-2004  00:00:00",           { 000000,  00, 00, 00,     1,   2, 2004, 1,    60,   {-28800, 0 }}},
+
+    /* 01-Mar-2005 */
+    { "01 Mar 2005 00:00:00",           { 000000,  00, 00, 00,     1,   2, 2005, 2,    59,   {-28800, 0 }}},
+    { "3/1/05      00:00:00",           { 000000,  00, 00, 00,     1,   2, 2005, 2,    59,   {-28800, 0 }}},
+    { "3/1/2005    00:00:00",           { 000000,  00, 00, 00,     1,   2, 2005, 2,    59,   {-28800, 0 }}},
+    { "3-1-05      00:00:00",           { 000000,  00, 00, 00,     1,   2, 2005, 2,    59,   {-28800, 0 }}},
+    { "3-1-2005    00:00:00",           { 000000,  00, 00, 00,     1,   2, 2005, 2,    59,   {-28800, 0 }}},
+    { "03-01-05    00:00:00",           { 000000,  00, 00, 00,     1,   2, 2005, 2,    59,   {-28800, 0 }}},
+    { "03-01-2005  00:00:00",           { 000000,  00, 00, 00,     1,   2, 2005, 2,    59,   {-28800, 0 }}},
+
+    /* 09-Sep-1999. Interesting because of its use as an eof marker? */
+    { "09 Sep 1999 00:00:00",           { 000000,  00, 00, 00,     9,   8, 1999, 4,   251,   {-28800, 3600 }}},
+    { "9/9/99      00:00:00",           { 000000,  00, 00, 00,     9,   8, 1999, 4,   251,   {-28800, 3600 }}},
+    { "9/9/1999    00:00:00",           { 000000,  00, 00, 00,     9,   8, 1999, 4,   251,   {-28800, 3600 }}},
+    { "9-9-99      00:00:00",           { 000000,  00, 00, 00,     9,   8, 1999, 4,   251,   {-28800, 3600 }}},
+    { "9-9-1999    00:00:00",           { 000000,  00, 00, 00,     9,   8, 1999, 4,   251,   {-28800, 3600 }}},
+    { "09-09-99    00:00:00",           { 000000,  00, 00, 00,     9,   8, 1999, 4,   251,   {-28800, 3600 }}},
+    { "09-09-1999  00:00:00",           { 000000,  00, 00, 00,     9,   8, 1999, 4,   251,   {-28800, 3600 }}},
+    
+    /* last element. string must be null */
+    { NULL }        
+}; /* end array of ParseTest */
+
+/*
+** TestParseTime() -- Test PR_ParseTimeString() for y2k compliance
+**
+** TestParseTime() loops thru the array parseArray. For each element in
+** the array, he calls PR_ParseTimeString() with sDate as the conversion
+** argument. The result (ct) is then converted to a PRExplodedTime structure
+** and compared with the exploded time value (parseArray[n].et) in the
+** array element; if equal, the element passes the test.
+**
+** The array parseArray[] contains entries that are interesting to the
+** y2k problem.
+**
+**
+*/
+static PRStatus TestParseTime( void )
+{
+    ParseTest       *ptp = parseArray;
+    PRTime          ct;
+    PRExplodedTime  cet;
+    char            *sp = ptp->sDate;
+    PRStatus        rc;
+    PRStatus        rv = PR_SUCCESS;
+
+    while ( sp != NULL)
+    {
+        rc = PR_ParseTimeString( sp, PR_FALSE, &ct );
+        if ( PR_FAILURE == rc )
+        {
+            PR_LOG( lm, PR_LOG_ERROR, 
+                ("TestParseTime(): PR_ParseTimeString() failed to convert: %s", sp ));
+            rv = PR_FAILURE;
+            failed_already = 1;
+        }
+        else
+        {
+            PR_ExplodeTime( ct, PR_LocalTimeParameters , &cet );
+
+            if ( !ExplodedTimeIsEqual( &cet, &ptp->et ))
+            {
+                PR_LOG( lm, PR_LOG_ERROR, 
+                    ("TestParseTime(): Exploded time compare failed: %s", sp ));
+                if ( debug_mode )
+                {
+                    PrintExplodedTime( &cet );
+                    printf("\n");
+                    PrintExplodedTime( &ptp->et );
+                    printf("\n");
+                }
+                
+                rv = PR_FAILURE;
+                failed_already = 1;
+            }
+        }
+                
+        /* point to next element in array, keep going */
+        ptp++;
+        sp = ptp->sDate;
+    } /* end while() */
+
+    return( rv );
+} /* end TestParseTime() */
+
+int main(int argc, char** argv)
+{
+	/* The command line argument: -d is used to determine if the test is being run
+	in debug mode. The regress tool requires only one line output:PASS or FAIL.
+	All of the printfs associated with this test has been handled with a if (debug_mode)
+	test.
+	Usage: test_name -d
+	*/
+	PLOptStatus os;
+	PLOptState *opt;
+    
+    PR_STDIO_INIT();
+	opt = PL_CreateOptState(argc, argv, "d");
+	while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+    {
+		if (PL_OPT_BAD == os) continue;
+        switch (opt->option)
+        {
+        case 'd':  /* debug mode */
+			debug_mode = PR_TRUE;
+            break;
+         default:
+            break;
+        }
+    }
+	PL_DestroyOptState(opt);
+
+ /* main test */
+	
+    PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+    lm = PR_NewLogModule("test");
+
+#ifdef XP_MAC
+	/* Set up the console */
+	InitializeSIOUX(true);
+	debug_mode = PR_TRUE;
+#endif
+
+    if ( PR_FAILURE == TestExplodeImplodeTime())
+    {
+        PR_LOG( lm, PR_LOG_ERROR,
+            ("TestExplodeImplodeTime() failed"));
+    }
+	printf("Test 1: Calendar Time Test passed\n");
+
+    if ( PR_FAILURE == TestNormalizeTime())
+    {
+        PR_LOG( lm, PR_LOG_ERROR,
+            ("TestNormalizeTime() failed"));
+    }
+
+	printf("Test 2: Normalize Time Test passed\n");
+
+    if ( PR_FAILURE == TestParseTime())
+    {
+        PR_LOG( lm, PR_LOG_ERROR,
+            ("TestParseTime() failed"));
+    }
+
+	printf("Test 3: Parse Time Test passed\n");
+
+#ifdef XP_MAC
+	if (1)
+	{
+		char dummyChar;
+		
+		printf("Press return to exit\n\n");
+		scanf("%c", &dummyChar);
+	}
+#endif
+
+	if (failed_already) 
+	    return 1;
+	else 
+	    return 0;
+} /* end main() y2k.c */
+