artificial changeset: close fixup head da2f481986ab for tag MANIFEST NORMANDY_BRANCH
authorcvs2hg
Thu, 21 Feb 2013 21:17:34 +0100
branchNORMANDY_BRANCH
changeset 4442 6d728d9d51a39426665efce7e1073db020134433
parent 148 cef62fc57b53c1a3a38ca8fa1dcac4706285013d (diff)
parent 149 da2f481986ab1649fe8cdc306281fb898196174d (current diff)
push idunknown
push userunknown
push dateunknown
artificial changeset: close fixup head da2f481986ab for tag MANIFEST
new file mode 100644
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,105 @@
+#! gmake
+
+#
+# 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.
+#
+
+MOD_DEPTH = .
+
+DIRS = config pr lib
+
+ifdef MOZILLA_CLIENT
+PR_CLIENT_BUILD = 1
+PR_CLIENT_BUILD_UNIX = 1
+endif
+
+include $(MOD_DEPTH)/config/rules.mk
+
+#
+# The -ll option of zip converts CR LF to LF.
+#
+ifeq ($(OS_ARCH),WINNT)
+ZIP_ASCII_OPT = -ll
+endif
+
+ifdef PR_CLIENT_BUILD
+export::
+	rm -r -f $(DIST)/../public/nspr
+ifdef PR_CLIENT_BUILD_UNIX
+	rm -f $(DIST)/lib/libnspr.a
+	rm -f $(DIST)/bin/libnspr.$(DLL_SUFFIX)
+endif
+endif
+
+release::
+	echo $(BUILD_NUMBER) > $(RELEASE_DIR)/$(BUILD_NUMBER)/version.df
+	@if test -f imports.df; then \
+	    echo "cp -f imports.df $(RELEASE_DIR)/$(BUILD_NUMBER)/imports.df"; \
+	    cp -f imports.df $(RELEASE_DIR)/$(BUILD_NUMBER)/imports.df; \
+	else \
+	    echo "echo > $(RELEASE_DIR)/$(BUILD_NUMBER)/imports.df"; \
+	    echo > $(RELEASE_DIR)/$(BUILD_NUMBER)/imports.df; \
+	fi
+	cd $(RELEASE_DIR)/$(BUILD_NUMBER)/$(OBJDIR_NAME); \
+	rm -rf META-INF; mkdir META-INF; cd META-INF; \
+	echo "Manifest-Version: 1.0" > MANIFEST.MF; \
+	echo "" >> MANIFEST.MF; \
+	cd ..; rm -f mdbinary.jar; zip -r mdbinary.jar META-INF lib; \
+	rm -rf META-INF; \
+	cd include; \
+	rm -rf META-INF; mkdir META-INF; cd META-INF; \
+	echo "Manifest-Version: 1.0" > MANIFEST.MF; \
+	echo "" >> MANIFEST.MF; \
+	cd ..; rm -f mdheader.jar; zip $(ZIP_ASCII_OPT) -r mdheader.jar *; \
+	rm -rf META-INF
+ifeq ($(OS_ARCH),WINNT)
+	@if test ! -d $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); then \
+		rm -rf $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); \
+		echo "making directory /m/dist/$(MOD_NAME)/$(BUILD_NUMBER)"; \
+		config/prmkdir.bat $(MDIST_DOS)\\$(MOD_NAME)\\$(BUILD_NUMBER); \
+	fi
+	@if test ! -d $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(OBJDIR_NAME); then \
+		rm -rf $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(OBJDIR_NAME); \
+		echo "making directory /m/dist/$(MOD_NAME)/$(BUILD_NUMBER)/$(OBJDIR_NAME)"; \
+		config/prmkdir.bat $(MDIST_DOS)\\$(MOD_NAME)\\$(BUILD_NUMBER)\\$(OBJDIR_NAME); \
+	fi
+else
+	@if test ! -d $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); then \
+		rm -rf $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); \
+		echo "making directory /m/dist/$(MOD_NAME)/$(BUILD_NUMBER)"; \
+		$(NSINSTALL) -D $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); \
+		chmod 775 $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); \
+	fi
+	@if test ! -d $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(OBJDIR_NAME); then \
+		rm -rf $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(OBJDIR_NAME); \
+		echo "making directory /m/dist/$(MOD_NAME)/$(BUILD_NUMBER)/$(OBJDIR_NAME)"; \
+		$(NSINSTALL) -D $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(OBJDIR_NAME); \
+		chmod 775 $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(OBJDIR_NAME); \
+	fi
+endif
+	cd $(RELEASE_DIR)/$(BUILD_NUMBER); \
+	cp -f version.df imports.df $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); \
+	chmod 664 $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/version.df; \
+	chmod 664 $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/imports.df; \
+	cd $(OBJDIR_NAME); \
+	cp -f mdbinary.jar $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(OBJDIR_NAME); \
+	chmod 664 $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(OBJDIR_NAME)/mdbinary.jar; \
+	cd include; \
+	cp -f mdheader.jar $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(OBJDIR_NAME); \
+	chmod 664 $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(OBJDIR_NAME)/mdheader.jar
+
+depend:
+	@echo "NSPR20 has no dependencies.  Skipped."
new file mode 100644
--- /dev/null
+++ b/config/.cvsignore
@@ -0,0 +1,2 @@
+nfspwd
+revdepth
new file mode 100644
--- /dev/null
+++ b/config/AIX.mk
@@ -0,0 +1,99 @@
+#
+# 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.
+#
+
+#
+# Config stuff for AIX.
+#
+
+include $(MOD_DEPTH)/config/UNIX.mk
+
+#
+# XXX
+# Temporary define for the Client; to be removed when binary release is used
+#
+ifdef MOZILLA_CLIENT
+CLASSIC_NSPR = 1
+endif
+
+#
+# There are three implementation strategies available on AIX:
+# pthreads, classic, and pthreads-user.  The default is pthreads.
+# 
+ifeq ($(CLASSIC_NSPR),1)
+	PTHREADS_USER =
+	USE_PTHREADS =
+	IMPL_STRATEGY = _CLASSIC
+	DEFINES += -D_PR_LOCAL_THREADS_ONLY
+else
+ifeq ($(PTHREADS_USER),1)
+	USE_PTHREADS =
+	IMPL_STRATEGY = _PTH_USER
+else
+	USE_PTHREADS = 1
+endif
+endif
+
+#
+# XXX
+# Temporary define for the Client; to be removed when binary release is used
+#
+ifdef MOZILLA_CLIENT
+IMPL_STRATEGY =
+endif
+
+ifeq ($(CLASSIC_NSPR),1)
+CC		= xlC
+CCC		= xlC
+else
+CC		= xlC_r
+CCC		= xlC_r
+endif
+
+CPU_ARCH	= rs6000
+
+RANLIB		= ranlib
+
+OS_CFLAGS 	= -qro -qroconst -DAIX -DSYSV
+ifeq ($(CC),xlC_r)
+OS_CFLAGS 	+= -qarch=com
+endif
+
+ifeq ($(OS_RELEASE),4.1)
+OS_CFLAGS	+= -DAIX4_1
+else
+DSO_LDOPTS	= -brtl -bM:SRE -bnoentry -bexpall
+MKSHLIB		= $(LD) $(DSO_LDOPTS)
+ifeq ($(OS_RELEASE),4.3)
+OS_CFLAGS	+= -DAIX4_3
+endif
+endif
+
+#
+# Special link info for constructing AIX programs. On AIX we have to
+# statically link programs that use NSPR into a single .o, rewriting the
+# calls to select to call "aix". Once that is done we then can
+# link that .o with a .o built in nspr which implements the system call.
+#
+ifneq ($(OS_RELEASE),4.1)
+AIX_LINK_OPTS	= -brtl -bnso -berok
+else
+AIX_LINK_OPTS	= -bnso -berok
+#AIX_LINK_OPTS	= -bnso -berok -brename:.select,.wrap_select -brename:.poll,.wrap_poll -bI:/usr/lib/syscalls.exp
+endif
+
+AIX_WRAP	= $(DIST)/lib/aixwrap.o
+AIX_TMP		= $(OBJDIR)/_aix_tmp.o
new file mode 100644
--- /dev/null
+++ b/config/BSD_OS.mk
@@ -0,0 +1,45 @@
+#
+# 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.
+#
+
+#
+# Config stuff for BSDI Unix for x86.
+#
+
+include $(MOD_DEPTH)/config/UNIX.mk
+
+#CC		= gcc -Wall -Wno-format
+#CCC		= g++
+CC		= shlicc2
+CCC		= shlicc2
+RANLIB		= ranlib
+
+DEFINES		+= -D_PR_LOCAL_THREADS_ONLY
+OS_CFLAGS	= -DBSDI -DHAVE_STRERROR -D__386BSD__ -DNEED_BSDREGEX -Di386
+OS_LIBS		= -lcompat -ldl
+
+ifeq ($(OS_RELEASE),2.1)
+OS_CFLAGS	+= -DBSDI_2
+endif
+
+G++INCLUDES	= -I/usr/include/g++
+
+CPU_ARCH	= x86
+
+NOSUCHFILE	= /no-such-file
+
+MKSHLIB		= $(LD) $(DSO_LDOPTS)
+DSO_LDOPTS	= -r
new file mode 100644
--- /dev/null
+++ b/config/FreeBSD.mk
@@ -0,0 +1,50 @@
+#
+# 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.
+#
+
+#
+# Config stuff for FreeBSD
+#
+
+include $(MOD_DEPTH)/config/UNIX.mk
+
+CC			= gcc
+CCC			= g++
+RANLIB			= ranlib
+
+OS_REL_CFLAGS		= -mno-486 -Di386
+CPU_ARCH		= x86
+
+OS_CFLAGS		= $(DSO_CFLAGS) $(OS_REL_CFLAGS) -ansi -Wall -pipe -DFREEBSD -DHAVE_STRERROR -DHAVE_BSD_FLOCK -D_PR_NEED_POLL
+
+ifeq ($(USE_PTHREADS),1)
+OS_LIBS			= -lc_r
+# XXX probably should define _THREAD_SAFE too.
+DEFINES			+= -D_PR_NEED_FAKE_POLL
+else
+OS_LIBS			= -lc
+DEFINES			+= -D_PR_LOCAL_THREADS_ONLY
+endif
+
+ARCH			= freebsd
+
+DSO_CFLAGS		= -fPIC
+DSO_LDOPTS		= -Bshareable
+DSO_LDFLAGS		=
+
+MKSHLIB			= $(LD) $(DSO_LDOPTS)
+
+G++INCLUDES		= -I/usr/include/g++
new file mode 100644
--- /dev/null
+++ b/config/HP-UX.mk
@@ -0,0 +1,155 @@
+#
+# 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.
+#
+
+#
+# Config stuff for HP-UX
+#
+
+include $(MOD_DEPTH)/config/UNIX.mk
+
+DLL_SUFFIX	= sl
+
+CC			= cc -Ae
+CCC			= CC
+RANLIB			= echo
+
+CPU_ARCH		= hppa
+
+OS_CFLAGS		= +ESlit $(DSO_CFLAGS) -DHPUX -D$(CPU_ARCH) -D_HPUX_SOURCE
+
+#
+# The header netdb.h on HP-UX 9 does not declare h_errno.
+# On 10.10 and 10.20, netdb.h declares h_errno only if
+# _XOPEN_SOURCE_EXTENDED is defined.  So we need to declare
+# h_errno ourselves.
+#
+ifeq ($(basename $(OS_RELEASE)),A.09)
+OS_CFLAGS		+= -D_PR_NEED_H_ERRNO
+endif
+ifeq (,$(filter-out B.10.10 B.10.20,$(OS_RELEASE)))
+OS_CFLAGS		+= -D_PR_NEED_H_ERRNO
+endif
+
+#
+# XXX
+# Temporary define for the Client; to be removed when binary release is used
+#
+ifdef MOZILLA_CLIENT
+CLASSIC_NSPR = 1
+endif
+
+#
+# On HP-UX 9, the default (and only) implementation strategy is
+# classic nspr.
+#
+# On HP-UX 10.10 and 10.20, the default implementation strategy is
+# pthreads (actually DCE threads).  Classic nspr is also available.
+#
+# On HP-UX 10.30 and 11.00, the default implementation strategy is
+# pthreads.  Classic nspr and pthreads-user are also available.
+#
+ifeq ($(basename $(OS_RELEASE)),A.09)
+OS_CFLAGS		+= -DHPUX9
+DEFAULT_IMPL_STRATEGY = _CLASSIC
+endif
+
+ifeq ($(OS_RELEASE),B.10.01)
+OS_CFLAGS		+= -DHPUX10
+DEFAULT_IMPL_STRATEGY = _CLASSIC
+endif
+
+ifeq ($(OS_RELEASE),B.10.10)
+OS_CFLAGS		+= -DHPUX10 -DHPUX10_10
+DEFAULT_IMPL_STRATEGY = _PTH
+endif
+
+ifeq ($(OS_RELEASE),B.10.20)
+OS_CFLAGS		+= -DHPUX10 -DHPUX10_20
+DEFAULT_IMPL_STRATEGY = _PTH
+endif
+
+#
+# On 10.30 and 11.00, we use the new ANSI C++ compiler aCC.
+#
+
+ifeq ($(OS_RELEASE),B.10.30)
+CCC			= /opt/aCC/bin/aCC
+OS_CFLAGS		+= +DAportable +DS1.1 -DHPUX10 -DHPUX10_30
+DEFAULT_IMPL_STRATEGY = _PTH
+endif
+
+# 11.00 is similar to 10.30.
+ifeq ($(OS_RELEASE),B.11.00)
+CCC			= /opt/aCC/bin/aCC
+OS_CFLAGS		+= +DAportable +DS1.1 -DHPUX10 -DHPUX11
+DEFAULT_IMPL_STRATEGY = _PTH
+endif
+
+ifeq ($(DEFAULT_IMPL_STRATEGY),_CLASSIC)
+CLASSIC_NSPR = 1
+endif
+
+ifeq ($(DEFAULT_IMPL_STRATEGY),_PTH)
+USE_PTHREADS = 1
+ifeq ($(CLASSIC_NSPR),1)
+USE_PTHREADS =
+IMPL_STRATEGY = _CLASSIC
+endif
+ifeq ($(PTHREADS_USER),1)
+USE_PTHREADS =
+IMPL_STRATEGY = _PTH_USER
+endif
+endif
+
+#
+# XXX
+# Temporary define for the Client; to be removed when binary release is used
+#
+ifdef MOZILLA_CLIENT
+IMPL_STRATEGY =
+endif
+
+ifeq ($(CLASSIC_NSPR),1)
+DEFINES			+= -D_PR_LOCAL_THREADS_ONLY
+endif
+
+#
+# To use the true pthread (kernel thread) library on 10.30 and
+# 11.00, we should define _POSIX_C_SOURCE to be 199506L.
+# The _REENTRANT macro is deprecated.
+#
+
+ifdef USE_PTHREADS
+ifeq (,$(filter-out B.10.10 B.10.20,$(OS_RELEASE)))
+OS_CFLAGS		+= -D_REENTRANT -D_PR_DCETHREADS
+else
+OS_CFLAGS		+= -D_POSIX_C_SOURCE=199506L
+endif
+endif
+
+ifdef PTHREADS_USER
+OS_CFLAGS		+= -D_POSIX_C_SOURCE=199506L
+endif
+
+MKSHLIB			= $(LD) $(DSO_LDOPTS)
+
+DSO_LDOPTS		= -b
+DSO_LDFLAGS		=
+# +Z generates position independent code for use in shared libraries.
+DSO_CFLAGS		= +Z
+
+HAVE_PURIFY		= 1
new file mode 100644
--- /dev/null
+++ b/config/IRIX.mk
@@ -0,0 +1,114 @@
+#
+# 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.
+#
+
+#
+# Config stuff for IRIX
+#
+
+include $(MOD_DEPTH)/config/UNIX.mk
+
+#
+# The default implementation strategy for Irix is classic nspr.
+#
+ifeq ($(USE_PTHREADS),1)
+IMPL_STRATEGY = _PTH
+endif
+
+ifdef NS_USE_GCC
+CC			= gcc
+COMPILER_TAG		= _gcc
+AS			= $(CC) -x assembler-with-cpp
+ODD_CFLAGS		= -Wall -Wno-format
+ifdef BUILD_OPT
+OPTIMIZER		= -O6
+endif
+else
+CC			= cc
+CCC         = CC
+ODD_CFLAGS		= -fullwarn -xansi
+ifdef BUILD_OPT
+
+ifeq ($(USE_N32),1)
+OPTIMIZER		= -O -OPT:Olimit=4000
+else
+OPTIMIZER		= -O -Olimit 4000
+endif
+
+endif
+
+# For 6.x machines, include this flag
+ifeq (6.,$(findstring 6.,$(OS_RELEASE)))
+ifeq ($(USE_N32),1)
+ODD_CFLAGS		+= -n32 -exceptions -woff 1209,1642,3201
+COMPILER_TAG		= _n32
+else
+ODD_CFLAGS		+=  -32 -multigot
+endif
+else
+ODD_CFLAGS		+= -xgot
+endif
+endif
+
+ODD_CFLAGS		+= -DSVR4 -DIRIX
+
+
+CPU_ARCH		= mips
+
+RANLIB			= /bin/true
+
+# For purify
+# XXX: should always define _SGI_MP_SOURCE
+NOMD_OS_CFLAGS		= $(ODD_CFLAGS) -D_SGI_MP_SOURCE
+
+ifeq ($(OS_RELEASE),5.3)
+OS_CFLAGS               += -DIRIX5_3
+endif
+
+ifeq ($(OS_RELEASE),6.2)
+OS_CFLAGS               += -DIRIX6_2
+endif
+
+ifeq ($(OS_RELEASE),6.3)
+OS_CFLAGS               += -DIRIX6_3
+endif
+
+ifndef NO_MDUPDATE
+OS_CFLAGS		+= $(NOMD_OS_CFLAGS) -MDupdate $(DEPENDENCIES)
+else
+OS_CFLAGS		+= $(NOMD_OS_CFLAGS)
+endif
+
+# catch unresolved symbols
+ifeq ($(basename $(OS_RELEASE)),6)
+SHLIB_LD_OPTS = -no_unresolved
+endif
+
+ifeq ($(USE_N32),1)
+SHLIB_LD_OPTS		+= -n32
+endif
+
+MKSHLIB			= $(LD) $(SHLIB_LD_OPTS) -rdata_shared -shared -soname $(@:$(OBJDIR)/%.so=%.so)
+
+HAVE_PURIFY		= 1
+
+DSO_LDOPTS		= -elf -shared -all
+
+ifdef DSO_BACKEND
+DSO_LDOPTS		+= -soname $(DSO_NAME)
+
+
+endif
new file mode 100644
--- /dev/null
+++ b/config/Linux.mk
@@ -0,0 +1,104 @@
+#
+# 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.
+#
+
+######################################################################
+# Config stuff for Linux (all architectures)
+######################################################################
+
+######################################################################
+# Version-independent
+######################################################################
+
+include $(MOD_DEPTH)/config/UNIX.mk
+
+#
+# The default implementation strategy for Linux is classic nspr.
+#
+ifeq ($(USE_PTHREADS),1)
+IMPL_STRATEGY = _PTH
+DEFINES			+= -D_REENTRANT
+else
+DEFINES			+= -D_PR_LOCAL_THREADS_ONLY
+endif
+
+ifeq (86,$(findstring 86,$(OS_TEST)))
+CPU_ARCH		:= x86
+else
+CPU_ARCH		:= $(OS_TEST)
+CPU_ARCH_TAG		= _$(CPU_ARCH)
+endif
+
+CC			= gcc
+CCC			= g++
+RANLIB			= ranlib
+
+OS_INCLUDES		=
+G++INCLUDES		= -I/usr/include/g++
+
+PLATFORM_FLAGS		= -ansi -Wall -pipe -DLINUX -Dlinux
+PORT_FLAGS		= -D_POSIX_SOURCE -D_BSD_SOURCE -DHAVE_STRERROR
+
+OS_CFLAGS		= $(DSO_CFLAGS) $(PLATFORM_FLAGS) $(PORT_FLAGS)
+
+######################################################################
+# Version-specific stuff
+######################################################################
+
+ifeq ($(CPU_ARCH),alpha)
+PLATFORM_FLAGS		+= -D_ALPHA_ -D__alpha
+PORT_FLAGS		+= -D_XOPEN_SOURCE
+endif
+ifeq ($(CPU_ARCH),ppc)
+PLATFORM_FLAGS		+= -DMKLINUX
+OS_INCLUDES		+= -I/usr/local/include
+endif
+ifeq ($(CPU_ARCH),x86)
+PLATFORM_FLAGS		+= -mno-486 -Di386
+PORT_FLAGS		+= -D_XOPEN_SOURCE
+endif
+ifeq ($(CPU_ARCH),m68k)
+#
+# gcc on Linux/m68k either has a bug or triggers a code-sequence
+# bug in the 68060 which causes gcc to crash.  The simplest way to
+# avoid this is to enable a minimum level of optimization.
+#
+ifndef BUILD_OPT
+OPTIMIZER		+= -O
+endif
+PLATFORM_FLAGS		+= -m68020-40
+endif
+
+#
+# Linux ppc and 2.0 have shared libraries.
+#
+
+MKSHLIB			= $(LD) $(DSO_LDOPTS) -soname $(@:$(OBJDIR)/%.so=%.so)
+ifdef BUILD_OPT
+OPTIMIZER		= -O2
+endif
+
+######################################################################
+# Overrides for defaults in config.mk (or wherever)
+######################################################################
+
+######################################################################
+# Other
+######################################################################
+
+DSO_CFLAGS		= -fPIC
+DSO_LDOPTS		= -shared
+DSO_LDFLAGS		=
new file mode 100644
--- /dev/null
+++ b/config/Makefile
@@ -0,0 +1,40 @@
+#! gmake
+
+#
+# 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.
+#
+
+MOD_DEPTH	= ..
+
+include $(MOD_DEPTH)/config/config.mk
+
+CSRCS	= nsinstall.c pathsub.c
+
+PLSRCS	= nfspwd.pl
+
+ifneq ($(OS_ARCH),WINNT)
+PROGRAM	= $(OBJDIR)/nsinstall
+TARGETS = $(PROGRAM) $(PLSRCS:.pl=)
+endif
+
+include $(MOD_DEPTH)/config/rules.mk
+
+# Redefine MAKE_OBJDIR for just this directory
+define MAKE_OBJDIR
+if test ! -d $(@D); then rm -rf $(@D); mkdir $(@D); fi
+endef
+
+export:: $(TARGETS)
new file mode 100644
--- /dev/null
+++ b/config/NCR.mk
@@ -0,0 +1,75 @@
+#
+# 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.
+#
+
+#
+# Config stuff for NCR SVR4 MP-RAS
+#
+
+include $(MOD_DEPTH)/config/UNIX.mk
+###
+NS_USE_NATIVE = 1
+
+# NS_USE_GCC = 1
+
+export PATH:=$(PATH):/opt/ncc/bin
+###
+
+RANLIB          = true
+GCC_FLAGS_EXTRA = -pipe
+
+DEFINES		+= -DSVR4 -DSYSV -DHAVE_STRERROR -DNCR -D_PR_LOCAL_THREADS_ONLY
+
+ifdef NS_USE_NATIVE
+CC              = cc
+CCC             = ncc
+OS_CFLAGS	= -Hnocopyr
+#OS_LIBS         = -L/opt/ncc/lib 
+else
+#OS_LIBS		=
+endif
+
+CCC	= g++
+
+#OS_LIBS	       += -lsocket -lnsl -ldl -lc
+
+MKSHLIB		= $(LD) $(DSO_LDOPTS)
+#DSO_LDOPTS	= -G -z defs
+DSO_LDOPTS	= -G
+
+CPU_ARCH	= x86
+ARCH		= ncr
+
+NOSUCHFILE	= /no-such-file
+
+# now take care of default GCC (rus@5/5/97)
+ 
+ifdef NS_USE_GCC
+# if gcc-settings are redefined already - don't touch it
+#
+ifeq (,$(findstring gcc, $(CC)))
+CC      = gcc
+CCC     = g++
+CXX     = g++
+COMPILER_TAG = _gcc
+# always use -fPIC - some makefiles are still broken and don't distinguish
+# situation when they build shared and static libraries
+CFLAGS  += -fPIC -Wall $(GCC_FLAGS_EXTRA)
+#OS_LIBS += -L/usr/local/lib -lstdc++ -lg++ -lgcc
+endif
+endif
+###
+
new file mode 100644
--- /dev/null
+++ b/config/NEC.mk
@@ -0,0 +1,45 @@
+#
+# 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.
+#
+
+#
+# Config stuff for NEC Mips SYSV
+#
+
+include $(MOD_DEPTH)/config/UNIX.mk
+
+CPU_ARCH		= mips
+
+ifdef NS_USE_GCC
+CC			= gcc
+CCC			= g++
+else
+CC			= $(NSDEPTH)/build/hcc -Xa -KGnum=0 -KOlimit=4000
+CCC			= g++
+endif
+
+MKSHLIB			= $(LD) $(DSO_LDOPTS)
+
+RANLIB			= /bin/true
+
+DEFINES			+= -D_PR_LOCAL_THREADS_ONLY
+OS_CFLAGS		= $(ODD_CFLAGS) -DSVR4 -D__SVR4 -DNEC -Dnec_ews -DHAVE_STRERROR
+OS_LIBS			= -lsocket -lnsl -ldl $(LDOPTIONS)
+LDOPTIONS		= -lc -L/usr/ucblib -lucb
+
+NOSUCHFILE		= /no-such-file
+
+DSO_LDOPTS		= -G
new file mode 100644
--- /dev/null
+++ b/config/NEWS-OS.mk
@@ -0,0 +1,59 @@
+#
+# 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.
+#
+
+######################################################################
+# Config stuff for Sony NEWS-OS
+######################################################################
+ 
+######################################################################
+# Version-independent
+######################################################################
+
+include $(MOD_DEPTH)/config/UNIX.mk
+
+ARCH			:= sony
+CPU_ARCH		:= mips
+ 
+CC			= cc
+CCC			= CC
+RANLIB			= /bin/true
+
+OS_INCLUDES		= -I/usr/include
+G++INCLUDES		=
+#OS_LIBS			= -lsocket -lnsl -lgen -lresolv
+
+PLATFORM_FLAGS		= -Xa -fullwarn -DSONY
+PORT_FLAGS		= -DSYSV -DSVR4 -D__svr4 -D__svr4__ -D_PR_LOCAL_THREADS_ONLY
+
+OS_CFLAGS		= $(PLATFORM_FLAGS) $(PORT_FLAGS)
+
+######################################################################
+# Version-specific stuff
+######################################################################
+
+######################################################################
+# Overrides for defaults in config.mk (or wherever)
+######################################################################
+
+######################################################################
+# Other
+######################################################################
+
+MKSHLIB			= $(LD) $(DSO_LDOPTS)
+ 
+DSO_LDOPTS		= -G
+DSO_LDFLAGS		=
new file mode 100644
--- /dev/null
+++ b/config/OS2.mk
@@ -0,0 +1,87 @@
+#
+# 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.
+#
+
+#
+# Configuration common to all (supported) versions of OS/2
+#
+# OS_CFLAGS is the command line options for the compiler when
+#   building the .DLL object files.
+# OS_EXE_CFLAGS is the command line options for the compiler
+#   when building the .EXE object files; this is for the test
+#   programs.
+# the macro OS_CFLAGS is set to OS_EXE_CFLAGS inside of the
+#   makefile for the pr/tests directory. ... Hack.
+
+
+#
+# On OS/2 we proudly support gbash...
+#
+SHELL = GBASH.EXE
+
+CC			= icc -q -DXP_OS2 -N10
+CCC			= icc -q -DXP_OS2 -DOS2=4 -N10
+LINK			= flipper ilink
+AR			= flipper ilibo //noignorecase //nologo $@
+RANLIB = echo
+BSDECHO = echo
+NSINSTALL = nsinstall
+INSTALL	= $(NSINSTALL)
+MAKE_OBJDIR = mkdir $(OBJDIR)
+IMPLIB = flipper implib -nologo -noignorecase
+FILTER = flipper cppfilt -q
+RC = rc.exe
+
+GARBAGE =
+
+XP_DEFINE = -DXP_PC
+OBJ_SUFFIX = obj
+LIB_SUFFIX = lib
+DLL_SUFFIX = dll
+
+OS_CFLAGS     = -I. -W3 -gm -gd+ -sd- -su4 -ge-
+OS_EXE_CFLAGS = -I. -W3 -gm -gd+ -sd- -su4 
+AR_EXTRA_ARGS = ,,
+
+ifdef BUILD_OPT
+OPTIMIZER	= -O+ -Oi 
+DEFINES = -UDEBUG -U_DEBUG -DNDEBUG
+DLLFLAGS	= -DLL -OUT:$@ -MAP:$(@:.dll=.map)
+OBJDIR_TAG = _OPT
+else
+OPTIMIZER	= -Ti+
+DEFINES = -DDEBUG -D_DEBUG -UNDEBUG
+DLLFLAGS	= -DEBUG -DLL -OUT:$@ -MAP:$(@:.dll=.map)
+OBJDIR_TAG = _DBG
+LDFLAGS = -DEBUG 
+endif
+
+DEFINES += -DOS2=4 -DBSD_SELECT
+DEFINES += -D_X86_
+DEFINES += -D_PR_GLOBAL_THREADS_ONLY
+
+# Name of the binary code directories
+ifeq ($(CPU_ARCH),x386)
+ifdef MOZ_LITE
+OBJDIR_NAME = $(subst OS2,NAV,$(OS_CONFIG))$(OBJDIR_TAG).OBJ
+else
+OBJDIR_NAME = $(OS_CONFIG)$(OBJDIR_TAG).OBJ
+endif
+else
+OBJDIR_NAME = $(OS_CONFIG)$(CPU_ARCH)$(OBJDIR_TAG).OBJ
+endif
+
+OS_DLLFLAGS = -nologo -DLL -FREE -NOE
new file mode 100644
--- /dev/null
+++ b/config/OSF1.mk
@@ -0,0 +1,93 @@
+#
+# 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.
+#
+
+#
+# Config stuff for DEC OSF/1
+#
+
+#
+# The Bourne shell (sh) on OSF1 doesn't handle "set -e" correctly,
+# which we use to stop LOOP_OVER_DIRS submakes as soon as any
+# submake fails.  So we use the Korn shell instead.
+#
+SHELL			= /usr/bin/ksh
+
+include $(MOD_DEPTH)/config/UNIX.mk
+
+#
+# XXX
+# Temporary define for the Client; to be removed when binary release is used
+#
+ifdef MOZILLA_CLIENT
+CLASSIC_NSPR = 1
+endif
+
+#
+# On OSF1 V3.2, classic nspr is the default (and only) implementation
+# strategy.
+#
+# On OSF1 V4.0, pthreads is the default implementation strategy.
+# Classic nspr is also available.
+#
+ifneq ($(OS_RELEASE),V3.2)
+USE_PTHREADS = 1
+ifeq ($(CLASSIC_NSPR), 1)
+	USE_PTHREADS =
+	IMPL_STRATEGY := _CLASSIC
+	DEFINES += -D_PR_LOCAL_THREADS_ONLY
+endif
+endif
+
+#
+# XXX
+# Temporary define for the Client; to be removed when binary release is used
+#
+ifdef MOZILLA_CLIENT
+IMPL_STRATEGY =
+endif
+
+CC			= cc $(NON_LD_FLAGS) -std -readonly_strings
+# The C++ compiler cxx has -readonly_strings on by default.
+CCC			= cxx
+
+RANLIB			= /bin/true
+
+CPU_ARCH		= alpha
+
+ifdef BUILD_OPT
+OPTIMIZER		+= -Olimit 4000
+endif
+
+NON_LD_FLAGS		= -ieee_with_inexact
+
+OS_CFLAGS		= -DOSF1 -D_REENTRANT -taso
+
+ifeq ($(OS_RELEASE),V3.2)
+OS_CFLAGS		+= -DOSF1V3
+endif
+
+ifeq ($(OS_RELEASE),V4.0)
+OS_CFLAGS		+= -DOSF1V4
+endif
+
+ifeq ($(USE_PTHREADS),1)
+OS_CFLAGS		+= -pthread
+endif
+
+# The command to build a shared library on OSF1.
+MKSHLIB = ld -shared -all -expect_unresolved "*"
+DSO_LDOPTS		= -shared
new file mode 100644
--- /dev/null
+++ b/config/Rhapsody.mk
@@ -0,0 +1,58 @@
+#
+# 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.
+#
+
+#
+# Config stuff for Rhapsody5.0
+#
+
+include $(MOD_DEPTH)/config/UNIX.mk
+
+CC			= cc
+CCC			= cc++
+RANLIB			= ranlib
+
+OS_REL_CFLAGS		= -Dppc
+CPU_ARCH		= ppc
+
+#OS_REL_CFLAGS		= -mno-486 -Di386
+#CPU_ARCH		= x86
+
+# "Commons" are tentative definitions in a global scope, like this:
+#     int x;
+# The meaning of a common is ambiguous.  It may be a true definition:
+#     int x = 0;
+# or it may be a declaration of a symbol defined in another file:
+#     extern int x;
+# Use the -fno-common option to force all commons to become true
+# definitions so that the linker can catch multiply-defined symbols.
+# Also, common symbols are not allowed with Rhapsody dynamic libraries.
+
+OS_CFLAGS		= $(DSO_CFLAGS) $(OS_REL_CFLAGS) -fno-common -pipe -DRHAPSODY -DHAVE_STRERROR -DHAVE_BSD_FLOCK
+
+DEFINES			+= -D_PR_LOCAL_THREADS_ONLY -D_PR_NEED_FAKE_POLL
+
+ARCH			= rhapsody
+
+#DSO_CFLAGS		= -fPIC
+#DSO_LDOPTS		= -Bshareable
+#DSO_LDFLAGS		=
+
+# Do we need this?: -install_name
+MKSHLIB			= $(CC) -arch ppc -dynamiclib -compatibility_version 1 -current_version 1 -all_load
+DLL_SUFFIX		= dylib
+
+#G++INCLUDES		= -I/usr/include/g++
new file mode 100644
--- /dev/null
+++ b/config/SCOOS.mk
@@ -0,0 +1,75 @@
+#
+# 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.
+#
+
+#
+# Config stuff for SCO OpenServer for x86.
+# SCO OpenServer 5, based on SVR3.2, is intended for small to
+# medium customers.
+#
+
+include $(MOD_DEPTH)/config/UNIX.mk
+
+CC			= cc -b elf -KPIC
+CCC			= g++ -b elf -I/usr/local/lib/g++-include
+# CCC			= $(DEPTH)/build/hcpp +.cpp +w
+RANLIB			= /bin/true
+
+DEFINES			+= -D_PR_LOCAL_THREADS_ONLY
+#
+# -DSCO - Changes to Netscape source (consistent with AIX, LINUX, etc..)
+# -Dsco - Needed for /usr/include/X11/*
+#
+OS_CFLAGS		= -DSYSV -D_SVID3 -DHAVE_STRERROR -D_PR_NEED_H_ERRNO -DSCO -Dsco
+#OS_LIBS			= -lpmapi -lsocket -lc
+
+MKSHLIB			= $(LD) $(DSO_LDOPTS)
+
+XINC			= /usr/include/X11
+MOTIFLIB		= -lXm
+INCLUDES		+= -I$(XINC)
+
+CPU_ARCH		= x86
+GFX_ARCH		= x
+ARCH			= sco
+
+LOCALE_MAP		= $(DEPTH)/cmd/xfe/intl/sco.lm
+EN_LOCALE		= C
+DE_LOCALE		= de_DE.ISO8859-1
+FR_LOCALE		= fr_FR.ISO8859-1
+JP_LOCALE		= ja
+SJIS_LOCALE		= ja_JP.SJIS
+KR_LOCALE		= ko_KR.EUC
+CN_LOCALE		= zh
+TW_LOCALE		= zh
+I2_LOCALE		= i2
+
+LOC_LIB_DIR		= /usr/lib/X11
+
+NOSUCHFILE		= /no-such-file
+
+BSDECHO			= /bin/echo
+
+#
+# These defines are for building unix plugins
+#
+BUILD_UNIX_PLUGINS	= 1
+#DSO_LDOPTS		= -b elf -G -z defs
+DSO_LDOPTS		= -b elf -G
+DSO_LDFLAGS		= -nostdlib -L/lib -L/usr/lib -lXm -lXt -lX11 -lgen
+
+# Used for Java compiler
+EXPORT_FLAGS = -W l,-Bexport
new file mode 100644
--- /dev/null
+++ b/config/SINIX.mk
@@ -0,0 +1,79 @@
+#
+# 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.
+#
+
+#
+# Config stuff for SNI SINIX (aka ReliantUNIX)
+#
+
+include $(MOD_DEPTH)/config/UNIX.mk
+
+# use gcc -tf-
+NS_USE_GCC		= 1
+
+ifeq ($(NS_USE_GCC),1)
+## gcc-2.7.2 homebrewn
+CC			= gcc
+COMPILER_TAG		= _gcc
+CCC			= g++
+AS			= $(CC) -x assembler-with-cpp
+LD			= gld
+ODD_CFLAGS		= -pipe -Wall -Wno-format
+ifdef BUILD_OPT
+OPTIMIZER		= -O
+#OPTIMIZER		= -O6
+endif
+MKSHLIB			= $(LD) -G -z defs -h $(@:$(OBJDIR)/%.so=%.so)
+#DSO_LDOPTS		= -G -Xlinker -Blargedynsym
+else
+## native compiler (CDS++ 1.0)
+CC			= /usr/bin/cc
+CCC			= /usr/bin/CC
+AS			= /usr/bin/cc
+#ODD_CFLAGS		= -fullwarn -xansi
+ODD_CFLAGS		= 
+ifdef BUILD_OPT
+#OPTIMIZER		= -Olimit 4000
+OPTIMIZER		= -O -F Olimit,4000
+endif
+MKSHLIB			= $(LD) -G -z defs -h $(@:$(OBJDIR)/%.so=%.so)
+#DSO_LDOPTS		= -G -W l,-Blargedynsym
+endif
+
+ODD_CFLAGS		+= -DSVR4 -DSNI -DRELIANTUNIX -Dsinix -D_SVID_GETTOD
+
+# On SINIX 5.43, need to define IP_MULTICAST in order to get the
+# IP multicast macro and struct definitions in netinet/in.h.
+# (SINIX 5.42 does not have IP multicast at all.)
+ifeq ($(OS_RELEASE),5.43)
+ODD_CFLAGS		+= -DIP_MULTICAST
+endif
+
+CPU_ARCH		= mips
+
+RANLIB			= /bin/true
+
+# For purify
+NOMD_OS_CFLAGS		= $(ODD_CFLAGS)
+
+# we do not have -MDupdate ...
+OS_CFLAGS		= $(NOMD_OS_CFLAGS)
+OS_LIBS			= -lsocket -lnsl -lresolv -ldl -lc
+NOSUCHFILE		= /no-such-file
+
+HAVE_PURIFY		= 0
+
+DEFINES			+= -D_PR_LOCAL_THREADS_ONLY
new file mode 100644
--- /dev/null
+++ b/config/SunOS.mk
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+
+#
+# Config stuff for SunOS.
+# 4 and 5 are vastly different, so we use 2 different files.
+#
+ifeq ($(basename $(OS_RELEASE)),4.1)
+include $(MOD_DEPTH)/config/SunOS4.mk
+else
+include $(MOD_DEPTH)/config/SunOS5.mk
+endif
new file mode 100644
--- /dev/null
+++ b/config/SunOS4.mk
@@ -0,0 +1,48 @@
+#
+# 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.
+#
+
+#
+# Config stuff for SunOS4.1
+#
+
+include $(MOD_DEPTH)/config/UNIX.mk
+
+# SunOS 4 _requires_ that shared libs have a version number.
+# XXX FIXME: Version number should use NSPR_VERSION_NUMBER?
+DLL_SUFFIX	= so.1.0
+
+CC			= gcc
+COMPILER_TAG		= _gcc
+
+RANLIB			= ranlib
+
+CPU_ARCH		= sparc
+
+DEFINES			+= -D_PR_LOCAL_THREADS_ONLY
+# Purify doesn't like -MDupdate
+NOMD_OS_CFLAGS		= -Wall -Wno-format -DSUNOS4
+OS_CFLAGS		= $(DSO_CFLAGS) $(NOMD_OS_CFLAGS) -MDupdate $(DEPENDENCIES)
+
+MKSHLIB			= $(LD) $(DSO_LDOPTS)
+
+HAVE_PURIFY		= 1
+
+NOSUCHFILE		= /no-such-file
+
+DSO_LDOPTS		=
+# -fPIC generates position-independent code for use in a shared library.
+DSO_CFLAGS		= -fPIC
new file mode 100644
--- /dev/null
+++ b/config/SunOS5.mk
@@ -0,0 +1,162 @@
+#
+# 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.
+#
+
+#
+# Config stuff for SunOS 5.x on sparc and x86
+#
+
+include $(MOD_DEPTH)/config/UNIX.mk
+
+#
+# XXX
+# Temporary define for the Client; to be removed when binary release is used
+#
+ifdef MOZILLA_CLIENT
+LOCAL_THREADS_ONLY = 1
+ifndef NS_USE_NATIVE
+NS_USE_GCC = 1
+endif
+endif
+
+#
+# The default implementation strategy on Solaris is global threads only.
+# Local threads only and pthreads are also available.
+#
+ifeq ($(USE_PTHREADS),1)
+  IMPL_STRATEGY = _PTH
+else
+  ifeq ($(LOCAL_THREADS_ONLY),1)
+    IMPL_STRATEGY = _LOCAL
+    DEFINES += -D_PR_LOCAL_THREADS_ONLY
+  else
+    DEFINES += -D_PR_GLOBAL_THREADS_ONLY
+  endif
+endif
+
+#
+# XXX
+# Temporary define for the Client; to be removed when binary release is used
+#
+ifdef MOZILLA_CLIENT
+IMPL_STRATEGY =
+endif
+
+ifdef NS_USE_GCC
+CC			= gcc -Wall
+CCC			= g++ -Wall
+#
+# XXX
+# Temporary define for the Client; to be removed when binary release is used
+#
+ifdef MOZILLA_CLIENT
+#COMPILER_TAG		= _gcc
+else
+COMPILER_TAG		= _gcc
+endif
+#ASFLAGS			+= -x assembler-with-cpp
+ifdef NO_MDUPDATE
+OS_CFLAGS		= $(NOMD_OS_CFLAGS)
+else
+OS_CFLAGS		= $(NOMD_OS_CFLAGS) -MDupdate $(DEPENDENCIES)
+endif
+else
+CC			= cc -xstrconst
+CCC			= CC -Qoption cg -xstrconst
+ASFLAGS			+= -Wa,-P
+OS_CFLAGS		= $(NOMD_OS_CFLAGS)
+#
+# If we are building for a release, we want to put all symbol
+# tables in the debug executable or share library instead of
+# the .o files, so that our clients can run dbx on the debug
+# library without having the .o files around.
+#
+ifdef BUILD_NUMBER
+ifndef BUILD_OPT
+OS_CFLAGS		+= -xs
+endif
+endif
+endif
+
+RANLIB			= echo
+
+OS_DEFINES		= -DSVR4 -DSYSV -D__svr4 -D__svr4__ -DSOLARIS
+
+ifeq ($(OS_TEST),i86pc)
+CPU_ARCH		= x86
+CPU_ARCH_TAG		= _i86pc
+OS_DEFINES		+= -Di386
+else
+CPU_ARCH		= sparc
+endif
+
+ifeq (5.5,$(findstring 5.5,$(OS_RELEASE)))
+OS_DEFINES		+= -DSOLARIS2_5
+SOL_CFLAGS		= -D_SVID_GETTOD
+endif
+
+ifeq ($(OS_RELEASE),5.6)
+SOL_CFLAGS		= -D_SVID_GETTOD
+endif
+
+ifneq ($(LOCAL_THREADS_ONLY),1)
+OS_DEFINES		+= -D_REENTRANT
+endif
+
+# Purify doesn't like -MDupdate
+NOMD_OS_CFLAGS		= $(DSO_CFLAGS) $(OS_DEFINES) $(SOL_CFLAGS)
+
+MKSHLIB			= $(LD) $(DSO_LDOPTS)
+
+# ld options:
+# -G: produce a shared object
+# -z defs: no unresolved symbols allowed
+DSO_LDOPTS		= -G
+
+# -KPIC generates position independent code for use in shared libraries.
+# (Similarly for -fPIC in case of gcc.)
+ifdef NS_USE_GCC
+DSO_CFLAGS		= -fPIC
+else
+DSO_CFLAGS		= -KPIC
+endif
+
+HAVE_PURIFY		= 1
+
+NOSUCHFILE		= /no-such-file
+
+#
+# Library of atomic functions for UltraSparc systems
+#
+# The nspr makefiles build ULTRASPARC_LIBRARY (which contains assembly language
+# implementation of the nspr atomic functions for UltraSparc systems) in addition
+# to libnspr.so. (The actual name of the library is
+# lib$(ULTRASPARC_LIBRARY)$(MOD_VERSION).so
+#
+# The actual name of the filter-library, recorded in libnspr.so, is set to the
+# value of $(ULTRASPARC_FILTER_LIBRARY).
+# For an application to use the assembly-language implementation, a link should be
+# made so that opening ULTRASPARC_FILTER_LIBRARY results in opening
+# ULTRASPARC_LIBRARY. This indirection requires the user to explicitly set up
+# library for use on UltraSparc systems, thereby helping to avoid using it by
+# accident on non-UltraSparc systems.
+# The directory containing the ultrasparc libraries should be in LD_LIBRARY_PATH.
+#
+ifeq ($(OS_TEST),sun4u)
+ULTRASPARC_LIBRARY = ultrasparc
+ULTRASPARC_FILTER_LIBRARY = libatomic.so
+DSO_LDOPTS		+= -f $(ULTRASPARC_FILTER_LIBRARY)
+endif
new file mode 100644
--- /dev/null
+++ b/config/UNIX.mk
@@ -0,0 +1,70 @@
+#
+# 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.
+#
+
+XP_DEFINE	= -DXP_UNIX
+OBJ_SUFFIX	= o
+LIB_SUFFIX	= a
+DLL_SUFFIX	= so
+AR		= ar cr $@
+
+ifdef BUILD_OPT
+OPTIMIZER	= -O
+DEFINES		= -UDEBUG -DNDEBUG
+OBJDIR_TAG	= _OPT
+else
+OPTIMIZER	= -g
+DEFINES		= -DDEBUG -UNDEBUG -DDEBUG_$(shell whoami)
+OBJDIR_TAG	= _DBG
+endif
+
+# Name of the binary code directories
+OBJDIR_NAME	= $(OS_CONFIG)$(CPU_ARCH_TAG)$(COMPILER_TAG)$(IMPL_STRATEGY)$(OBJDIR_TAG).OBJ
+
+MKDEPEND_DIR    = $(DEPTH)/config/mkdepend
+MKDEPEND 	= $(MKDEPEND_DIR)/$(OBJDIR_NAME)/mkdepend
+MKDEPENDENCIES  = $(OBJDIR)/depend.mk
+
+####################################################################
+#
+# One can define the makefile variable NSDISTMODE to control
+# how files are published to the 'dist' directory.  If not
+# defined, the default is "install using relative symbolic
+# links".  The two possible values are "copy", which copies files
+# but preserves source mtime, and "absolute_symlink", which
+# installs using absolute symbolic links.  The "absolute_symlink"
+# option requires NFSPWD.
+#
+####################################################################
+
+NSINSTALL	= $(MOD_DEPTH)/config/$(OBJDIR_NAME)/nsinstall
+
+ifeq ($(NSDISTMODE),copy)
+# copy files, but preserve source mtime
+INSTALL		= $(NSINSTALL) -t
+else
+ifeq ($(NSDISTMODE),absolute_symlink)
+# install using absolute symbolic links
+INSTALL		= $(NSINSTALL) -L `$(NFSPWD)`
+else
+# install using relative symbolic links
+INSTALL		= $(NSINSTALL) -R
+endif
+endif
+
+define MAKE_OBJDIR
+if test ! -d $(@D); then rm -rf $(@D); $(NSINSTALL) -D $(@D); fi
+endef
new file mode 100644
--- /dev/null
+++ b/config/UNIXWARE.mk
@@ -0,0 +1,44 @@
+#
+# 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.
+#
+
+#
+# Config stuff for SCO UnixWare
+# UnixWare is intended for high-end enterprise customers.
+# UnixWare 2.1 and 2.1.1 are based on SVR4.  (2.1.2 is a maintenance
+# release.)
+# UnixWare 7 (codename Gemini) is based on what SCO calls SVR5.
+# The somewhat odd version number 7 was chosen to suggest that
+#     UnixWare 2 + OpenServer 5 = UnixWare 7
+#
+
+include $(MOD_DEPTH)/config/UNIX.mk
+
+CC		= $(NSDEPTH)/build/hcc
+CCC		= $(NSDEPTH)/build/hcpp
+
+RANLIB		= true
+
+DEFINES		+= -D_PR_LOCAL_THREADS_ONLY
+OS_CFLAGS	= -DSVR4 -DSYSV -DUNIXWARE
+
+MKSHLIB		= $(LD) $(DSO_LDOPTS)
+DSO_LDOPTS	= -G
+
+CPU_ARCH	= x86
+ARCH		= sco
+
+NOSUCHFILE	= /no-such-file
new file mode 100644
--- /dev/null
+++ b/config/WIN32.mk
@@ -0,0 +1,139 @@
+#
+# 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.
+#
+
+#
+# Configuration common to all versions of Windows NT
+# and Windows 95.
+#
+
+#
+# Client build: make sure we use the shmsdos.exe under $(MOZ_TOOLS).
+# $(MOZ_TOOLS_FLIPPED) is $(MOZ_TOOLS) with all the backslashes
+# flipped, so that gmake won't interpret them as escape characters.
+#
+ifdef PR_CLIENT_BUILD_WINDOWS
+SHELL = $(MOZ_TOOLS_FLIPPED)/bin/shmsdos.exe
+endif
+
+CC = cl
+CCC = cl
+LINK = link
+AR = lib -NOLOGO -OUT:"$@"
+RANLIB = echo
+BSDECHO = echo
+NSINSTALL = nsinstall
+INSTALL	= $(NSINSTALL)
+define MAKE_OBJDIR
+if test ! -d $(@D); then rm -rf $(@D); $(NSINSTALL) -D $(@D); fi
+endef
+RC = rc.exe
+
+GARBAGE = $(OBJDIR)/vc20.pdb $(OBJDIR)/vc40.pdb
+
+XP_DEFINE = -DXP_PC
+OBJ_SUFFIX = obj
+LIB_SUFFIX = lib
+DLL_SUFFIX = dll
+
+OS_CFLAGS = -W3 -nologo -GF -Gy
+
+ifdef MOZ_PROF
+
+#
+# compile with debug symbols, but without DEBUG code and ASSERTs
+#
+ifdef USE_DEBUG_RTL
+OS_CFLAGS += -MDd
+else
+OS_CFLAGS += -MD
+endif
+OPTIMIZER = -Od -Z7
+#OPTIMIZER = -Zi -Fd$(OBJDIR)/ -Od
+DEFINES = -UDEBUG -U_DEBUG -DNDEBUG
+DLLFLAGS = -DEBUG -DEBUGTYPE:CV -OUT:"$@"
+OBJDIR_TAG = _DBG
+LDFLAGS = -DEBUG -DEBUGTYPE:CV
+
+else
+
+ifdef BUILD_OPT
+OS_CFLAGS += -MD
+OPTIMIZER = -O2
+DEFINES = -UDEBUG -U_DEBUG -DNDEBUG
+DLLFLAGS = -OUT:"$@"
+OBJDIR_TAG = _OPT
+else
+#
+# Define USE_DEBUG_RTL if you want to use the debug runtime library
+# (RTL) in the debug build
+#
+ifdef USE_DEBUG_RTL
+OS_CFLAGS += -MDd
+else
+OS_CFLAGS += -MD
+endif
+OPTIMIZER = -Od -Z7
+#OPTIMIZER = -Zi -Fd$(OBJDIR)/ -Od
+DEFINES = -DDEBUG -D_DEBUG -UNDEBUG
+DLLFLAGS = -DEBUG -DEBUGTYPE:CV -OUT:"$@"
+OBJDIR_TAG = _DBG
+LDFLAGS = -DEBUG -DEBUGTYPE:CV
+endif
+endif
+
+DEFINES += -DWIN32
+ifeq ($(OS_TARGET),WINNT)
+#
+# Win NT needs -GT so that fibers can work
+#
+OS_CFLAGS += -GT
+DEFINES += -DWINNT
+else
+DEFINES += -DWIN95 -D_PR_GLOBAL_THREADS_ONLY
+endif
+
+ifeq ($(CPU_ARCH),x386)
+DEFINES += -D_X86_
+else
+ifeq ($(CPU_ARCH),MIPS)
+DEFINES += -D_MIPS_
+else
+ifeq ($(CPU_ARCH),ALPHA)
+DEFINES += -D_ALPHA_=1
+else
+CPU_ARCH = processor_is_undefined
+endif
+endif
+endif
+
+# Name of the binary code directories
+
+ifeq ($(CPU_ARCH),x386)
+CPU_ARCH_TAG =
+else
+CPU_ARCH_TAG = $(CPU_ARCH)
+endif
+
+ifdef USE_DEBUG_RTL
+OBJDIR_SUFFIX = OBJD
+else
+OBJDIR_SUFFIX = OBJ
+endif
+
+OBJDIR_NAME = $(OS_CONFIG)$(CPU_ARCH_TAG)$(OBJDIR_TAG).$(OBJDIR_SUFFIX)
+
+OS_DLLFLAGS = -nologo -DLL -SUBSYSTEM:WINDOWS -PDB:NONE
new file mode 100644
--- /dev/null
+++ b/config/WIN95.mk
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+#
+# Config stuff for WIN95
+#
+
+include $(MOD_DEPTH)/config/WIN32.mk
new file mode 100644
--- /dev/null
+++ b/config/WINNT.mk
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+#
+# Config stuff for WINNT
+#
+
+include $(MOD_DEPTH)/config/WIN32.mk
new file mode 100644
--- /dev/null
+++ b/config/arch.mk
@@ -0,0 +1,203 @@
+#
+# 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.
+#
+
+#######################################################################
+# Master "Core Components" macros for getting the OS architecture     #
+#######################################################################
+
+#
+# Important internal static macros
+#
+
+OS_ARCH		:= $(subst /,_,$(shell uname -s))
+OS_RELEASE	:= $(shell uname -r)
+OS_TEST		:= $(shell uname -m)
+
+#
+# Tweak the default OS_ARCH and OS_RELEASE macros as needed.
+#
+ifeq ($(OS_ARCH),AIX)
+OS_RELEASE	:= $(shell uname -v).$(shell uname -r)
+endif
+ifeq ($(OS_ARCH),BSD_386)
+OS_ARCH		:= BSD_OS
+endif
+ifeq ($(OS_ARCH),IRIX64)
+OS_ARCH		:= IRIX
+endif
+ifeq ($(OS_ARCH),UNIX_SV)
+ifneq ($(findstring NCR,$(shell grep NCR /etc/bcheckrc | head -1 )),)
+OS_ARCH		:= NCR
+else
+OS_ARCH		:= UNIXWARE
+OS_RELEASE	:= $(shell uname -v)
+endif
+endif
+ifeq ($(OS_ARCH),ncr)
+OS_ARCH		:= NCR
+endif
+# This is the only way to correctly determine the actual OS version on NCR boxes.
+ifeq ($(OS_ARCH),NCR)
+OS_RELEASE	:= $(shell awk '{print $$3}' /etc/.relid | sed 's/^\([0-9]\)\(.\)\(..\)\(.*\)$$/\2.\3/')
+endif
+ifeq ($(OS_ARCH),UNIX_System_V)
+OS_ARCH		:= NEC
+endif
+ifeq ($(OS_ARCH),SCO_SV)
+OS_ARCH		:= SCOOS
+OS_RELEASE	:= 5.0
+endif
+ifeq ($(OS_ARCH),SINIX-N)
+OS_ARCH		:= SINIX
+endif
+ifeq ($(OS_ARCH),SINIX-Y)
+OS_ARCH		:= SINIX
+endif
+# SINIX changes name to ReliantUNIX with 5.43
+ifeq ($(OS_ARCH),ReliantUNIX-N)
+OS_ARCH		:= SINIX
+endif
+ifeq ($(OS_ARCH),UnixWare)
+OS_ARCH		:= UNIXWARE
+OS_RELEASE	:= $(shell uname -v)
+endif
+
+#
+# Handle FreeBSD 2.2-STABLE and Linux 2.0.30-osfmach3
+#
+
+ifeq (,$(filter-out Linux FreeBSD,$(OS_ARCH)))
+OS_RELEASE	:= $(shell echo $(OS_RELEASE) | sed 's/-.*//')
+endif
+
+#
+# Distinguish between OSF1 V4.0B and V4.0D
+#
+
+ifeq ($(OS_ARCH)$(OS_RELEASE),OSF1V4.0)
+	OS_VERSION := $(shell uname -v)
+	ifeq ($(OS_VERSION),564)
+		OS_RELEASE := V4.0B
+	endif
+	ifeq ($(OS_VERSION),878)
+		OS_RELEASE := V4.0D
+	endif
+endif
+
+#######################################################################
+# Master "Core Components" macros for getting the OS target           #
+#######################################################################
+
+#
+# Note: OS_TARGET should be specified on the command line for gmake.
+# When OS_TARGET=WIN95 is specified, then a Windows 95 target is built.
+# The difference between the Win95 target and the WinNT target is that
+# the WinNT target uses Windows NT specific features not available
+# in Windows 95. The Win95 target will run on Windows NT, but (supposedly)
+# at lesser performance (the Win95 target uses threads; the WinNT target
+# uses fibers).
+#
+# When OS_TARGET=WIN16 is specified, then a Windows 3.11 (16bit) target
+# is built. See: win16_3.11.mk for lots more about the Win16 target.
+#
+# If OS_TARGET is not specified, it defaults to $(OS_ARCH), i.e., no
+# cross-compilation.
+#
+
+#
+# The following hack allows one to build on a WIN95 machine (as if
+# s/he were cross-compiling on a WINNT host for a WIN95 target).
+# It also accomodates for MKS's uname.exe.  If you never intend
+# to do development on a WIN95 machine, you don't need this hack.
+#
+ifeq ($(OS_ARCH),WIN95)
+	OS_ARCH   := WINNT
+	OS_TARGET := WIN95
+endif
+ifeq ($(OS_ARCH),Windows_95)
+	OS_ARCH   := Windows_NT
+	OS_TARGET := WIN95
+endif
+ifeq ($(OS_ARCH), OS2)
+	OS_ARCH   := WINNT
+	OS_TARGET := OS2
+endif
+
+#
+# On WIN32, we also define the variable CPU_ARCH.
+#
+
+ifeq ($(OS_ARCH), WINNT)
+	CPU_ARCH := $(shell uname -p)
+	ifeq ($(CPU_ARCH),I386)
+		CPU_ARCH = x386
+	endif
+else
+#
+# If uname -s returns "Windows_NT", we assume that we are using
+# the uname.exe in MKS toolkit.
+#
+# The -r option of MKS uname only returns the major version number.
+# So we need to use its -v option to get the minor version number.
+# Moreover, it doesn't have the -p option, so we need to use uname -m.
+#
+ifeq ($(OS_ARCH), Windows_NT)
+	OS_ARCH = WINNT
+	OS_MINOR_RELEASE := $(shell uname -v)
+	ifeq ($(OS_MINOR_RELEASE),00)
+		OS_MINOR_RELEASE = 0
+	endif
+	OS_RELEASE := $(OS_RELEASE).$(OS_MINOR_RELEASE)
+	CPU_ARCH := $(shell uname -m)
+	#
+	# MKS's uname -m returns "586" on a Pentium machine.
+	#
+	ifneq (,$(findstring 86,$(CPU_ARCH)))
+		CPU_ARCH = x386
+	endif
+else
+#
+# If uname -s returns "CYGWIN32/NT", we assume that we are using
+# the uname.exe in the GNU-Win32 tools.
+#
+ifeq ($(OS_ARCH), CYGWIN32_NT)
+	OS_ARCH = WINNT
+	CPU_ARCH := $(shell uname -m)
+	#
+	# GNU-Win32's uname -m returns "i686" on a Pentium Pro machine.
+	#
+	ifneq (,$(findstring 86,$(CPU_ARCH)))
+		CPU_ARCH = x386
+	endif
+endif
+endif
+endif
+
+ifndef OS_TARGET
+	OS_TARGET := $(OS_ARCH)
+endif
+
+ifeq ($(OS_TARGET), WIN95)
+	OS_RELEASE := 4.0
+endif
+
+ifeq ($(OS_TARGET), WIN16)
+	OS_RELEASE :=
+#	OS_RELEASE := _3.11
+endif
+
+OS_CONFIG := $(OS_TARGET)$(OS_RELEASE)
new file mode 100644
--- /dev/null
+++ b/config/config.mk
@@ -0,0 +1,112 @@
+#! gmake
+#
+# 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.
+#
+
+# Configuration information for building in the NSPR source module
+
+# Define an include-at-most-once-flag
+NSPR_CONFIG_MK	= 1
+
+include $(MOD_DEPTH)/config/module.df
+
+include $(MOD_DEPTH)/config/arch.mk
+
+ifndef NSDEPTH
+NSDEPTH = $(MOD_DEPTH)/..
+endif
+
+#
+# Default command macros; can be overridden in <arch>.mk.
+#
+# XXX FIXME: I removed CCF and LINKEXE.
+AS		= $(CC)
+ASFLAGS		= $(CFLAGS)
+PURIFY		= purify $(PURIFYOPTIONS)
+LINK_DLL	= $(LINK) $(OS_DLLFLAGS) $(DLLFLAGS)
+NFSPWD		= $(MOD_DEPTH)/config/nfspwd
+
+LIBNSPR		= $(DIST)/lib/libnspr.$(LIB_SUFFIX)
+PURELIBNSPR	= $(DIST)/lib/libpurenspr.$(LIB_SUFFIX)
+
+CFLAGS		= $(OPTIMIZER) $(OS_CFLAGS) $(XP_DEFINE) $(DEFINES) $(INCLUDES) \
+				$(XCFLAGS)
+# For purify
+NOMD_CFLAGS	= $(OPTIMIZER) $(NOMD_OS_CFLAGS) $(XP_DEFINE) $(DEFINES) $(INCLUDES) \
+				$(XCFLAGS)
+
+include $(MOD_DEPTH)/config/$(OS_TARGET).mk
+
+# Figure out where the binary code lives.
+BUILD		= $(OBJDIR_NAME)
+OBJDIR		= $(OBJDIR_NAME)
+DIST		= $(NSDEPTH)/dist/$(OBJDIR_NAME)
+ifeq ($(MOZ_BITS),16)
+MOZ_INCL	= $(NSDEPTH)/dist/public/win16
+MOZ_DIST	= $(NSDEPTH)/dist/WIN16D_D.OBJ
+endif
+
+VPATH		= $(OBJDIR)
+DEPENDENCIES	= $(OBJDIR)/.md
+
+ifdef BUILD_DEBUG_GC
+DEFINES		+= -DDEBUG_GC
+endif
+
+GARBAGE		+= $(DEPENDENCIES) core $(wildcard core.[0-9]*)
+
+####################################################################
+#
+# The NSPR-specific configuration
+#
+####################################################################
+
+OS_CFLAGS += -DFORCE_PR_LOG
+
+ifeq ($(_PR_NO_CLOCK_TIMER),1)
+OS_CFLAGS += -D_PR_NO_CLOCK_TIMER
+endif
+
+ifeq ($(USE_PTHREADS), 1)
+OS_CFLAGS += -D_PR_PTHREADS -UHAVE_CVAR_BUILT_ON_SEM
+endif
+
+ifeq ($(PTHREADS_USER), 1)
+OS_CFLAGS += -DPTHREADS_USER -UHAVE_CVAR_BUILT_ON_SEM
+endif
+
+ifeq ($(USE_IPV6),1)
+OS_CFLAGS += -D_PR_INET6
+endif
+
+####################################################################
+#
+# Configuration for the release process
+#
+####################################################################
+
+MDIST = /m/dist
+ifeq ($(OS_ARCH),WINNT)
+MDIST = //helium/dist
+MDIST_DOS = \\\\helium\\dist
+endif
+
+# RELEASE_DIR is ns/dist/<module name>
+
+RELEASE_DIR = $(NSDEPTH)/dist/release/$(MOD_NAME)
+
+RELEASE_INCLUDE_DIR = $(RELEASE_DIR)/$(BUILD_NUMBER)/$(OBJDIR_NAME)/include
+RELEASE_LIB_DIR = $(RELEASE_DIR)/$(BUILD_NUMBER)/$(OBJDIR_NAME)/lib
new file mode 100644
--- /dev/null
+++ b/config/libc_r.h
@@ -0,0 +1,139 @@
+/* -*- 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.
+ */
+
+/* libc_r.h  --  macros, defines, etc. to make using reentrant libc calls */
+/*               a bit easier.  This was initially done for AIX pthreads, */
+/*               but should be usable for anyone...                       */
+
+/* Most of these use locally defined space instead of static library space. */
+/* Because of this, we use the _INIT_R to declare/allocate space (stack),   */
+/* and the plain routines to actually do it..._WARNING_: avoid allocating   */
+/* memory wherever possible.  Memory allocation is fairly expensive, at     */
+/* least on AIX...use arrays instead (which allocate from the stack.)       */
+/* I know the names are a bit strange, but I wanted to be fairly certain    */
+/* that we didn't have any namespace corruption...in general, the inits are */
+/* R_<name>_INIT_R(), and the actual calls are R_<name>_R().                */
+
+#ifndef _LIBC_R_H
+#define _LIBC_R_H
+
+/************/
+/*  strtok  */
+/************/
+#define R_STRTOK_INIT_R() \
+    char *r_strtok_r=NULL
+
+#define R_STRTOK_R(return,source,delim) \     
+    return=strtok_r(source,delim,&r_strtok_r)
+
+#define R_STRTOK_NORET_R(source,delim) \
+    strtok_r(source,delim,&r_strtok_r)
+
+/**************/
+/*  strerror  */
+/**************/
+#define R_MAX_STRERROR_LEN_R 8192     /* Straight from limits.h */
+
+#define R_STRERROR_INIT_R() \
+    char r_strerror_r[R_MAX_STRERROR_LEN_R]
+
+#define R_STRERROR_R(val) \
+    strerror_r(val,r_strerror_r,R_MAX_STRERROR_LEN_R)
+
+/*****************/
+/*  time things  */
+/*****************/
+#define R_ASCTIME_INIT_R() \
+    char r_asctime_r[26]
+
+#define R_ASCTIME_R(val) \
+    asctime_r(val,r_asctime_r)
+
+#define R_CTIME_INIT_R() \
+    char r_ctime_r[26]
+
+#define R_CTIME_R(val) \
+    ctime_r(val,r_ctime_r)
+
+#define R_GMTIME_INIT_R() \
+    struct tm r_gmtime_r
+
+#define R_GMTIME_R(time) \
+    gmtime_r(time,&r_gmtime_r)
+
+#define R_LOCALTIME_INIT_R() \
+   struct tm r_localtime_r
+
+#define R_LOCALTIME_R(val) \
+   localtime_r(val,&r_localtime_r)
+    
+/***********/
+/*  crypt  */
+/***********/
+#include <crypt.h>
+#define R_CRYPT_INIT_R() \
+    CRYPTD r_cryptd_r; \
+    bzero(&r_cryptd_r,sizeof(CRYPTD)) 
+
+#define R_CRYPT_R(pass,salt) \
+    crypt_r(pass,salt,&r_cryptd_r)
+
+/**************/
+/*  pw stuff  */
+/**************/
+#define R_MAX_PW_LEN_R 1024
+/* The following must be after the last declaration, but */
+/* before the first bit of code...                       */
+#define R_GETPWNAM_INIT_R(pw_ptr) \
+    struct passwd r_getpwnam_pw_r; \
+    char r_getpwnam_line_r[R_MAX_PW_LEN_R]; \
+    pw_ptr = &r_getpwnam_pw_r
+
+#define R_GETPWNAM_R(name) \
+    getpwnam_r(name,&r_getpwnam_pw_r,r_getpwnam_line_r,R_MAX_PW_LEN_R)
+
+/*******************/
+/*  gethost stuff  */
+/*******************/
+#define R_GETHOSTBYADDR_INIT_R() \
+    struct hostent r_gethostbyaddr_r; \
+    struct hostent_data r_gethostbyaddr_data_r
+
+#define R_GETHOSTBYADDR_R(addr,len,type,xptr_ent) \
+    bzero(&r_gethostbyaddr_r,sizeof(struct hostent)); \
+    bzero(&r_gethostbyaddr_data_r,sizeof(struct hostent_data)); \
+    xptr_ent = &r_gethostbyaddr_r; \
+    if (gethostbyaddr_r(addr,len,type, \
+       &r_gethostbyaddr_r,&r_gethostbyaddr_data_r) == -1) { \
+           xptr_ent = NULL; \
+    }
+
+#define R_GETHOSTBYNAME_INIT_R() \
+    struct hostent r_gethostbyname_r; \
+    struct hostent_data r_gethostbyname_data_r
+
+#define R_GETHOSTBYNAME_R(name,xptr_ent) \
+    bzero(&r_gethostbyname_r,sizeof(struct hostent)); \
+    bzero(&r_gethostbyname_data_r,sizeof(struct hostent_data)); \
+    xptr_ent = &r_gethostbyname_r; \
+    if (gethostbyname_r(name, \
+       &r_gethostbyname_r,&r_gethostbyname_data_r) == -1) { \
+          xptr_ent = NULL; \
+    }
+
+#endif /* _LIBC_R_H */
new file mode 100644
--- /dev/null
+++ b/config/module.df
@@ -0,0 +1,23 @@
+#
+# 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.
+#
+
+# Module description file
+#
+# A module is also called a component or a subsystem.
+
+MOD_NAME = nspr20
+MOD_VERSION = 21
new file mode 100644
--- /dev/null
+++ b/config/nfspwd.pl
@@ -0,0 +1,30 @@
+#! perl
+#
+# 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.
+#
+
+require "fastcwd.pl";
+
+$_ = &fastcwd;
+if (m@^/[uh]/@o || s@^/tmp_mnt/@/@o) {
+    print("$_\n");
+} elsif ((($user, $rest) = m@^/usr/people/(\w+)/(.*)@o)
+      && readlink("/u/$user") eq "/usr/people/$user") {
+    print("/u/$user/$rest\n");
+} else {
+    chop($host = `hostname`);
+    print("/h/$host$_\n");
+}
new file mode 100644
--- /dev/null
+++ b/config/nsinstall.c
@@ -0,0 +1,336 @@
+/* -*- 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.
+ */
+
+/*
+** Netscape portable install command.
+**
+** Brendan Eich, 7/20/95
+*/
+#include <stdio.h>  /* OSF/1 requires this before grp.h, so put it first */
+#include <assert.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utime.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "pathsub.h"
+
+#define HAVE_LCHOWN
+
+#if defined(AIX) || defined(BSDI) || defined(HPUX) || defined(LINUX) || defined(SUNOS4) || defined(SCO) || defined(UNIXWARE) || defined(RHAPSODY)
+#undef HAVE_LCHOWN
+#endif
+
+/*
+ * Does getcwd() take NULL as the first argument and malloc
+ * the result buffer?
+ */
+#if !defined(RHAPSODY)
+#define GETCWD_CAN_MALLOC
+#endif
+
+#ifdef LINUX
+#include <getopt.h>
+#endif
+
+#if defined(SCO) || defined(UNIXWARE) || defined(SNI) || defined(NCR) || defined(NEC)
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+#define S_ISLNK(a)	(((a) & S_IFMT) == S_IFLNK)
+#endif
+#endif
+
+#if defined(SNI)
+extern int fchmod(int fildes, mode_t mode);
+#endif
+
+static void
+usage(void)
+{
+    fprintf(stderr,
+	"usage: %s [-C cwd] [-L linkprefix] [-m mode] [-o owner] [-g group]\n"
+	"       %*s [-DdltR] file [file ...] directory\n",
+	program, strlen(program), "");
+    exit(2);
+}
+
+static int
+mkdirs(char *path, mode_t mode)
+{
+    char *cp;
+    struct stat sb;
+    
+    while (*path == '/' && path[1] == '/')
+	path++;
+    while ((cp = strrchr(path, '/')) && cp[1] == '\0')
+	*cp = '\0';
+    if (cp && cp != path) {
+	*cp = '\0';
+	if ((lstat(path, &sb) < 0 || !S_ISDIR(sb.st_mode)) &&
+	    mkdirs(path, mode) < 0) {
+	    return -1;
+	}
+	*cp = '/';
+    }
+    return mkdir(path, mode);
+}
+
+static uid_t
+touid(char *owner)
+{
+    struct passwd *pw;
+    uid_t uid;
+    char *cp;
+
+    pw = getpwnam(owner);
+    if (pw)
+	return pw->pw_uid;
+    uid = strtol(owner, &cp, 0);
+    if (uid == 0 && cp == owner)
+	fail("cannot find uid for %s", owner);
+    return uid;
+}
+
+static gid_t
+togid(char *group)
+{
+    struct group *gr;
+    gid_t gid;
+    char *cp;
+
+    gr = getgrnam(group);
+    if (gr)
+	return gr->gr_gid;
+    gid = strtol(group, &cp, 0);
+    if (gid == 0 && cp == group)
+	fail("cannot find gid for %s", group);
+    return gid;
+}
+
+int
+main(int argc, char **argv)
+{
+    int onlydir, dodir, dolink, dorelsymlink, dotimes, opt, len, lplen, tdlen, bnlen, exists, fromfd, tofd, cc, wc;
+    mode_t mode = 0755;
+    char *linkprefix, *owner, *group, *cp, *cwd, *todir, *toname, *name, *base, *linkname, *bp, buf[BUFSIZ];
+    uid_t uid;
+    gid_t gid;
+    struct stat sb, tosb;
+    struct utimbuf utb;
+
+    program = argv[0];
+    cwd = linkname = linkprefix = owner = group = 0;
+    onlydir = dodir = dolink = dorelsymlink = dotimes = lplen = 0;
+
+    while ((opt = getopt(argc, argv, "C:DdlL:Rm:o:g:t")) != EOF) {
+	switch (opt) {
+	  case 'C':
+	    cwd = optarg;
+	    break;
+	  case 'D':
+	    onlydir = 1;
+	    break;
+	  case 'd':
+	    dodir = 1;
+	    break;
+	  case 'l':
+	    dolink = 1;
+	    break;
+	  case 'L':
+	    linkprefix = optarg;
+	    lplen = strlen(linkprefix);
+	    dolink = 1;
+	    break;
+	  case 'R':
+	    dolink = dorelsymlink = 1;
+	    break;
+	  case 'm':
+	    mode = strtoul(optarg, &cp, 8);
+	    if (mode == 0 && cp == optarg)
+		usage();
+	    break;
+	  case 'o':
+	    owner = optarg;
+	    break;
+	  case 'g':
+	    group = optarg;
+	    break;
+	  case 't':
+	    dotimes = 1;
+	    break;
+	  default:
+	    usage();
+	}
+    }
+
+    argc -= optind;
+    argv += optind;
+    if (argc < 2 - onlydir)
+	usage();
+
+    todir = argv[argc-1];
+    if ((stat(todir, &sb) < 0 || !S_ISDIR(sb.st_mode)) &&
+	mkdirs(todir, 0777) < 0) {
+	fail("cannot make directory %s", todir);
+    }
+    if (onlydir)
+	return 0;
+
+    if (!cwd) {
+#ifdef GETCWD_CAN_MALLOC
+	cwd = getcwd(0, PATH_MAX);
+#else
+	cwd = malloc(PATH_MAX + 1);
+	cwd = getcwd(cwd, PATH_MAX);
+#endif
+    }
+    xchdir(todir);
+#ifdef GETCWD_CAN_MALLOC
+    todir = getcwd(0, PATH_MAX);
+#else
+    todir = malloc(PATH_MAX + 1);
+    todir = getcwd(todir, PATH_MAX);
+#endif
+    tdlen = strlen(todir);
+    xchdir(cwd);
+    tdlen = strlen(todir);
+
+    uid = owner ? touid(owner) : -1;
+    gid = group ? togid(group) : -1;
+
+    while (--argc > 0) {
+	name = *argv++;
+	len = strlen(name);
+	base = xbasename(name);
+	bnlen = strlen(base);
+	toname = (char*)xmalloc(tdlen + 1 + bnlen + 1);
+	sprintf(toname, "%s/%s", todir, base);
+	exists = (lstat(toname, &tosb) == 0);
+
+	if (dodir) {
+	    /* -d means create a directory, always */
+	    if (exists && !S_ISDIR(tosb.st_mode)) {
+		(void) unlink(toname);
+		exists = 0;
+	    }
+	    if (!exists && mkdir(toname, mode) < 0)
+		fail("cannot make directory %s", toname);
+	    if ((owner || group) && chown(toname, uid, gid) < 0)
+		fail("cannot change owner of %s", toname);
+	} else if (dolink) {
+	    if (*name == '/') {
+		/* source is absolute pathname, link to it directly */
+		linkname = 0;
+	    } else {
+		if (linkprefix) {
+		    /* -L implies -l and prefixes names with a $cwd arg. */
+		    len += lplen + 1;
+		    linkname = (char*)xmalloc(len + 1);
+		    sprintf(linkname, "%s/%s", linkprefix, name);
+		} else if (dorelsymlink) {
+		    /* Symlink the relative path from todir to source name. */
+		    linkname = (char*)xmalloc(PATH_MAX);
+
+		    if (*todir == '/') {
+			/* todir is absolute: skip over common prefix. */
+			lplen = relatepaths(todir, cwd, linkname);
+			strcpy(linkname + lplen, name);
+		    } else {
+			/* todir is named by a relative path: reverse it. */
+			reversepath(todir, name, len, linkname);
+			xchdir(cwd);
+		    }
+
+		    len = strlen(linkname);
+		}
+		name = linkname;
+	    }
+
+	    /* Check for a pre-existing symlink with identical content. */
+	    if (exists &&
+		(!S_ISLNK(tosb.st_mode) ||
+		 readlink(toname, buf, sizeof buf) != len ||
+		 strncmp(buf, name, len) != 0)) {
+		(void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname);
+		exists = 0;
+	    }
+	    if (!exists && symlink(name, toname) < 0)
+		fail("cannot make symbolic link %s", toname);
+#ifdef HAVE_LCHOWN
+	    if ((owner || group) && lchown(toname, uid, gid) < 0)
+		fail("cannot change owner of %s", toname);
+#endif
+
+	    if (linkname) {
+		free(linkname);
+		linkname = 0;
+	    }
+	} else {
+	    /* Copy from name to toname, which might be the same file. */
+	    fromfd = open(name, O_RDONLY);
+	    if (fromfd < 0 || fstat(fromfd, &sb) < 0)
+		fail("cannot access %s", name);
+	    if (exists && (!S_ISREG(tosb.st_mode) || access(toname, W_OK) < 0))
+		(void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname);
+	    tofd = open(toname, O_CREAT | O_WRONLY, 0666);
+	    if (tofd < 0)
+		fail("cannot create %s", toname);
+
+	    bp = buf;
+	    while ((cc = read(fromfd, bp, sizeof buf)) > 0) {
+		while ((wc = write(tofd, bp, cc)) > 0) {
+		    if ((cc -= wc) == 0)
+			break;
+		    bp += wc;
+		}
+		if (wc < 0)
+		    fail("cannot write to %s", toname);
+	    }
+	    if (cc < 0)
+		fail("cannot read from %s", name);
+
+	    if (ftruncate(tofd, sb.st_size) < 0)
+		fail("cannot truncate %s", toname);
+	    if (dotimes) {
+		utb.actime = sb.st_atime;
+		utb.modtime = sb.st_mtime;
+		if (utime(toname, &utb) < 0)
+		    fail("cannot set times of %s", toname);
+	    }
+	    if (fchmod(tofd, mode) < 0)
+		fail("cannot change mode of %s", toname);
+	    if ((owner || group) && fchown(tofd, uid, gid) < 0)
+		fail("cannot change owner of %s", toname);
+
+	    /* Must check for delayed (NFS) write errors on close. */
+	    if (close(tofd) < 0)
+		fail("cannot write to %s", toname);
+	    close(fromfd);
+	}
+
+	free(toname);
+    }
+
+    free(cwd);
+    free(todir);
+    return 0;
+}
new file mode 100644
--- /dev/null
+++ b/config/pathsub.c
@@ -0,0 +1,219 @@
+/* -*- 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.
+ */
+
+/*
+** Pathname subroutines.
+**
+** Brendan Eich, 8/29/95
+*/
+#include <assert.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include "pathsub.h"
+#ifdef USE_REENTRANT_LIBC
+#include "libc_r.h"
+#endif /* USE_REENTRANT_LIBC */
+
+char *program;
+
+void
+fail(char *format, ...)
+{
+    int error;
+    va_list ap;
+
+#ifdef USE_REENTRANT_LIBC
+    R_STRERROR_INIT_R();
+#endif
+
+    error = errno;
+    fprintf(stderr, "%s: ", program);
+    va_start(ap, format);
+    vfprintf(stderr, format, ap);
+    va_end(ap);
+    if (error)
+
+#ifdef USE_REENTRANT_LIBC
+    R_STRERROR_R(errno);
+	fprintf(stderr, ": %s", r_strerror_r);
+#else
+	fprintf(stderr, ": %s", strerror(errno));
+#endif
+
+    putc('\n', stderr);
+    exit(1);
+}
+
+char *
+getcomponent(char *path, char *name)
+{
+    if (*path == '\0')
+	return 0;
+    if (*path == '/') {
+	*name++ = '/';
+    } else {
+	do {
+	    *name++ = *path++;
+	} while (*path != '/' && *path != '\0');
+    }
+    *name = '\0';
+    while (*path == '/')
+	path++;
+    return path;
+}
+
+#ifdef UNIXWARE
+/* Sigh.  The static buffer in Unixware's readdir is too small. */
+struct dirent * readdir(DIR *d)
+{
+        static struct dirent *buf = NULL;
+#define MAX_PATH_LEN 1024
+
+
+        if(buf == NULL)
+                buf = (struct dirent *) malloc(sizeof(struct dirent) + MAX_PATH_LEN)
+;
+        return(readdir_r(d, buf));
+}
+#endif
+
+char *
+ino2name(ino_t ino, char *dir)
+{
+    DIR *dp;
+    struct dirent *ep;
+    char *name;
+
+    dp = opendir("..");
+    if (!dp)
+	fail("cannot read parent directory");
+    for (;;) {
+	if (!(ep = readdir(dp)))
+	    fail("cannot find current directory");
+	if (ep->d_ino == ino)
+	    break;
+    }
+    name = xstrdup(ep->d_name);
+    closedir(dp);
+    return name;
+}
+
+void *
+xmalloc(size_t size)
+{
+    void *p = malloc(size);
+    if (!p)
+	fail("cannot allocate %u bytes", size);
+    return p;
+}
+
+char *
+xstrdup(char *s)
+{
+    return strcpy((char*)xmalloc(strlen(s) + 1), s);
+}
+
+char *
+xbasename(char *path)
+{
+    char *cp;
+
+    while ((cp = strrchr(path, '/')) && cp[1] == '\0')
+	*cp = '\0';
+    if (!cp) return path;
+    return cp + 1;
+}
+
+void
+xchdir(char *dir)
+{
+    if (chdir(dir) < 0)
+	fail("cannot change directory to %s", dir);
+}
+
+int
+relatepaths(char *from, char *to, char *outpath)
+{
+    char *cp, *cp2;
+    int len;
+    char buf[NAME_MAX];
+
+    assert(*from == '/' && *to == '/');
+    for (cp = to, cp2 = from; *cp == *cp2; cp++, cp2++)
+	if (*cp == '\0')
+	    break;
+    while (cp[-1] != '/')
+	cp--, cp2--;
+    if (cp - 1 == to) {
+	/* closest common ancestor is /, so use full pathname */
+	len = strlen(strcpy(outpath, to));
+	if (outpath[len] != '/') {
+	    outpath[len++] = '/';
+	    outpath[len] = '\0';
+	}
+    } else {
+	len = 0;
+	while ((cp2 = getcomponent(cp2, buf)) != 0) {
+	    strcpy(outpath + len, "../");
+	    len += 3;
+	}
+	while ((cp = getcomponent(cp, buf)) != 0) {
+	    sprintf(outpath + len, "%s/", buf);
+	    len += strlen(outpath + len);
+	}
+    }
+    return len;
+}
+
+void
+reversepath(char *inpath, char *name, int len, char *outpath)
+{
+    char *cp, *cp2;
+    char buf[NAME_MAX];
+    struct stat sb;
+
+    cp = strcpy(outpath + PATH_MAX - (len + 1), name);
+    cp2 = inpath;
+    while ((cp2 = getcomponent(cp2, buf)) != 0) {
+	if (strcmp(buf, ".") == 0)
+	    continue;
+	if (strcmp(buf, "..") == 0) {
+	    if (stat(".", &sb) < 0)
+		fail("cannot stat current directory");
+	    name = ino2name(sb.st_ino, "..");
+	    len = strlen(name);
+	    cp -= len + 1;
+	    strcpy(cp, name);
+	    cp[len] = '/';
+	    free(name);
+	    xchdir("..");
+	} else {
+	    cp -= 3;
+	    strncpy(cp, "../", 3);
+	    xchdir(buf);
+	}
+    }
+    strcpy(outpath, cp);
+}
new file mode 100644
--- /dev/null
+++ b/config/pathsub.h
@@ -0,0 +1,59 @@
+/* -*- 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.
+ */
+
+#ifndef pathsub_h___
+#define pathsub_h___
+/*
+** Pathname subroutines.
+**
+** Brendan Eich, 8/29/95
+*/
+#include <limits.h>
+#include <sys/types.h>
+
+#if SUNOS4
+#include "../pr/include/md/sunos4.h"
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+/*
+ * Just prevent stupidity
+ */
+#undef NAME_MAX
+#define NAME_MAX 256
+
+extern char *program;
+
+extern void fail(char *format, ...);
+extern char *getcomponent(char *path, char *name);
+extern char *ino2name(ino_t ino, char *dir);
+extern void *xmalloc(size_t size);
+extern char *xstrdup(char *s);
+extern char *xbasename(char *path);
+extern void xchdir(char *dir);
+
+/* Relate absolute pathnames from and to returning the result in outpath. */
+extern int relatepaths(char *from, char *to, char *outpath);
+
+/* XXX changes current working directory -- caveat emptor */
+extern void reversepath(char *inpath, char *name, int len, char *outpath);
+
+#endif /* pathsub_h___ */
new file mode 100755
--- /dev/null
+++ b/config/prmkdir.bat
@@ -0,0 +1,18 @@
+REM
+REM The contents of this file are subject to the Netscape Public License
+REM Version 1.0 (the "NPL"); you may not use this file except in
+REM compliance with the NPL.  You may obtain a copy of the NPL at
+REM http://www.mozilla.org/NPL/
+REM 
+REM Software distributed under the NPL is distributed on an "AS IS" basis,
+REM WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+REM for the specific language governing rights and limitations under the
+REM NPL.
+REM 
+REM The Initial Developer of this code under the NPL is Netscape
+REM Communications Corporation.  Portions created by Netscape are
+REM Copyright (C) 1998 Netscape Communications Corporation.  All Rights
+REM Reserved.
+REM
+
+mkdir %1
new file mode 100644
--- /dev/null
+++ b/config/rules.mk
@@ -0,0 +1,366 @@
+#! gmake
+#
+# 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.
+#
+
+################################################################################
+# We have a 4 pass build process:
+#
+# Pass 1. export - Create generated headers and stubs. Publish public headers to
+#		dist/<arch>/include.
+#
+# Pass 2. libs - Create libraries. Publish libraries to dist/<arch>/lib.
+#
+# Pass 3. all - Create programs. 
+#
+# Pass 4. install - Publish programs to dist/<arch>/bin.
+#
+# Parameters to this makefile (set these before including):
+#
+# a)
+#	TARGETS	-- the target to create 
+#			(defaults to $LIBRARY $PROGRAM)
+# b)
+#	DIRS	-- subdirectories for make to recurse on
+#			(the 'all' rule builds $TARGETS $DIRS)
+# c)
+#	CSRCS   -- .c files to compile
+#			(used to define $OBJS)
+# d)
+#	PROGRAM	-- the target program name to create from $OBJS
+#			($OBJDIR automatically prepended to it)
+# e)
+#	LIBRARY	-- the target library name to create from $OBJS
+#			($OBJDIR automatically prepended to it)
+#
+################################################################################
+
+ifndef NSPR_CONFIG_MK
+include $(MOD_DEPTH)/config/config.mk
+endif
+
+#
+# This makefile contains rules for building the following kinds of
+# libraries:
+# - LIBRARY: a static (archival) library
+# - SHARED_LIBRARY: a shared (dynamic link) library
+# - IMPORT_LIBRARY: an import library, used only on Windows and OS/2
+# - PURE_LIBRARY: a library for Purify
+#
+# The names of these libraries can be generated by simply specifying
+# LIBRARY_NAME and LIBRARY_VERSION.
+#
+
+ifdef LIBRARY_NAME
+ifeq ($(OS_ARCH), WINNT)
+
+#
+# Win16 and OS/2 require library names conforming to the 8.3 rule.
+# other platforms do not.
+#
+ifeq (,$(filter-out WIN16 OS2,$(OS_TARGET)))
+LIBRARY		= $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION)_s.lib
+SHARED_LIBRARY	= $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION).dll
+IMPORT_LIBRARY	= $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION).lib
+else
+LIBRARY		= $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION)_s.lib
+SHARED_LIBRARY	= $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).dll
+IMPORT_LIBRARY	= $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).lib
+endif
+
+else
+
+LIBRARY		= $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(LIB_SUFFIX)
+ifeq ($(OS_ARCH)$(OS_RELEASE), AIX4.1)
+SHARED_LIBRARY	= $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION)_shr.a
+else
+SHARED_LIBRARY	= $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX)
+endif
+ifdef HAVE_PURIFY
+ifdef DSO_BACKEND
+PURE_LIBRARY	= $(OBJDIR)/purelib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX)
+else
+PURE_LIBRARY	= $(OBJDIR)/purelib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(LIB_SUFFIX)
+endif
+endif
+
+endif
+endif
+
+ifndef TARGETS
+ifeq ($(OS_ARCH), WINNT)
+TARGETS		= $(LIBRARY) $(SHARED_LIBRARY) $(IMPORT_LIBRARY)
+else
+TARGETS		= $(LIBRARY) $(SHARED_LIBRARY)
+ifdef HAVE_PURIFY
+TARGETS		+= $(PURE_LIBRARY)
+endif
+endif
+endif
+
+#
+# OBJS is the list of object files.  It can be constructed by
+# specifying CSRCS (list of C source files) and ASFILES (list
+# of assembly language source files).
+#
+
+ifndef OBJS
+OBJS		= $(addprefix $(OBJDIR)/,$(CSRCS:.c=.$(OBJ_SUFFIX))) \
+		  $(addprefix $(OBJDIR)/,$(ASFILES:.s=.$(OBJ_SUFFIX)))
+endif
+
+ifeq ($(OS_TARGET), WIN16)
+	comma := ,
+	empty :=
+	space := $(empty) $(empty)
+	W16OBJS = $(subst $(space),$(comma)$(space),$(strip $(OBJS)))
+	W16TEMP =$(OS_LIBS) $(EXTRA_LIBS)
+    ifeq ($(strip $(W16TEMP)),)
+		W16LIBS =
+    else
+		W16LIBS = library $(subst $(space),$(comma)$(space),$(strip $(W16TEMP)))
+    endif
+	W16DEF = $(notdir $(basename $(SHARED_LIBRARY))).DEF
+endif
+
+ifeq ($(OS_ARCH), WINNT)
+ifneq ($(OS_TARGET), WIN16)
+ifneq ($(OS_TARGET), OS2)
+OBJS += $(RES)
+endif
+endif
+endif
+
+ALL_TRASH		= $(TARGETS) $(OBJS) $(OBJDIR) LOGS TAGS $(GARBAGE) \
+			  $(NOSUCHFILE) \
+			  so_locations
+
+ifdef DIRS
+LOOP_OVER_DIRS		=					\
+	@for d in $(DIRS); do					\
+		if test -d $$d; then				\
+			set -e;					\
+			echo "cd $$d; $(MAKE) $@";		\
+			$(MAKE) -C $$d $@;			\
+			set +e;					\
+		else						\
+			echo "Skipping non-directory $$d...";	\
+		fi;						\
+	done
+endif
+
+################################################################################
+
+all:: export libs install
+
+export::
+	+$(LOOP_OVER_DIRS)
+
+libs::
+	+$(LOOP_OVER_DIRS)
+
+install::
+	+$(LOOP_OVER_DIRS)
+
+clean::
+	rm -rf $(OBJS) so_locations $(NOSUCHFILE)
+	+$(LOOP_OVER_DIRS)
+
+clobber::
+	rm -rf $(OBJS) $(TARGETS) $(OBJDIR) $(GARBAGE) so_locations $(NOSUCHFILE)
+	+$(LOOP_OVER_DIRS)
+
+realclean clobber_all::
+	rm -rf $(wildcard *.OBJ *.OBJD) dist $(ALL_TRASH)
+	+$(LOOP_OVER_DIRS)
+
+release:: export
+ifdef RELEASE_LIBS
+	@echo "Copying libraries to release directory"
+	@if test -z "$(BUILD_NUMBER)"; then \
+		echo "BUILD_NUMBER must be defined"; \
+		false; \
+	fi
+	@if test ! -d $(RELEASE_LIB_DIR); then \
+		rm -rf $(RELEASE_LIB_DIR); \
+		$(NSINSTALL) -D $(RELEASE_LIB_DIR);\
+	fi
+	cp $(RELEASE_LIBS) $(RELEASE_LIB_DIR)
+endif
+ifdef RELEASE_HEADERS
+	@echo "Copying header files to release directory"
+	@if test -z "$(BUILD_NUMBER)"; then \
+		echo "BUILD_NUMBER must be defined"; \
+		false; \
+	fi
+	@if test ! -d $(RELEASE_HEADERS_DEST); then \
+		rm -rf $(RELEASE_HEADERS_DEST); \
+		$(NSINSTALL) -D $(RELEASE_HEADERS_DEST);\
+	fi
+	cp $(RELEASE_HEADERS) $(RELEASE_HEADERS_DEST)
+endif
+	+$(LOOP_OVER_DIRS)
+
+alltags:
+	rm -f TAGS tags
+	find . -name dist -prune -o \( -name '*.[hc]' -o -name '*.cp' -o -name '*.cpp' \) -print | xargs etags -a
+	find . -name dist -prune -o \( -name '*.[hc]' -o -name '*.cp' -o -name '*.cpp' \) -print | xargs ctags -a
+
+$(NFSPWD):
+	cd $(@D); $(MAKE) $(@F)
+
+$(PROGRAM): $(OBJS)
+	@$(MAKE_OBJDIR)
+ifeq ($(OS_ARCH),WINNT)
+	$(CC) $(OBJS) -Fe$@ -link $(LDFLAGS) $(OS_LIBS) $(EXTRA_LIBS)
+else
+	$(CC) -o $@ $(CFLAGS) $(OBJS) $(LDFLAGS)
+endif
+
+$(LIBRARY): $(OBJS)
+	@$(MAKE_OBJDIR)
+	rm -f $@
+	$(AR) $(OBJS) $(AR_EXTRA_ARGS)
+	$(RANLIB) $@
+
+ifeq ($(OS_TARGET), WIN16)
+$(IMPORT_LIBRARY): $(SHARED_LIBRARY)
+	wlib $(OS_LIB_FLAGS) $@ +$(SHARED_LIBRARY)
+endif
+
+ifeq ($(OS_TARGET), OS2)
+$(IMPORT_LIBRARY): $(SHARED_LIBRARY)
+	$(IMPLIB) $@ $(SHARED_LIBRARY).def
+endif
+    
+$(SHARED_LIBRARY): $(OBJS)
+	@$(MAKE_OBJDIR)
+	rm -f $@
+ifeq ($(OS_ARCH)$(OS_RELEASE), AIX4.1)
+	echo "#!" > $(OBJDIR)/lib$(LIBRARY_NAME)_syms
+	nm -B -C -g $(OBJS) \
+		| awk '/ [T,D] / {print $$3}' \
+		| sed -e 's/^\.//' \
+		| sort -u >> $(OBJDIR)/lib$(LIBRARY_NAME)_syms
+	$(LD) $(XCFLAGS) -o $@ $(OBJS) -bE:$(OBJDIR)/lib$(LIBRARY_NAME)_syms \
+		-bM:SRE -bnoentry $(OS_LIBS) $(EXTRA_LIBS)
+else
+ifeq ($(OS_ARCH), WINNT)
+ifeq ($(OS_TARGET), WIN16)
+	echo system windows dll initinstance >w16link
+	echo option map >>w16link
+	echo option oneautodata >>w16link
+	echo option heapsize=32K >>w16link
+	echo option $(OS_DLL_OPTION) >>w16link
+	echo debug $(DEBUGTYPE) all >>w16link
+	echo name $@ >>w16link
+	echo file >>w16link
+	echo $(W16OBJS) >>w16link
+	echo $(W16IMPORTS) >>w16link
+	echo $(W16LIBS) >>w16link
+	echo $(W16_EXPORTS) >>w16link
+	echo libfile libentry >>w16link
+	$(LINK) @w16link.
+	rm w16link
+else
+ifeq ($(OS_TARGET), OS2)
+# append ( >> ) doesn't seem to be working under OS/2 gmake. Run through OS/2 shell instead.	
+	@cmd /C "echo LIBRARY $(notdir $(basename $(SHARED_LIBRARY))) INITINSTANCE TERMINSTANCE >$@.def"
+	@cmd /C "echo PROTMODE >>$@.def"
+	@cmd /C "echo CODE    LOADONCALL MOVEABLE DISCARDABLE >>$@.def"
+	@cmd /C "echo DATA    PRELOAD MOVEABLE MULTIPLE NONSHARED >>$@.def"	
+	@cmd /C "echo EXPORTS >>$@.def"
+	@cmd /C "$(FILTER) -B -P $(LIBRARY) >> $@.def"
+	$(LINK_DLL) -MAP $(DLLBASE) $(OS_LIBS) $(EXTRA_LIBS) $(OBJS) $@.def
+else
+	$(LINK_DLL) -MAP $(DLLBASE) $(OS_LIBS) $(EXTRA_LIBS) $(OBJS)
+endif
+endif
+else
+	$(MKSHLIB) -o $@ $(OBJS) $(EXTRA_LIBS) $(OS_LIBS)
+endif
+endif
+
+$(PURE_LIBRARY):
+	rm -f $@
+ifneq ($(OS_ARCH), WINNT)
+	$(AR) $(OBJS)
+endif
+	$(RANLIB) $@
+
+ifeq ($(OS_ARCH), WINNT)
+$(RES): $(RESNAME)
+	@$(MAKE_OBJDIR)
+ifeq ($(OS_TARGET),OS2)
+	$(RC) -DOS2 -r $(RESNAME) $(RES)
+else
+	$(RC) -Fo$(RES) $(RESNAME)
+endif
+	@echo $(RES) finished
+endif
+
+$(OBJDIR)/%.$(OBJ_SUFFIX): %.cpp
+	@$(MAKE_OBJDIR)
+ifeq ($(OS_ARCH), WINNT)
+	$(CCC) -Fo$@ -c $(CFLAGS) $<
+else
+	$(CCC) -o $@ -c $(CFLAGS) $< 
+endif
+
+WCCFLAGS1 = $(subst /,\\,$(CFLAGS))
+WCCFLAGS2 = $(subst -I,-i=,$(WCCFLAGS1))
+WCCFLAGS3 = $(subst -D,-d,$(WCCFLAGS2))
+$(OBJDIR)/%.$(OBJ_SUFFIX): %.c
+	@$(MAKE_OBJDIR)
+ifeq ($(OS_ARCH), WINNT)
+ifeq ($(OS_TARGET), WIN16)
+#	$(MOD_DEPTH)/config/w16opt $(WCCFLAGS3)
+	echo $(WCCFLAGS3) >w16wccf
+	$(CC) -zq -fo$(OBJDIR)\\$*.$(OBJ_SUFFIX)  @w16wccf $*.c
+	rm w16wccf
+else
+	$(CC) -Fo$@ -c $(CFLAGS) $*.c
+endif
+else
+	$(CC) -o $@ -c $(CFLAGS) $*.c
+endif
+
+$(OBJDIR)/%.$(OBJ_SUFFIX): %.s
+	@$(MAKE_OBJDIR)
+	$(AS) -o $@ $(ASFLAGS) -c $*.s
+
+%.i: %.c
+	$(CC) -C -E $(CFLAGS) $< > $*.i
+
+%: %.pl
+	rm -f $@; cp $*.pl $@; chmod +x $@
+
+################################################################################
+# Special gmake rules.
+################################################################################
+
+#
+# Re-define the list of default suffixes, so gmake won't have to churn through
+# hundreds of built-in suffix rules for stuff we don't need.
+#
+.SUFFIXES:
+.SUFFIXES: .a .$(OBJ_SUFFIX) .c .cpp .s .h .i .pl
+
+#
+# Fake targets.  Always run these rules, even if a file/directory with that
+# name already exists.
+#
+.PHONY: all alltags clean export install libs realclean release
new file mode 100644
--- /dev/null
+++ b/config/win16.mk
@@ -0,0 +1,99 @@
+#
+# 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.
+#
+
+#
+# win16_3.11.mk -- Make configuration for Win16
+#
+# This file configures gmake to build the Win16 variant of
+# NSPR 2.0. This file has the function of two files commonly
+# used on other platforms, for example: winnt.mk and
+# winnt4.0.mk. ... The packaging is easier and there is only
+# one variant of the Win16 target.
+# 
+# Win16 is built using the Watcom C/C++ version 11.0
+# compiler. You gotta set up the compiler first. Follow the
+# directions in the manual (Ha! ... really, its not a
+# problem). The Watcom compiler depends on a few environment
+# variables; these environment variables define where the
+# compiler components are installed; they must be set before
+# running the make.
+# 
+# Notes:
+# OS_CFLAGS is the command line options for the compiler when
+#   building the .DLL object files.
+# OS_EXE_CFLAGS is the command line options for the compiler
+#   when building the .EXE object files; this is for the test
+#   programs.
+# the macro OS_CFLAGS is set to OS_EXE_CFLAGS inside of the
+#   makefile for the pr/tests directory. ... Hack.
+# 
+# USE_WATCOM_DEBUG_DATA environment variable causes the
+#   watcom compiler flag to be set to -hw (otherwise
+#   it is set to -hc (codeview debug data)) for debug builds.
+#
+
+# -- configuration -----------------------------------------
+
+CC = wcc
+CCC = wcl
+LINK = wlink
+AR = wlib -q $@
+RC = wrc.exe /r /dWIN16=1 /bt=windows
+RANLIB = echo
+BSDECHO = echo
+NSINSTALL = nsinstall
+INSTALL	= $(NSINSTALL)
+MAKE_OBJDIR = mkdir $(OBJDIR)
+
+XP_DEFINE = -DXP_PC
+OBJ_SUFFIX = obj
+LIB_SUFFIX = lib
+DLL_SUFFIX = dll
+
+ifdef BUILD_OPT
+OBJDIR_TAG = _O
+OPTIMIZER = -oneatx -oh -oi -ei -3 -fpi87 -fp3 -s
+else
+ifdef USE_WATCOM_DEBUG_DATA
+OPTIMIZER = -d2 -hw -s -DDEBUG
+DEBUGTYPE = watcom
+else
+OPTIMIZER = -d2 -hc -s -DDEBUG
+DEBUGTYPE = codeview
+endif
+OBJDIR_TAG = _D
+endif
+
+# XXX FIXME: I doubt we use this.  It is redundant with
+# SHARED_LIBRARY.
+ifdef DLL
+DLL := $(addprefix $(OBJDIR)/, $(DLL))
+endif
+
+
+CPU_ARCH = x386
+OS_CFLAGS = -ml -3 -bd -zc -zu -bt=windows -d_X86_ -dWIN16 -d_WINDLL
+OS_EXE_CFLAGS = -ml -3 -bt=windows -d_X86_ -dWIN16
+OS_LIB_FLAGS = -c -iro -n
+
+# Name of the binary code directories
+OBJDIR_NAME     = $(OS_CONFIG)$(OBJDIR_TAG).OBJ
+
+OS_DLL_OPTION = CASEEXACT
+OS_DLLFLAGS =
+OS_LIBS =
+W16_EXPORTS = #
new file mode 100644
--- /dev/null
+++ b/lib/Makefile
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+
+#! gmake
+
+MOD_DEPTH = ..
+
+export NSPR20=1
+
+include $(MOD_DEPTH)/config/config.mk
+
+DIRS = ds libc msgc
+
+include $(MOD_DEPTH)/config/rules.mk
+
+export:: $(TARGETS)
+
+install:: export
new file mode 100644
--- /dev/null
+++ b/lib/ds/MANIFEST
@@ -0,0 +1,8 @@
+#
+# This is a list of local files which get copied to the mozilla:dist directory
+#
+
+plarenas.h
+plarena.h
+plevent.h
+plhash.h
new file mode 100644
--- /dev/null
+++ b/lib/libc/Makefile
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+
+#! gmake
+
+MOD_DEPTH = ../..
+
+export NSPR20=1
+
+include $(MOD_DEPTH)/config/config.mk
+
+DIRS = include src
+
+include $(MOD_DEPTH)/config/rules.mk
+
+export:: $(TARGETS)
+
+install:: export
new file mode 100644
--- /dev/null
+++ b/lib/libc/README
@@ -0,0 +1,20 @@
+NSPR 2.0 libc functions
+-----------------------
+
+Last edited: AOF 04 March 1997
+
+This directory contains various libc-types of functions. All functions in
+this directory are platform independent, thread friendly (both safe and
+efficient). They are contributed from various sources, though the contri-
+butions are monitored by the NSPR group (mailto:freier).
+
+All API items exported by these functions will contain the same three
+character prefix, "PL_" (Portable Library). Internal function names
+that are not exported (static) are of little concern, though some caution
+must be used on those elements that are 'extern' but not really intended
+to be part of the API. Those should all have a prefix of "_PL_" (is that
+legal?).
+
+The responsibility for contributions in this area are distributed among
+all interested parties.
+
new file mode 100644
--- /dev/null
+++ b/lib/libc/include/MANIFEST
@@ -0,0 +1,9 @@
+#
+# This is a list of local files which get copied to the mozilla:dist directory
+#
+
+plbase64.h
+plerror.h
+plgetopt.h
+plresolv.h
+plstr.h
new file mode 100644
--- /dev/null
+++ b/lib/libc/src/Makefile
@@ -0,0 +1,105 @@
+#
+# 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.
+#
+
+#! gmake
+
+MOD_DEPTH = ../../..
+
+include $(MOD_DEPTH)/config/config.mk
+
+# Disable optimization of the nspr on SunOS4.1.3
+ifeq ($(OS_ARCH),SunOS)
+ifeq ($(OS_RELEASE),4.1.3_U1)
+OPTIMIZER =
+endif
+endif
+
+INCLUDES = -I$(DIST)/include
+
+CSRCS =\
+	strlen.c  \
+	strcpy.c  \
+	strdup.c  \
+	strcat.c  \
+	strcmp.c  \
+	strccmp.c \
+	strchr.c  \
+	strpbrk.c \
+	strstr.c  \
+	strcstr.c \
+	base64.c \
+	plerror.c \
+	plgetopt.c \
+	$(NULL)
+
+LIBRARY_NAME	= plc
+LIBRARY_VERSION	= $(MOD_VERSION)
+
+RELEASE_LIBS = $(TARGETS)
+
+ifeq ($(OS_ARCH),WINNT)
+ifeq (,$(filter-out WIN16 OS2,$(OS_TARGET)))
+EXTRA_LIBS = $(DIST)/lib/nspr$(MOD_VERSION).lib
+else
+DLLBASE=/BASE:0x30000000
+RES=$(OBJDIR)/plc.res
+RESNAME=$(MOD_DEPTH)/pr/src/nspr.rc
+EXTRA_LIBS = $(DIST)/lib/libnspr$(MOD_VERSION).lib
+endif
+else
+ifeq ($(OS_ARCH), AIX)
+ifeq ($(CLASSIC_NSPR),1)
+OS_LIBS += -lc
+else
+OS_LIBS += -lc_r
+endif
+endif
+ifeq ($(OS_ARCH)$(OS_RELEASE), AIX4.1)
+EXTRA_LIBS = -L$(DIST)/lib -lnspr$(MOD_VERSION)_shr
+else
+EXTRA_LIBS = -L$(DIST)/lib -lnspr$(MOD_VERSION)
+endif
+endif
+
+# On NCR and SCOOS, we can't link with extra libraries when
+# we build a shared library.  If we do so, the linker doesn't
+# complain, but we would run into weird problems at run-time.
+# Therefore on these platforms, we link just the .o files.
+ifeq ($(OS_ARCH),NCR)
+EXTRA_LIBS =
+endif
+ifeq ($(OS_ARCH),SCOOS)
+EXTRA_LIBS =
+endif
+
+include $(MOD_DEPTH)/config/rules.mk
+
+#
+# The Client build wants the shared libraries in $(DIST)/bin,
+# so we also install them there.
+#
+
+export:: $(TARGETS)
+	$(INSTALL) -m 444 $(TARGETS) $(DIST)/lib
+	$(INSTALL) -m 444 $(SHARED_LIBRARY) $(DIST)/bin
+ifeq ($(MOZ_BITS),16)
+	$(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/lib
+	$(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/bin
+endif
+
+install:: export
+
new file mode 100644
--- /dev/null
+++ b/lib/libc/src/README
@@ -0,0 +1,20 @@
+NSPR 2.0 libc functions
+-----------------------
+
+Last edited: AOF 04 March 1997
+
+This directory contains various libc-types of functions. All functions in
+this directory are platform independent, thread friendly (both safe and
+efficient). They are contributed from various sources, though the contri-
+butions are monitored by the NSPR group (mailto:freier).
+
+All API items exported by these functions will contain the same three
+character prefix, "PL_" (Portable Library). Internal function names
+that are not exported (static) are of little concern, though some caution
+must be used on those elements that are 'extern' but not really intended
+to be part of the API. Those should all have a prefix of "_PL_" (is that
+legal?).
+
+The responsibility for contributions in this area are distributed among
+all interested parties.
+
new file mode 100644
--- /dev/null
+++ b/lib/libc/src/base64.c
@@ -0,0 +1,403 @@
+/* -*- 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.
+ */
+
+#include "plbase64.h"
+#include "prlog.h" /* For PR_NOT_REACHED */
+#include "prmem.h" /* for malloc / PR_MALLOC */
+#include "plstr.h" /* for PL_strlen */
+
+static unsigned char *base = (unsigned char *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static void
+encode3to4
+(
+    const unsigned char    *src,
+    unsigned char          *dest
+)
+{
+    PRUint32 b32 = (PRUint32)0;
+    PRIntn i, j = 18;
+
+    for( i = 0; i < 3; i++ )
+    {
+        b32 <<= 8;
+        b32 |= (PRUint32)src[i];
+    }
+
+    for( i = 0; i < 4; i++ )
+    {
+        dest[i] = base[ (PRUint32)((b32>>j) & 0x3F) ];
+        j -= 6;
+    }
+
+    return;
+}
+
+static void
+encode2to4
+(
+    const unsigned char    *src,
+    unsigned char          *dest
+)
+{
+    dest[0] = base[ (PRUint32)((src[0]>>2) & 0x3F) ];
+    dest[1] = base[ (PRUint32)(((src[0] & 0x03) << 4) | ((src[1] >> 4) & 0x0F)) ];
+    dest[2] = base[ (PRUint32)((src[1] & 0x0F) << 2) ];
+    dest[3] = (unsigned char)'=';
+    return;
+}
+
+static void
+encode1to4
+(
+    const unsigned char    *src,
+    unsigned char          *dest
+)
+{
+    dest[0] = base[ (PRUint32)((src[0]>>2) & 0x3F) ];
+    dest[1] = base[ (PRUint32)((src[0] & 0x03) << 4) ];
+    dest[2] = (unsigned char)'=';
+    dest[3] = (unsigned char)'=';
+    return;
+}
+
+static void
+encode
+(
+    const unsigned char    *src,
+    PRUint32                srclen,
+    unsigned char          *dest
+)
+{
+    while( srclen >= 3 )
+    {
+        encode3to4(src, dest);
+        src += 3;
+        dest += 4;
+        srclen -= 3;
+    }
+
+    switch( srclen )
+    {
+        case 2:
+            encode2to4(src, dest);
+            break;
+        case 1:
+            encode1to4(src, dest);
+            break;
+        case 0:
+            break;
+        default:
+            PR_NOT_REACHED("coding error");
+    }
+
+    return;
+}
+
+/*
+ * PL_Base64Encode
+ *
+ * If the destination argument is NULL, a return buffer is 
+ * allocated, and the data therein will be null-terminated.  
+ * If the destination argument is not NULL, it is assumed to
+ * be of sufficient size, and the contents will not be null-
+ * terminated by this routine.
+ *
+ * Returns null if the allocation fails.
+ */
+
+PR_IMPLEMENT(char *)
+PL_Base64Encode
+(
+    const char *src,
+    PRUint32    srclen,
+    char       *dest
+)
+{
+    if( 0 == srclen )
+    {
+        srclen = PL_strlen(src);
+    }
+
+    if( (char *)0 == dest )
+    {
+        PRUint32 destlen = ((srclen + 2)/3) * 4;
+        dest = (char *)PR_MALLOC(destlen + 1);
+        if( (char *)0 == dest )
+        {
+            return (char *)0;
+        }
+        dest[ destlen ] = (char)0; /* null terminate */
+    }
+
+    encode((const unsigned char *)src, srclen, (unsigned char *)dest);
+    return dest;
+}
+
+static PRInt32
+codetovalue
+(
+    unsigned char c
+)
+{
+    if( (c >= (unsigned char)'A') && (c <= (unsigned char)'Z') )
+    {
+        return (PRInt32)(c - (unsigned char)'A');
+    }
+    else if( (c >= (unsigned char)'a') && (c <= (unsigned char)'z') )
+    {
+        return ((PRInt32)(c - (unsigned char)'a') +26);
+    }
+    else if( (c >= (unsigned char)'0') && (c <= (unsigned char)'9') )
+    {
+        return ((PRInt32)(c - (unsigned char)'0') +52);
+    }
+    else if( (unsigned char)'+' == c )
+    {
+        return (PRInt32)62;
+    }
+    else if( (unsigned char)'/' == c )
+    {
+        return (PRInt32)63;
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+static PRStatus
+decode4to3
+(
+    const unsigned char    *src,
+    unsigned char          *dest
+)
+{
+    PRUint32 b32 = (PRUint32)0;
+    PRInt32 bits;
+    PRIntn i;
+
+    for( i = 0; i < 4; i++ )
+    {
+        bits = codetovalue(src[i]);
+        if( bits < 0 )
+        {
+            return PR_FAILURE;
+        }
+
+        b32 <<= 6;
+        b32 |= bits;
+    }
+
+    dest[0] = (unsigned char)((b32 >> 16) & 0xFF);
+    dest[1] = (unsigned char)((b32 >>  8) & 0xFF);
+    dest[2] = (unsigned char)((b32      ) & 0xFF);
+
+    return PR_SUCCESS;
+}
+
+static PRStatus
+decode3to2
+(
+    const unsigned char    *src,
+    unsigned char          *dest
+)
+{
+    PRUint32 b32 = (PRUint32)0;
+    PRInt32 bits;
+    PRUint32 ubits;
+
+    bits = codetovalue(src[0]);
+    if( bits < 0 )
+    {
+        return PR_FAILURE;
+    }
+
+    b32 = (PRUint32)bits;
+    b32 <<= 6;
+
+    bits = codetovalue(src[1]);
+    if( bits < 0 )
+    {
+        return PR_FAILURE;
+    }
+
+    b32 |= (PRUint32)bits;
+    b32 <<= 4;
+
+    bits = codetovalue(src[2]);
+    if( bits < 0 )
+    {
+        return PR_FAILURE;
+    }
+
+    ubits = (PRUint32)bits;
+    b32 |= (ubits >> 2);
+
+    dest[0] = (unsigned char)((b32 >> 8) & 0xFF);
+    dest[1] = (unsigned char)((b32     ) & 0xFF);
+
+    return PR_SUCCESS;
+}
+
+static PRStatus
+decode2to1
+(
+    const unsigned char    *src,
+    unsigned char          *dest
+)
+{
+    PRUint32 b32;
+    PRUint32 ubits;
+    PRInt32 bits;
+
+    bits = codetovalue(src[0]);
+    if( bits < 0 )
+    {
+        return PR_FAILURE;
+    }
+
+    ubits = (PRUint32)bits;
+    b32 = (ubits << 2);
+
+    bits = codetovalue(src[1]);
+    if( bits < 0 )
+    {
+        return PR_FAILURE;
+    }
+
+    ubits = (PRUint32)bits;
+    b32 |= (ubits >> 4);
+
+    dest[0] = (unsigned char)b32;
+
+    return PR_SUCCESS;
+}
+
+static PRStatus
+decode
+(
+    const unsigned char    *src,
+    PRUint32                srclen,
+    unsigned char          *dest
+)
+{
+    PRStatus rv;
+
+    while( srclen >= 4 )
+    {
+        rv = decode4to3(src, dest);
+        if( PR_SUCCESS != rv )
+        {
+            return PR_FAILURE;
+        }
+
+        src += 4;
+        dest += 3;
+        srclen -= 4;
+    }
+
+    switch( srclen )
+    {
+        case 3:
+            rv = decode3to2(src, dest);
+            break;
+        case 2:
+            rv = decode2to1(src, dest);
+            break;
+        case 1:
+            rv = PR_FAILURE;
+            break;
+        case 0:
+            break;
+        default:
+            PR_NOT_REACHED("coding error");
+    }
+
+    return rv;
+}
+
+/*
+ * PL_Base64Decode
+ *
+ * If the destination argument is NULL, a return buffer is
+ * allocated and the data therein will be null-terminated.
+ * If the destination argument is not null, it is assumed
+ * to be of sufficient size, and the data will not be null-
+ * terminated by this routine.
+ * 
+ * Returns null if the allocation fails, or if the source string is 
+ * not well-formed.
+ */
+
+PR_IMPLEMENT(char *)
+PL_Base64Decode
+(
+    const char *src,
+    PRUint32    srclen,
+    char       *dest
+)
+{
+    PRStatus status;
+    PRBool allocated = PR_FALSE;
+
+    if( 0 == srclen )
+    {
+        srclen = PL_strlen(src);
+    }
+
+    if( 0 == (srclen & 3) )
+    {
+        if( (char)'=' == src[ srclen-1 ] )
+        {
+            if( (char)'=' == src[ srclen-2 ] )
+            {
+                srclen -= 2;
+            }
+            else
+            {
+                srclen -= 1;
+            }
+        }
+    }
+
+    if( (char *)0 == dest )
+    {
+        PRUint32 destlen = ((srclen * 3) / 4);
+        dest = (char *)PR_MALLOC(destlen + 1);
+        if( (char *)0 == dest )
+        {
+            return (char *)0;
+        }
+        dest[ destlen ] = (char)0; /* null terminate */
+        allocated = PR_TRUE;
+    }
+
+    status = decode((const unsigned char *)src, srclen, (unsigned char *)dest);
+    if( PR_SUCCESS != status )
+    {
+        if( PR_TRUE == allocated )
+        {
+            PR_DELETE(dest);
+        }
+
+        return (char *)0;
+    }
+
+    return dest;
+}
new file mode 100644
--- /dev/null
+++ b/lib/libc/src/plerror.c
@@ -0,0 +1,144 @@
+/* -*- 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:plerror.c
+** Description: Simple routine to print translate the calling thread's
+**  error numbers and print them to "syserr".
+*/
+
+#include "plerror.h"
+
+#include "prprf.h"
+#include "prerror.h"
+
+PR_IMPLEMENT(void) PL_FPrintError(PRFileDesc *fd, const char *msg)
+{
+static const char *tags[] =
+{
+    "PR_OUT_OF_MEMORY_ERROR",
+    "PR_BAD_DESCRIPTOR_ERROR", 
+    "PR_WOULD_BLOCK_ERROR",
+    "PR_ACCESS_FAULT_ERROR", 
+    "PR_INVALID_METHOD_ERROR", 
+    "PR_ILLEGAL_ACCESS_ERROR", 
+    "PR_UNKNOWN_ERROR",
+    "PR_PENDING_INTERRUPT_ERROR",
+    "PR_NOT_IMPLEMENTED_ERROR",
+    "PR_IO_ERROR", 
+    "PR_IO_TIMEOUT_ERROR", 
+    "PR_IO_PENDING_ERROR", 
+    "PR_DIRECTORY_OPEN_ERROR", 
+    "PR_INVALID_ARGUMENT_ERROR", 
+    "PR_ADDRESS_NOT_AVAILABLE_ERROR",
+    "PR_ADDRESS_NOT_SUPPORTED_ERROR",
+    "PR_IS_CONNECTED_ERROR", 
+    "PR_BAD_ADDRESS_ERROR",
+    "PR_ADDRESS_IN_USE_ERROR", 
+    "PR_CONNECT_REFUSED_ERROR",
+    "PR_NETWORK_UNREACHABLE_ERROR",
+    "PR_CONNECT_TIMEOUT_ERROR",
+    "PR_NOT_CONNECTED_ERROR",
+    "PR_LOAD_LIBRARY_ERROR", 
+    "PR_UNLOAD_LIBRARY_ERROR", 
+    "PR_FIND_SYMBOL_ERROR",
+    "PR_INSUFFICIENT_RESOURCES_ERROR", 
+    "PR_DIRECTORY_LOOKUP_ERROR", 
+    "PR_TPD_RANGE_ERROR",
+    "PR_PROC_DESC_TABLE_FULL_ERROR", 
+    "PR_SYS_DESC_TABLE_FULL_ERROR",
+    "PR_NOT_SOCKET_ERROR", 
+    "PR_NOT_TCP_SOCKET_ERROR", 
+    "PR_SOCKET_ADDRESS_IS_BOUND_ERROR",
+    "PR_NO_ACCESS_RIGHTS_ERROR", 
+    "PR_OPERATION_NOT_SUPPORTED_ERROR",
+    "PR_PROTOCOL_NOT_SUPPORTED_ERROR", 
+    "PR_REMOTE_FILE_ERROR",
+    "PR_BUFFER_OVERFLOW_ERROR",
+    "PR_CONNECT_RESET_ERROR",
+    "PR_RANGE_ERROR",
+    "PR_DEADLOCK_ERROR", 
+    "PR_FILE_IS_LOCKED_ERROR", 
+    "PR_FILE_TOO_BIG_ERROR", 
+    "PR_NO_DEVICE_SPACE_ERROR",
+    "PR_PIPE_ERROR", 
+    "PR_NO_SEEK_DEVICE_ERROR", 
+    "PR_IS_DIRECTORY_ERROR", 
+    "PR_LOOP_ERROR", 
+    "PR_NAME_TOO_LONG_ERROR",
+    "PR_FILE_NOT_FOUND_ERROR", 
+    "PR_NOT_DIRECTORY_ERROR",
+    "PR_READ_ONLY_FILESYSTEM_ERROR", 
+    "PR_DIRECTORY_NOT_EMPTY_ERROR",
+    "PR_FILESYSTEM_MOUNTED_ERROR", 
+    "PR_NOT_SAME_DEVICE_ERROR",
+    "PR_DIRECTORY_CORRUPTED_ERROR",
+    "PR_FILE_EXISTS_ERROR",
+    "PR_MAX_DIRECTORY_ENTRIES_ERROR",
+    "PR_INVALID_DEVICE_STATE_ERROR", 
+    "PR_DEVICE_IS_LOCKED_ERROR", 
+    "PR_NO_MORE_FILES_ERROR",
+    "PR_END_OF_FILE_ERROR",
+    "PR_FILE_SEEK_ERROR",
+    "PR_FILE_IS_BUSY_ERROR", 
+    "PR_IN_PROGRESS_ERROR",
+    "PR_ALREADY_INITIATED_ERROR",
+    "PR_GROUP_EMPTY_ERROR",
+    "PR_INVALID_STATE_ERROR",
+    "PR_MAX_ERROR"
+};
+
+PRErrorCode error = PR_GetError();
+PRInt32 oserror = PR_GetOSError();
+PRIntn thoseIKnowAbout = sizeof(tags) / sizeof(char*);
+PRIntn lastError = PR_NSPR_ERROR_BASE + thoseIKnowAbout;
+
+	if (NULL != msg) PR_fprintf(fd, "%s: ", msg);
+    if ((error < PR_NSPR_ERROR_BASE) || (error > lastError))
+        PR_fprintf(
+			fd, " (%d)OUT OF RANGE, oserror = %d\n", error, oserror);
+    else
+        PR_fprintf(
+            fd, "%s(%d), oserror = %d\n",
+            tags[error - PR_NSPR_ERROR_BASE], error, oserror);
+}  /* PL_FPrintError */
+
+PR_IMPLEMENT(void) PL_PrintError(const char *msg)
+{
+	static PRFileDesc *fd = NULL;
+	if (NULL == fd) fd = PR_GetSpecialFD(PR_StandardError);
+	PL_FPrintError(fd, msg);
+}  /* PL_PrintError */
+
+#if defined(WIN16)
+/*
+** libmain() is a required function for win16
+**
+*/
+int CALLBACK LibMain( HINSTANCE hInst, WORD wDataSeg, 
+  WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+return TRUE;
+}
+#endif /* WIN16 */
+
+
+
+
+
+/* plerror.c */
new file mode 100644
--- /dev/null
+++ b/lib/libc/src/plgetopt.c
@@ -0,0 +1,165 @@
+/* -*- 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:          plgetopt.c
+** Description:   utilities to parse argc/argv
+*/
+
+#include "prmem.h"
+#include "prlog.h"
+#include "prerror.h"
+#include "plstr.h"
+#include "plgetopt.h"
+
+#include <string.h>
+
+static char static_Nul = 0;
+
+struct PLOptionInternal
+{
+    const char *options;        /* client options list specification */
+    PRIntn argc;                /* original number of arguments */
+    char **argv;                /* vector of pointers to arguments */
+    PRIntn xargc;               /* which one we're processing now */
+    const char *xargv;          /* where within *argv[xargc] */
+    PRBool minus;               /* do we already have the '-'? */
+};
+
+/*
+** Create the state in which to parse the tokens.
+**
+** argc        the sum of the number of options and their values
+** argv        the options and their values
+** options    vector of single character options w/ | w/o ':
+*/
+PR_IMPLEMENT(PLOptState*) PL_CreateOptState(
+    PRIntn argc, char **argv, const char *options)
+{
+    PLOptState *opt = NULL;
+    if (NULL == options)
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+    else
+    {
+        opt = PR_NEWZAP(PLOptState);
+        if (NULL == opt)
+            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        else
+        {
+            PLOptionInternal *internal = PR_NEW(PLOptionInternal);
+            if (NULL == internal)
+            {
+                PR_DELETE(opt);
+                PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+            }
+            else
+            {
+				opt->option = 0;
+				opt->value = NULL;
+				opt->internal = internal;
+
+                internal->argc = argc;
+                internal->argv = argv;
+                internal->xargc = 0;
+                internal->xargv = &static_Nul;
+                internal->minus = PR_FALSE;
+                internal->options = options;
+            }
+        }
+    }
+    return opt;
+}  /* PL_CreateOptState */
+
+/*
+** Destroy object created by CreateOptState()
+*/
+PR_IMPLEMENT(void) PL_DestroyOptState(PLOptState *opt)
+{
+    PR_DELETE(opt->internal);
+    PR_DELETE(opt);
+}  /* PL_DestroyOptState */
+
+PR_IMPLEMENT(PLOptStatus) PL_GetNextOpt(PLOptState *opt)
+{
+    PLOptionInternal *internal = opt->internal;
+    PRIntn cop, eoo = PL_strlen(internal->options);
+
+    /*
+    ** If the current xarg points to nul, advance to the next
+    ** element of the argv vector. If the vector index is equal
+    ** to argc, we're out of arguments, so return an EOL.
+	** Note whether the first character of the new argument is
+	** a '-' and skip by it if it is.
+    */
+    while (0 == *internal->xargv)
+    {
+        internal->xargc += 1;
+        if (internal->xargc >= internal->argc)
+		{
+			opt->option = 0;
+			opt->value = NULL;
+			return PL_OPT_EOL;
+		}
+        internal->xargv = internal->argv[internal->xargc];
+		internal->minus = ('-' == *internal->xargv ? PR_TRUE : PR_FALSE);  /* not it */
+		if (internal->minus) internal->xargv += 1;  /* and consume */
+    }
+
+    /*
+    ** If we already have a '-' in hand, xargv points to the next
+    ** option. See if we can find a match in the list of possible
+    ** options supplied.
+    */
+
+    if (internal->minus)
+    {
+        for (cop = 0; cop < eoo; ++cop)
+        {
+            if (internal->options[cop] == *internal->xargv)
+            {
+                opt->option = *internal->xargv;
+                internal->xargv += 1;
+                /*
+                ** if options indicates that there's an associated
+				** value, this argv is finished and the next is the
+				** option's value.
+                */
+                if (':' == internal->options[cop + 1])
+                {
+					PR_ASSERT(0 == *internal->xargv);
+                    opt->value = internal->argv[++(internal->xargc)];
+                    internal->xargv = &static_Nul;
+                    internal->minus = PR_FALSE;
+                }
+				else opt->value = NULL;
+                return PL_OPT_OK;
+            }
+        }
+        internal->xargv += 1;  /* consume that option */
+        return PL_OPT_BAD;
+    }
+    /*
+    ** No '-', so it must be a standalone value. The option is nul.
+    */
+    opt->value = internal->argv[(internal->xargc)++];
+    internal->xargv = &static_Nul;
+    opt->option = 0;
+    return PL_OPT_OK;
+}  /* PL_GetNextOpt */
+
+/* plgetopt.c */
new file mode 100644
--- /dev/null
+++ b/lib/libc/src/strcat.c
@@ -0,0 +1,70 @@
+/* -*- 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.
+ */
+
+#include "plstr.h"
+
+PR_IMPLEMENT(char *)
+PL_strcat(char *dest, const char *src)
+{
+    char *rv;
+    
+    if( (char *)0 == dest ) return (char *)0;
+    if( (const char *)0 == src ) return dest;
+
+    for( rv = dest; *dest; dest++ )
+        ;
+
+    for( ; ((*dest = *src) != 0); dest++, src++ )
+        ;
+
+    return rv;
+}
+
+PR_IMPLEMENT(char *)
+PL_strncat(char *dest, const char *src, PRUint32 max)
+{
+    char *rv;
+
+    if( (char *)0 == dest ) return (char *)0;
+    if( (const char *)0 == src ) return dest;
+    if( 0 == max ) return dest;
+
+    for( rv = dest; *dest; dest++ )
+        ;
+
+    (void)PL_strncpy(dest, src, max);
+    return rv;
+}
+
+PR_IMPLEMENT(char *)
+PL_strcatn(char *dest, PRUint32 max, const char *src)
+{
+    char *rv;
+    PRUint32 dl;
+
+    if( (char *)0 == dest ) return (char *)0;
+    if( (const char *)0 == src ) return dest;
+
+    for( rv = dest, dl = 0; *dest; dest++, dl++ )
+        ;
+
+    if( max <= dl ) return rv;
+    (void)PL_strncpyz(dest, src, max-dl);
+
+    return rv;
+}
new file mode 100644
--- /dev/null
+++ b/lib/libc/src/strccmp.c
@@ -0,0 +1,80 @@
+/* -*- 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.
+ */
+
+#include "plstr.h"
+
+static const unsigned char uc[] =
+{
+    '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+    '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+    '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+    '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+    ' ',    '!',    '"',    '#',    '$',    '%',    '&',    '\'',
+    '(',    ')',    '*',    '+',    ',',    '-',    '.',    '/',
+    '0',    '1',    '2',    '3',    '4',    '5',    '6',    '7',
+    '8',    '9',    ':',    ';',    '<',    '=',    '>',    '?',
+    '@',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
+    'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
+    'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
+    'X',    'Y',    'Z',    '[',    '\\',   ']',    '^',    '_',
+    '`',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
+    'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
+    'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
+    'X',    'Y',    'Z',    '{',    '|',    '}',    '~',    '\177'
+};
+
+PR_IMPLEMENT(PRIntn)
+PL_strcasecmp(const char *a, const char *b)
+{
+    const unsigned char *ua = (const unsigned char *)a;
+    const unsigned char *ub = (const unsigned char *)b;
+
+    if( ((const char *)0 == a) || (const char *)0 == b ) 
+        return (PRIntn)(a-b);
+
+    while( (uc[*ua] == uc[*ub]) && ('\0' != *a) )
+    {
+        a++;
+        ua++;
+        ub++;
+    }
+
+    return (PRIntn)(uc[*ua] - uc[*ub]);
+}
+
+PR_IMPLEMENT(PRIntn)
+PL_strncasecmp(const char *a, const char *b, PRUint32 max)
+{
+    const unsigned char *ua = (const unsigned char *)a;
+    const unsigned char *ub = (const unsigned char *)b;
+
+    if( ((const char *)0 == a) || (const char *)0 == b ) 
+        return (PRIntn)(a-b);
+
+    while( max && (uc[*ua] == uc[*ub]) && ('\0' != *a) )
+    {
+        a++;
+        ua++;
+        ub++;
+        max--;
+    }
+
+    if( 0 == max ) return (PRIntn)0;
+
+    return (PRIntn)(uc[*ua] - uc[*ub]);
+}
new file mode 100644
--- /dev/null
+++ b/lib/libc/src/strchr.c
@@ -0,0 +1,83 @@
+/* -*- 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.
+ */
+
+#include "plstr.h"
+
+PR_IMPLEMENT(char *)
+PL_strchr(const char *s, char c)
+{
+    if( (const char *)0 == s ) return (char *)0;
+
+    for( ; *s; s++ )
+        if( *s == c )
+            return (char *)s;
+
+    if( (char)0 == c ) return (char *)s;
+
+    return (char *)0;
+}
+
+PR_IMPLEMENT(char *)
+PL_strrchr(const char *s, char c)
+{
+    const char *p;
+
+    if( (const char *)0 == s ) return (char *)0;
+
+    for( p = s; *p; p++ )
+        ;
+
+    for( ; p >= s; p-- )
+        if( *p == c )
+            return (char *)p;
+
+    return (char *)0;
+}
+
+PR_IMPLEMENT(char *)
+PL_strnchr(const char *s, char c, PRUint32 n)
+{
+    if( (const char *)0 == s ) return (char *)0;
+
+    for( ; *s && n; s++, n-- )
+        if( *s == c )
+            return (char *)s;
+
+    if( ((char)0 == c) && ((char)0 == *s) && (n > 0)) return (char *)s;
+
+    return (char *)0;
+}
+
+PR_IMPLEMENT(char *)
+PL_strnrchr(const char *s, char c, PRUint32 n)
+{
+    const char *p;
+
+    if( (const char *)0 == s ) return (char *)0;
+
+    for( p = s; *p && n; p++, n-- )
+        ;
+
+    if( ((char)0 == c) && ((char)0 == *p) && (n > 0) ) return (char *)p;
+
+    for( p--; p >= s; p-- )
+        if( *p == c )
+            return (char *)p;
+
+    return (char *)0;
+}
new file mode 100644
--- /dev/null
+++ b/lib/libc/src/strcmp.c
@@ -0,0 +1,52 @@
+/* -*- 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.
+ */
+
+#include "plstr.h"
+
+PR_IMPLEMENT(PRIntn)
+PL_strcmp(const char *a, const char *b)
+{
+    if( ((const char *)0 == a) || (const char *)0 == b ) 
+        return (PRIntn)(a-b);
+
+    while( (*a == *b) && ('\0' != *a) )
+    {
+        a++;
+        b++;
+    }
+
+    return (PRIntn)(*((const unsigned char *)a) - *((const unsigned char *)b));
+}
+
+PR_IMPLEMENT(PRIntn)
+PL_strncmp(const char *a, const char *b, PRUint32 max)
+{
+    if( ((const char *)0 == a) || (const char *)0 == b ) 
+        return (PRIntn)(a-b);
+
+    while( max && (*a == *b) && ('\0' != *a) )
+    {
+        a++;
+        b++;
+        max--;
+    }
+
+    if( 0 == max ) return (PRIntn)0;
+
+    return (PRIntn)(*((const unsigned char *)a) - *((const unsigned char *)b));
+}
new file mode 100644
--- /dev/null
+++ b/lib/libc/src/strcpy.c
@@ -0,0 +1,69 @@
+/* -*- 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.
+ */
+
+#include "plstr.h"
+
+PR_IMPLEMENT(char *)
+PL_strcpy(char *dest, const char *src)
+{
+    char *rv;
+    
+    if( (char *)0 == dest ) return (char *)0;
+    if( (const char *)0 == src ) return (char *)0;
+
+    for( rv = dest; ((*dest = *src) != 0); dest++, src++ )
+        ;
+
+    return rv;
+}
+
+PR_IMPLEMENT(char *)
+PL_strncpy(char *dest, const char *src, PRUint32 max)
+{
+    char *rv;
+    
+    if( (char *)0 == dest ) return (char *)0;
+    if( (const char *)0 == src ) return (char *)0;
+
+    for( rv = dest; max && ((*dest = *src) != 0); dest++, src++, max-- )
+        ;
+
+#ifdef JLRU
+    while( --max )
+        *++dest = '\0';
+#endif /* JLRU */
+
+    return rv;
+}
+
+PR_IMPLEMENT(char *)
+PL_strncpyz(char *dest, const char *src, PRUint32 max)
+{
+    char *rv;
+    
+    if( (char *)0 == dest ) return (char *)0;
+    if( (const char *)0 == src ) return (char *)0;
+    if( 0 == max ) return (char *)0;
+
+    for( rv = dest, max--; max && ((*dest = *src) != 0); dest++, src++, max-- )
+        ;
+
+    *dest = '\0';
+
+    return rv;
+}
new file mode 100644
--- /dev/null
+++ b/lib/libc/src/strcstr.c
@@ -0,0 +1,104 @@
+/* -*- 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.
+ */
+
+#include "plstr.h"
+
+PR_IMPLEMENT(char *)
+PL_strcasestr(const char *big, const char *little)
+{
+    PRUint32 ll;
+
+    if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0;
+    if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0;
+
+    ll = PL_strlen(little);
+
+    for( ; *big; big++ )
+        /* obvious improvement available here */
+            if( 0 == PL_strncasecmp(big, little, ll) )
+                return (char *)big;
+
+    return (char *)0;
+}
+
+PR_IMPLEMENT(char *)
+PL_strcaserstr(const char *big, const char *little)
+{
+    const char *p;
+    PRUint32 ll;
+
+    if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0;
+    if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0;
+
+    ll = PL_strlen(little);
+    p = &big[ PL_strlen(big) - ll ];
+    if( p < big ) return (char *)0;
+
+    for( ; p >= big; p-- )
+        /* obvious improvement available here */
+            if( 0 == PL_strncasecmp(p, little, ll) )
+                return (char *)p;
+
+    return (char *)0;
+}
+
+PR_IMPLEMENT(char *)
+PL_strncasestr(const char *big, const char *little, PRUint32 max)
+{
+    PRUint32 ll;
+
+    if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0;
+    if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0;
+
+    ll = PL_strlen(little);
+    if( ll > max ) return (char *)0;
+    max -= ll;
+    max++;
+
+    for( ; *big && max; big++, max-- )
+        /* obvious improvement available here */
+            if( 0 == PL_strncasecmp(big, little, ll) )
+                return (char *)big;
+
+    return (char *)0;
+}
+
+PR_IMPLEMENT(char *)
+PL_strncaserstr(const char *big, const char *little, PRUint32 max)
+{
+    const char *p;
+    PRUint32 ll;
+
+    if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0;
+    if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0;
+
+    ll = PL_strlen(little);
+
+    for( p = big; *p && max; p++, max-- )
+        ;
+
+    p -= ll;
+    if( p < big ) return (char *)0;
+
+    for( ; p >= big; p-- )
+        /* obvious improvement available here */
+            if( 0 == PL_strncasecmp(p, little, ll) )
+                return (char *)p;
+
+    return (char *)0;
+}
new file mode 100644
--- /dev/null
+++ b/lib/libc/src/strdup.c
@@ -0,0 +1,64 @@
+/* -*- 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.
+ */
+
+#include "plstr.h"
+#include "prmem.h"
+
+PR_IMPLEMENT(char *)
+PL_strdup(const char *s)
+{
+    char *rv;
+    PRUint32 l;
+
+    l = PL_strlen(s);
+
+    rv = (char *)malloc(l+1);
+    if( (char *)0 == rv ) return rv;
+
+    if( (const char *)0 == s )
+        *rv = '\0';
+    else
+        (void)PL_strcpy(rv, s);
+
+    return rv;
+}
+
+PR_IMPLEMENT(void)
+PL_strfree(char *s)
+{
+	free(s);
+}
+
+PR_IMPLEMENT(char *)
+PL_strndup(const char *s, PRUint32 max)
+{
+    char *rv;
+    PRUint32 l;
+
+    l = PL_strnlen(s, max);
+
+    rv = (char *)malloc(l+1);
+    if( (char *)0 == rv ) return rv;
+
+    if( (const char *)0 == s )
+        *rv = '\0';
+    else
+        (void)PL_strncpyz(rv, s, l+1);
+
+    return rv;
+}
new file mode 100644
--- /dev/null
+++ b/lib/libc/src/strlen.c
@@ -0,0 +1,50 @@
+/* -*- 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.
+ */
+
+#include "plstr.h"
+#include "prtypes.h"
+#include "prlog.h"
+
+PR_IMPLEMENT(PRUint32)
+PL_strlen(const char *str)
+{
+    register const char *s;
+
+    if( (const char *)0 == str ) return 0;
+    for( s = str; *s; s++ )
+        ;
+/* error checking in case we have a 64-bit platform -- make sure we dont
+ * have ultra long strings that overflow a int32
+ */ 
+    if (sizeof(PRUint32) < sizeof(PRUptrdiff))
+        PR_ASSERT((s-str) < 2147483647);
+
+    return (PRUint32)(s - str);
+}
+
+PR_IMPLEMENT(PRUint32)
+PL_strnlen(const char *str, PRUint32 max)
+{
+    register const char *s;
+
+    if( (const char *)0 == str ) return 0;
+    for( s = str; *s && max; s++, max-- )
+        ;
+
+    return (PRUint32)(s - str);
+}
new file mode 100644
--- /dev/null
+++ b/lib/libc/src/strpbrk.c
@@ -0,0 +1,87 @@
+/* -*- 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.
+ */
+
+#include "plstr.h"
+
+PR_IMPLEMENT(char *)
+PL_strpbrk(const char *s, const char *list)
+{
+    const char *p;
+
+    if( ((const char *)0 == s) || ((const char *)0 == list) ) return (char *)0;
+
+    for( ; *s; s++ )
+        for( p = list; *p; p++ )
+            if( *s == *p )
+                return (char *)s;
+
+    return (char *)0;
+}
+
+PR_IMPLEMENT(char *)
+PL_strprbrk(const char *s, const char *list)
+{
+    const char *p;
+    const char *r;
+
+    if( ((const char *)0 == s) || ((const char *)0 == list) ) return (char *)0;
+
+    for( r = s; *r; r++ )
+        ;
+
+    for( r--; r >= s; r-- )
+        for( p = list; *p; p++ )
+            if( *r == *p )
+                return (char *)r;
+
+    return (char *)0;
+}
+
+PR_IMPLEMENT(char *)
+PL_strnpbrk(const char *s, const char *list, PRUint32 max)
+{
+    const char *p;
+
+    if( ((const char *)0 == s) || ((const char *)0 == list) ) return (char *)0;
+
+    for( ; *s && max; s++, max-- )
+        for( p = list; *p; p++ )
+            if( *s == *p )
+                return (char *)s;
+
+    return (char *)0;
+}
+
+PR_IMPLEMENT(char *)
+PL_strnprbrk(const char *s, const char *list, PRUint32 max)
+{
+    const char *p;
+    const char *r;
+
+    if( ((const char *)0 == s) || ((const char *)0 == list) ) return (char *)0;
+
+    for( r = s; *r && max; r++, max-- )
+        ;
+
+    for( r--; r >= s; r-- )
+        for( p = list; *p; p++ )
+            if( *r == *p )
+                return (char *)r;
+
+    return (char *)0;
+}
new file mode 100644
--- /dev/null
+++ b/lib/libc/src/strstr.c
@@ -0,0 +1,104 @@
+/* -*- 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.
+ */
+
+#include "plstr.h"
+
+PR_IMPLEMENT(char *)
+PL_strstr(const char *big, const char *little)
+{
+    PRUint32 ll;
+
+    if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0;
+    if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0;
+
+    ll = PL_strlen(little);
+
+    for( ; *big; big++ )
+        if( *little == *big )
+            if( 0 == PL_strncmp(big, little, ll) )
+                return (char *)big;
+
+    return (char *)0;
+}
+
+PR_IMPLEMENT(char *)
+PL_strrstr(const char *big, const char *little)
+{
+    const char *p;
+    PRUint32 ll;
+
+    if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0;
+    if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0;
+
+    ll = PL_strlen(little);
+    p = &big[ PL_strlen(big) - ll ];
+    if( p < big ) return (char *)0;
+
+    for( ; p >= big; p-- )
+        if( *little == *p )
+            if( 0 == PL_strncmp(p, little, ll) )
+                return (char *)p;
+
+    return (char *)0;
+}
+
+PR_IMPLEMENT(char *)
+PL_strnstr(const char *big, const char *little, PRUint32 max)
+{
+    PRUint32 ll;
+
+    if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0;
+    if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0;
+
+    ll = PL_strlen(little);
+    if( ll > max ) return (char *)0;
+    max -= ll;
+    max++;
+
+    for( ; *big && max; big++, max-- )
+        if( *little == *big )
+            if( 0 == PL_strncmp(big, little, ll) )
+                return (char *)big;
+
+    return (char *)0;
+}
+
+PR_IMPLEMENT(char *)
+PL_strnrstr(const char *big, const char *little, PRUint32 max)
+{
+    const char *p;
+    PRUint32 ll;
+
+    if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0;
+    if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0;
+
+    ll = PL_strlen(little);
+
+    for( p = big; *p && max; p++, max-- )
+        ;
+
+    p -= ll;
+    if( p < big ) return (char *)0;
+
+    for( ; p >= big; p-- )
+        if( *little == *p )
+            if( 0 == PL_strncmp(p, little, ll) )
+                return (char *)p;
+
+    return (char *)0;
+}
new file mode 100644
--- /dev/null
+++ b/lib/msgc/Makefile
@@ -0,0 +1,28 @@
+#
+# 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.
+#
+
+MOD_DEPTH = ../..
+
+include $(MOD_DEPTH)/config/config.mk
+
+DIRS = include src tests
+
+include $(MOD_DEPTH)/config/rules.mk
+
+export:: $(TARGETS)
+
+install:: export
new file mode 100644
--- /dev/null
+++ b/lib/msgc/include/MANIFEST
@@ -0,0 +1,5 @@
+#
+# This is a list of local files which get copied to the mozilla:dist directory
+#
+
+prgc.h
new file mode 100644
--- /dev/null
+++ b/lib/msgc/src/Makefile
@@ -0,0 +1,107 @@
+#
+# 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.
+#
+
+#! gmake
+
+MOD_DEPTH = ../../..
+
+include $(MOD_DEPTH)/config/config.mk
+
+# Disable optimization of the nspr on SunOS4.1.3
+ifeq ($(OS_ARCH),SunOS)
+ifeq ($(OS_RELEASE),4.1.3_U1)
+OPTIMIZER =
+endif
+endif
+
+INCLUDES = -I$(DIST)/include -I../include
+
+CSRCS = prgcapi.c prmsgc.c
+
+ifeq ($(OS_ARCH),WINNT)
+ifeq ($(OS_TARGET),WIN16)
+CSRCS += win16gc.c
+else
+ifeq ($(OS_TARGET),OS2)
+CSRCS += os2gc.c
+else
+CSRCS += win32gc.c
+endif
+endif
+else
+CSRCS += unixgc.c
+endif
+
+NSPR_VERSION = $(MOD_VERSION)
+
+ifeq ($(OS_ARCH), WINNT)
+ifeq (,$(filter-out WIN16 OS2,$(OS_TARGET)))
+EXTRA_LIBS = $(DIST)/lib/nspr$(NSPR_VERSION).lib
+else
+DLLBASE=/BASE:0x30000000
+#RES=$(OBJDIR)/ds.res
+#RESNAME=$(MOD_DEPTH)/pr/src/nspr.rc
+#OS_LIBS = user32.lib
+EXTRA_LIBS = $(DIST)/lib/libnspr$(NSPR_VERSION).lib
+endif
+else
+ifeq ($(OS_ARCH), AIX)
+ifeq ($(CLASSIC_NSPR),1)
+OS_LIBS += -lc
+else
+OS_LIBS += -lc_r
+endif
+endif
+ifeq ($(OS_ARCH)$(OS_RELEASE), AIX4.1)
+EXTRA_LIBS = -L$(DIST)/lib -lnspr$(NSPR_VERSION)_shr
+else
+EXTRA_LIBS = -L$(DIST)/lib -lnspr$(NSPR_VERSION)
+endif
+endif
+
+# On NCR and SCOOS, we can't link with extra libraries when
+# we build a shared library.  If we do so, the linker doesn't
+# complain, but we would run into weird problems at run-time.
+# Therefore on these platforms, we link just the .o files.
+ifeq ($(OS_ARCH),NCR)
+EXTRA_LIBS =
+endif
+ifeq ($(OS_ARCH),SCOOS)
+EXTRA_LIBS =
+endif
+
+LIBRARY_NAME = msgc
+LIBRARY_VERSION = $(MOD_VERSION)
+
+RELEASE_LIBS = $(TARGETS)
+
+include $(MOD_DEPTH)/config/rules.mk
+
+#
+# The Client build wants the shared libraries in $(DIST)/bin,
+# so we also install them there.
+#
+
+export:: $(TARGETS)
+	$(INSTALL) -m 444 $(TARGETS) $(DIST)/lib
+	$(INSTALL) -m 444 $(SHARED_LIBRARY) $(DIST)/bin
+ifeq ($(MOZ_BITS),16)
+	$(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/lib
+	$(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/bin
+endif	
+
+install:: export
new file mode 100644
--- /dev/null
+++ b/lib/msgc/src/macgc.c
@@ -0,0 +1,56 @@
+/* -*- 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.
+ */
+
+#include "primpl.h"
+#include "MacMemAllocator.h"
+
+void _MD_InitGC() {}
+
+void *_MD_GrowGCHeap(size_t *sizep)
+{
+	void			*heapPtr = NULL;
+	size_t			heapSize = *sizep;
+	
+	// In previous versions of this code we tried to allocate GC heaps from the application
+	// heap.  In the 4.0 application, we try to keep our app heap allications to a minimum
+	// and instead go through our own memory allocation routines.
+	heapPtr = malloc(heapSize);
+	
+	if (heapPtr == NULL) {		
+		FreeMemoryStats		stats;
+		
+		memtotal(heapSize, &stats);		// How much can we allcoate?
+		
+		if (stats.maxBlockSize < heapSize)
+			heapSize = stats.maxBlockSize;
+		
+		heapPtr = malloc(heapSize);
+		
+		if (heapPtr == NULL) 			// Now we're hurting
+			heapSize = 0;
+	}
+	
+	*sizep = heapSize;
+	return heapPtr;
+}
+
+
+void _MD_FreeGCSegment(void *base, int32 /* len */)
+{
+	free(base);
+}
new file mode 100644
--- /dev/null
+++ b/lib/msgc/src/os2gc.c
@@ -0,0 +1,64 @@
+/* -*- 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.
+ */
+
+/*
+ * GC related routines
+ *
+ */
+#include "prlog.h"
+
+#include <stdlib.h>
+
+/* Leave a bit of room for any malloc header bytes... */
+#define MAX_SEGMENT_SIZE    (65536L - 4096L)
+
+/************************************************************************/
+/*
+** Machine dependent GC Heap management routines:
+**    _MD_GrowGCHeap
+*/
+/************************************************************************/
+void _MD_InitGC() {}
+
+void *_MD_GrowGCHeap(PRUint32 *sizep)
+{
+    void *addr;
+
+    if ( *sizep > MAX_SEGMENT_SIZE )
+    {
+        *sizep = MAX_SEGMENT_SIZE;
+    }
+
+    addr = malloc((size_t)*sizep);
+    return addr;
+}
+
+
+PRBool _MD_ExtendGCHeap(char *base, PRInt32 oldSize, PRInt32 newSize) {
+  /* Not sure about this.  Todd?  */
+  return PR_FALSE;
+}
+
+
+void _MD_FreeGCSegment(void *base, PRInt32 len)
+{
+   if (base)
+   {
+       free(base);
+   }
+}
new file mode 100644
--- /dev/null
+++ b/lib/msgc/src/prgcapi.c
@@ -0,0 +1,332 @@
+/* -*- 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.
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include "prenv.h"
+#include "prmem.h"
+#include "prmon.h"
+#include "prlog.h"
+#include "prthread.h"
+#if defined(XP_MAC)
+#include "pprthred.h"
+#else
+#include "private/pprthred.h"
+#endif
+#include "gcint.h"
+
+/*
+** Generic GC implementation independent code for the NSPR GC
+*/
+
+RootFinder *_pr_rootFinders;
+
+CollectorType *_pr_collectorTypes;
+
+/* GC State information */
+GCInfo _pr_gcData;
+
+GCBeginGCHook *_pr_beginGCHook;
+void *_pr_beginGCHookArg;
+GCBeginGCHook *_pr_endGCHook;
+void *_pr_endGCHookArg;
+
+GCBeginFinalizeHook *_pr_beginFinalizeHook;
+void *_pr_beginFinalizeHookArg;
+GCBeginFinalizeHook *_pr_endFinalizeHook;
+void *_pr_endFinalizeHookArg;
+
+FILE *_pr_dump_file;
+int _pr_do_a_dump;
+GCLockHook *_pr_GCLockHook;
+
+extern PRLogModuleInfo *_pr_msgc_lm;
+
+/************************************************************************/
+
+static PRStatus PR_CALLBACK
+pr_ScanOneThread(PRThread* t, void** addr, PRUword count, void* closure)
+{
+#if defined(XP_MAC)
+#pragma unused (t, closure)
+#endif
+
+    _pr_gcData.processRootBlock(addr, count);
+    return PR_SUCCESS;
+}
+
+/*
+** Scan all of the threads C stack's and registers, looking for "root"
+** pointers into the GC heap. These are the objects that the GC cannot
+** move and are considered "live" by the GC. Caller has stopped all of
+** the threads from running.
+*/
+static void PR_CALLBACK ScanThreads(void *arg)
+{
+    PR_ScanStackPointers(pr_ScanOneThread, arg);
+}
+
+/************************************************************************/
+
+PR_IMPLEMENT(GCInfo *) PR_GetGCInfo(void)
+{
+    return &_pr_gcData;
+}
+
+
+PR_IMPLEMENT(PRInt32) PR_RegisterType(GCType *t)
+{
+    CollectorType *ct, *ect;
+    int rv = -1;
+
+    LOCK_GC();
+    ct = &_pr_collectorTypes[0];
+    ect = &_pr_collectorTypes[FREE_MEMORY_TYPEIX];
+    for (; ct < ect; ct++) {
+	if (ct->flags == 0) {
+	    ct->gctype = *t;
+	    ct->flags = _GC_TYPE_BUSY;
+	    if (0 != ct->gctype.finalize) {
+		ct->flags |= _GC_TYPE_FINAL;
+	    }
+	    if (0 != ct->gctype.getWeakLinkOffset) {
+		ct->flags |= _GC_TYPE_WEAK;
+	    }
+	    rv = ct - &_pr_collectorTypes[0];
+	    break;
+	}
+    }
+    UNLOCK_GC();
+    return rv;
+}
+
+PR_IMPLEMENT(PRStatus) PR_RegisterRootFinder(
+    GCRootFinder f, char *name, void *arg)
+{
+    RootFinder *rf = PR_NEWZAP(RootFinder);
+    if (rf) {
+	    rf->func = f;
+	    rf->name = name;
+	    rf->arg = arg;
+
+	    LOCK_GC();
+	    rf->next = _pr_rootFinders;
+	    _pr_rootFinders = rf;
+	    UNLOCK_GC();
+	    return PR_SUCCESS;
+    }
+    return PR_FAILURE;
+}
+
+
+PR_IMPLEMENT(int) PR_RegisterGCLockHook(GCLockHookFunc* f, void *arg)
+{
+
+    GCLockHook *rf = 0;
+
+    rf = (GCLockHook*) calloc(1, sizeof(GCLockHook));
+    if (rf) {
+	rf->func = f;
+	rf->arg = arg;
+
+	LOCK_GC();
+        /* first dummy node */
+        if (! _pr_GCLockHook) {
+          _pr_GCLockHook = (GCLockHook*) calloc(1, sizeof(GCLockHook));
+          _pr_GCLockHook->next = _pr_GCLockHook;
+          _pr_GCLockHook->prev = _pr_GCLockHook;
+        }
+
+        rf->next = _pr_GCLockHook;
+        rf->prev = _pr_GCLockHook->prev;
+        _pr_GCLockHook->prev->next = rf;
+        _pr_GCLockHook->prev = rf;
+	UNLOCK_GC();
+	return 0;
+    }
+    return -1;
+}
+
+/*
+PR_IMPLEMENT(void) PR_SetGCLockHook(GCLockHook *hook, void *arg)
+{
+    LOCK_GC();
+    _pr_GCLockHook = hook;
+    _pr_GCLockHookArg2 = arg;
+    UNLOCK_GC();
+}
+
+PR_IMPLEMENT(void) PR_GetGCLockHook(GCLockHook **hook, void **arg)
+{
+    LOCK_GC();
+    *hook = _pr_GCLockHook;
+    *arg = _pr_GCLockHookArg2;
+    UNLOCK_GC();
+}
+*/
+
+  
+PR_IMPLEMENT(void) PR_SetBeginGCHook(GCBeginGCHook *hook, void *arg)
+{
+    LOCK_GC();
+    _pr_beginGCHook = hook;
+    _pr_beginGCHookArg = arg;
+    UNLOCK_GC();
+}
+
+PR_IMPLEMENT(void) PR_GetBeginGCHook(GCBeginGCHook **hook, void **arg)
+{
+    LOCK_GC();
+    *hook = _pr_beginGCHook;
+    *arg = _pr_beginGCHookArg;
+    UNLOCK_GC();
+}
+
+PR_IMPLEMENT(void) PR_SetEndGCHook(GCEndGCHook *hook, void *arg)
+{
+    LOCK_GC();
+    _pr_endGCHook = hook;
+    _pr_endGCHookArg = arg;
+    UNLOCK_GC();
+}
+
+PR_IMPLEMENT(void) PR_GetEndGCHook(GCEndGCHook **hook, void **arg)
+{
+    LOCK_GC();
+    *hook = _pr_endGCHook;
+    *arg = _pr_endGCHookArg;
+    UNLOCK_GC();
+}
+
+PR_IMPLEMENT(void) PR_SetBeginFinalizeHook(GCBeginFinalizeHook *hook, void *arg)
+{
+    LOCK_GC();
+    _pr_beginFinalizeHook = hook;
+    _pr_beginFinalizeHookArg = arg;
+    UNLOCK_GC();
+}
+
+PR_IMPLEMENT(void) PR_GetBeginFinalizeHook(GCBeginFinalizeHook **hook, 
+                                           void **arg)
+{
+    LOCK_GC();
+    *hook = _pr_beginFinalizeHook;
+    *arg = _pr_beginFinalizeHookArg;
+    UNLOCK_GC();
+}
+
+PR_IMPLEMENT(void) PR_SetEndFinalizeHook(GCEndFinalizeHook *hook, void *arg)
+{
+    LOCK_GC();
+    _pr_endFinalizeHook = hook;
+    _pr_endFinalizeHookArg = arg;
+    UNLOCK_GC();
+}
+
+PR_IMPLEMENT(void) PR_GetEndFinalizeHook(GCEndFinalizeHook **hook, void **arg)
+{
+    LOCK_GC();
+    *hook = _pr_endFinalizeHook;
+    *arg = _pr_endFinalizeHookArg;
+    UNLOCK_GC();
+}
+
+#ifdef DEBUG
+#include "prprf.h"
+
+#if defined(WIN16)
+static FILE *tracefile = 0;
+#endif
+
+PR_IMPLEMENT(void) GCTrace(char *fmt, ...)
+{	
+    va_list ap;
+    char buf[400];
+
+    va_start(ap, fmt);
+    PR_vsnprintf(buf, sizeof(buf), fmt, ap);
+    va_end(ap);
+#if defined(WIN16)
+    if ( tracefile == 0 )
+    {
+        tracefile = fopen( "xxxGCtr", "w" );
+    }
+    fprintf(tracefile, "%s\n", buf );
+    fflush(tracefile);
+#else
+    PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, ("%s", buf));
+#endif
+}
+#endif
+
+void _PR_InitGC(PRWord flags)
+{
+    static char firstTime = 1;
+
+    if (!firstTime) return;
+    firstTime = 0;
+
+    _MD_InitGC();
+
+    if (flags == 0) {
+	char *ev = PR_GetEnv("GCLOG");
+	if (ev && ev[0]) {
+	    flags = atoi(ev);
+	}
+    }
+    _pr_gcData.flags = flags;
+
+    _pr_gcData.lock = PR_NewMonitor();
+
+    _pr_collectorTypes = (CollectorType*) PR_CALLOC(256 * sizeof(CollectorType));
+
+    PR_RegisterRootFinder(ScanThreads, "scan threads", 0);
+    PR_RegisterRootFinder(_PR_ScanFinalQueue, "scan final queue", 0);
+}
+
+extern void pr_FinalizeOnExit(void);
+
+#ifdef DEBUG
+#ifdef GC_STATS
+PR_PUBLIC_API(void) PR_PrintGCAllocStats(void);
+#endif 
+#endif 
+  
+PR_IMPLEMENT(void) 
+PR_ShutdownGC(PRBool finalizeOnExit)
+{
+    /* first finalize all the objects in the heap */
+    if (finalizeOnExit) {
+        pr_FinalizeOnExit();
+    }
+
+#ifdef DEBUG
+#ifdef GC_STATS
+    PR_PrintGCAllocStats();
+#endif /* GC_STATS */
+#endif /* DEBUG */
+
+    /* then the chance for any future allocations */
+
+    /* finally delete the gc heap */
+
+    /* write me */
+}
+
+/******************************************************************************/
new file mode 100644
--- /dev/null
+++ b/lib/msgc/src/prmsgc.c
@@ -0,0 +1,3478 @@
+/* -*- 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.
+ */
+
+#include <string.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <time.h>
+
+#ifdef WIN32
+#include <windef.h>
+#include <winbase.h>
+#endif
+
+#include "prclist.h"
+#include "prbit.h"
+
+#include "prtypes.h"
+#include "prenv.h"
+#include "prgc.h"
+#include "prthread.h"
+#include "prlog.h"
+#include "prlong.h"
+#include "prinrval.h"
+#include "prprf.h"
+#include "gcint.h"
+
+#if defined(XP_MAC)
+#include "pprthred.h"
+#else
+#include "private/pprthred.h"
+#endif
+
+typedef void (*PRFileDumper)(FILE *out, PRBool detailed);
+
+PR_EXTERN(void)
+PR_DumpToFile(char* filename, char* msg, PRFileDumper dump, PRBool detailed);
+
+/*
+** Mark&sweep garbage collector. Supports objects that require
+** finalization, objects that can have a single weak link, and special
+** objects that require care during sweeping.
+*/
+
+PRLogModuleInfo *_pr_msgc_lm;
+PRLogModuleInfo* GC;
+
+static PRInt32 _pr_pageShift;
+static PRInt32 _pr_pageSize;
+
+#ifdef DEBUG
+#define GCMETER
+#endif
+#ifdef DEBUG_jwz
+# undef GCMETER
+#endif /* 1 */
+
+#ifdef GCMETER
+#define METER(x) x
+#else
+#define METER(x)
+#endif
+
+/*
+** Make this constant bigger to reduce the amount of recursion during
+** garbage collection.
+*/
+#define MAX_SCAN_Q    100L
+
+#if defined(XP_PC) && !defined(WIN32)
+#define MAX_SEGS            400L
+#define MAX_SEGMENT_SIZE    (65536L - 4096L)
+#define SEGMENT_SIZE        (65536L - 4096L)
+#define MAX_ALLOC_SIZE      (65536L - 4096L)
+#else
+#define MAX_SEGS                    400L
+#define MAX_SEGMENT_SIZE            (2L * 256L * 1024L)
+#define SEGMENT_SIZE                (1L * 256L * 1024L)
+#define MAX_ALLOC_SIZE              (4L * 1024L * 1024L)
+#endif  
+
+/* 
+ * The highest value that can fit into a signed integer. This
+ * is used to prevent overflow of allocation size in alloc routines.
+ */
+ 
+#define MAX_INT ((1UL << (PR_BITS_PER_INT - 1)) - 1)
+
+/* 
+ * On 32-bit machines, only 22 bits are used in the cibx integer to
+ * store size since 8 bits of the integer are used to store type, and
+ * of the remainder, 2 are user defined. Max allocation size = 2^22 -1
+ */
+
+#define MAX_ALLOC ( (1L << (PR_BYTES_PER_WORD_LOG2 + WORDS_BITS )) -1)
+
+/* The minimum percentage of free heap space after a collection. If
+   the amount of free space doesn't meet this criteria then we will
+   attempt to grow the heap */
+#ifdef XP_MAC
+#define MIN_FREE_THRESHOLD_AFTER_GC 10L
+#else
+#define MIN_FREE_THRESHOLD_AFTER_GC 20L
+#endif
+
+static PRInt32 segmentSize = SEGMENT_SIZE;
+
+static PRInt32 collectorCleanupNeeded;
+
+#ifdef GCMETER
+PRUint32 _pr_gcMeter;
+
+#define _GC_METER_STATS         0x01L
+#define _GC_METER_GROWTH        0x02L
+#define _GC_METER_FREE_LIST     0x04L
+#endif
+
+/************************************************************************/
+
+/* Each free list bin holds a chunk of memory sized from
+   2^n to (2^(n+1))-1 inclusive. */
+#define NUM_BINS        32
+
+/*
+ * Find the bin number for a given size (in bytes). This does not round up as
+ * values from 2^n to (2^(n+1))-1 share the same bin.
+ */
+#define InlineBinNumber(_bin,_bytes)              \
+{                              \
+    PRUint32 _t, _n = (PRUint32) _bytes;              \
+    _bin = 0;                          \
+    if ((_t = (_n >> 16)) != 0) { _bin += 16; _n = _t;    } \
+    if ((_t = (_n >> 8)) != 0)  { _bin += 8; _n = _t; }      \
+    if ((_t = (_n >> 4)) != 0)  { _bin += 4; _n = _t; }      \
+    if ((_t = (_n >> 2)) != 0) { _bin += 2; _n = _t; }      \
+    if ((_n >> 1) != 0) _bin++;                  \
+}
+
+#define BIG_ALLOC       16384L
+
+#define MIN_FREE_CHUNK_BYTES    ((PRInt32)sizeof(GCFreeChunk))
+
+/* Note: fix code in PR_AllocMemory if you change the size of GCFreeChunk
+   so that it zeros the right number of words */
+typedef struct GCFreeChunk {
+    struct GCFreeChunk *next;
+    struct GCSeg *segment;
+    PRInt32 chunkSize;
+} GCFreeChunk;
+
+typedef struct GCSegInfo {
+    struct GCSegInfo *next;
+    char *base;
+    char *limit;
+    PRWord *hbits;
+    int fromMalloc;
+} GCSegInfo;
+    
+typedef struct GCSeg {
+    char *base;
+    char *limit;
+    PRWord *hbits;
+    GCSegInfo *info;
+} GCSeg;
+
+#ifdef GCMETER
+typedef struct GCMeter {
+    PRInt32 allocBytes;
+    PRInt32 wastedBytes;
+    PRInt32 numFreeChunks;
+    PRInt32 skippedFreeChunks;
+} GCMeter;
+static GCMeter meter;
+#endif
+
+/*
+** There is one of these for each segment of GC'able memory.
+*/
+static GCSeg segs[MAX_SEGS];
+static GCSegInfo *freeSegs;
+static GCSeg* lastInHeap;
+static int nsegs;
+
+static GCFreeChunk *bins[NUM_BINS];
+static PRInt32 minBin;
+static PRInt32 maxBin;
+
+/*
+** Scan Q used to avoid deep recursion when scanning live objects for
+** heap pointers
+*/
+typedef struct GCScanQStr {
+    PRWord *q[MAX_SCAN_Q];
+    int queued;
+} GCScanQ;
+
+static GCScanQ *pScanQ;
+
+#ifdef GCMETER
+PRInt32 _pr_maxScanDepth;
+PRInt32 _pr_scanDepth;
+#endif
+
+/*
+** Keeps track of the number of bytes allocated via the BigAlloc() 
+** allocator.  When the number of bytes allocated, exceeds the 
+** BIG_ALLOC_GC_SIZE, then a GC will occur before the next allocation
+** is done...
+*/
+#define BIG_ALLOC_GC_SIZE       (4*SEGMENT_SIZE)
+static PRWord bigAllocBytes = 0;
+
+/*
+** There is one GC header word in front of each GC allocated object.  We
+** use it to contain information about the object (what TYPEIX to use for
+** scanning it, how big it is, it's mark status, and if it's a root).
+*/
+#define TYPEIX_BITS    8L
+#define WORDS_BITS    20L
+#define MAX_CBS        (1L << GC_TYPEIX_BITS)
+#define MAX_WORDS    (1L << GC_WORDS_BITS)
+#define TYPEIX_SHIFT    24L
+#define MAX_TYPEIX    ((1L << TYPEIX_BITS) - 1L)
+#define TYPEIX_MASK    PR_BITMASK(TYPEIX_BITS)
+#define WORDS_SHIFT    2L
+#define WORDS_MASK    PR_BITMASK(WORDS_BITS)
+#define MARK_BIT    1L
+#define FINAL_BIT    2L
+
+/* Two bits per object header are reserved for the user of the memory
+   system to store information into. */
+#define GC_USER_BITS_SHIFT 22L
+#define GC_USER_BITS    0x00c00000L
+
+#define MAKE_HEADER(_cbix,_words)              \
+    ((PRWord) (((unsigned long)(_cbix) << TYPEIX_SHIFT) \
+         | ((unsigned long)(_words) << WORDS_SHIFT)))
+
+#define GET_TYPEIX(_h) \
+    (((PRUword)(_h) >> TYPEIX_SHIFT) & 0xff)
+
+#define MARK(_sp,_p) \
+    (((PRWord *)(_p))[0] |= MARK_BIT)
+#define IS_MARKED(_sp,_p) \
+    (((PRWord *)(_p))[0] & MARK_BIT)
+#define OBJ_BYTES(_h) \
+    (((PRInt32) (_h) & 0x003ffffcL) << (PR_BYTES_PER_WORD_LOG2-2L))
+
+#define GC_GET_USER_BITS(_h) (((_h) & GC_USER_BITS) >> GC_USER_BITS_SHIFT)
+
+/************************************************************************/
+
+/*
+** Mark the start of an object in a segment. Note that we mark the header
+** word (which we always have), not the data word (which we may not have
+** for empty objects).
+** XXX tune: put subtract of _sp->base into _sp->hbits pointer?
+*/
+#if !defined(WIN16)
+#define SET_HBIT(_sp,_ph) \
+    SET_BIT((_sp)->hbits, (((PRWord*)(_ph)) - ((PRWord*) (_sp)->base)))
+
+#define CLEAR_HBIT(_sp,_ph) \
+    CLEAR_BIT((_sp)->hbits, (((PRWord*)(_ph)) - ((PRWord*) (_sp)->base)))
+
+#define IS_HBIT(_sp,_ph) \
+    TEST_BIT((_sp)->hbits, (((PRWord*)(_ph)) - ((PRWord*) (_sp)->base)))
+#else
+
+#define SET_HBIT(_sp,_ph) set_hbit(_sp,_ph)
+
+#define CLEAR_HBIT(_sp,_ph) clear_hbit(_sp,_ph)
+
+#define IS_HBIT(_sp,_ph) is_hbit(_sp,_ph)
+
+static void
+set_hbit(GCSeg *sp, PRWord *p)
+{
+    unsigned int distance;
+    unsigned int index;
+    PRWord     mask;
+
+        PR_ASSERT( SELECTOROF(p) == SELECTOROF(sp->base) );
+        PR_ASSERT( OFFSETOF(p)   >= OFFSETOF(sp->base) );
+
+        distance = (OFFSETOF(p) - OFFSETOF(sp->base)) >> 2;
+    index    = distance >> PR_BITS_PER_WORD_LOG2;
+    mask     = 1L << (distance&(PR_BITS_PER_WORD-1));
+
+    sp->hbits[index] |= mask;
+}
+
+static void
+clear_hbit(GCSeg *sp, PRWord *p)
+{
+    unsigned int distance;
+    unsigned int index;
+    PRWord    mask;
+
+        PR_ASSERT( SELECTOROF(p) == SELECTOROF(sp->base) );
+        PR_ASSERT( OFFSETOF(p)   >= OFFSETOF(sp->base) );
+
+        distance = (OFFSETOF(p) - OFFSETOF(sp->base)) >> 2;
+    index    = distance >> PR_BITS_PER_WORD_LOG2;
+    mask     = 1L << (distance&(PR_BITS_PER_WORD-1));
+
+    sp->hbits[index] &= ~mask;
+}
+
+static int
+is_hbit(GCSeg *sp, PRWord *p)
+{
+    unsigned int distance;
+    unsigned int index;
+    PRWord    mask;
+
+        PR_ASSERT( SELECTOROF(p) == SELECTOROF(sp->base) );
+        PR_ASSERT( OFFSETOF(p)   >= OFFSETOF(sp->base) );
+
+        distance = (OFFSETOF(p) - OFFSETOF(sp->base)) >> 2;
+    index    = distance >> PR_BITS_PER_WORD_LOG2;
+    mask     = 1L << (distance&(PR_BITS_PER_WORD-1));
+
+    return ((sp->hbits[index] & mask) != 0);
+}
+
+
+#endif  /* WIN16 */
+
+/*
+** Given a pointer into this segment, back it up until we are at the
+** start of the object the pointer points into. Each heap segment has a
+** bitmap that has one bit for each word of the objects it contains.  The
+** bit's are set for the firstword of an object, and clear for it's other
+** words.
+*/
+static PRWord *FindObject(GCSeg *sp, PRWord *p)
+{
+    PRWord *base;
+    
+    /* Align p to it's proper boundary before we start fiddling with it */
+    p = (PRWord*) ((PRWord)p & ~(PR_BYTES_PER_WORD-1L));
+
+    base = (PRWord *) sp->base;
+#if defined(WIN16)
+    PR_ASSERT( SELECTOROF(p) == SELECTOROF(base));
+#endif
+    do {
+    if (IS_HBIT(sp, p)) {
+        return (p);
+    }
+    p--;
+    } while ( p >= base );
+
+    /* Heap is corrupted! */
+    _GCTRACE(GC_TRACE, ("ERROR: The heap is corrupted!!! aborting now!"));
+    abort();
+    return NULL;
+}
+
+/************************************************************************/
+#if !defined(XP_PC) || defined(XP_OS2)
+#define OutputDebugString(msg)
+#endif 
+
+#if !defined(WIN16)
+#define IN_SEGMENT(_sp, _p)             \
+    ((((char *)(_p)) >= (_sp)->base) &&    \
+     (((char *)(_p)) < (_sp)->limit))
+#else
+#define IN_SEGMENT(_sp, _p)                  \
+    ((((PRWord)(_p)) >= ((PRWord)(_sp)->base)) && \
+     (((PRWord)(_p)) < ((PRWord)(_sp)->limit)))
+#endif
+
+static GCSeg *InHeap(void *p)
+{
+    GCSeg *sp, *esp;
+
+    if (lastInHeap && IN_SEGMENT(lastInHeap, p)) {
+    return lastInHeap;
+    }
+
+    sp = segs;
+    esp = segs + nsegs;
+    for (; sp < esp; sp++) {
+    if (IN_SEGMENT(sp, p)) {
+        lastInHeap = sp;
+        return sp;
+    }
+    }
+    return 0;
+}
+
+/*
+** Grow the heap by allocating another segment. Fudge the requestedSize
+** value to try to pre-account for the HBITS.
+*/
+static GCSeg* DoGrowHeap(PRInt32 requestedSize, PRBool exactly)
+{
+    GCSeg *sp;
+    GCSegInfo *segInfo;
+    GCFreeChunk *cp;
+    char *base;
+    PRWord *hbits;
+    PRInt32 nhbytes, nhbits;
+    PRUint32 allocSize;
+
+    if (nsegs == MAX_SEGS) {
+    /* No room for more segments */
+    return 0;
+    }
+
+    segInfo = (GCSegInfo*) PR_MALLOC(sizeof(GCSegInfo));
+#ifdef DEBUG
+    {
+    char str[256];
+    sprintf(str, "[1] Allocated %ld bytes at %p\n",
+        (long) sizeof(GCSegInfo), segInfo);
+    OutputDebugString(str);
+    }
+#endif
+    if (!segInfo) {
+    return 0;
+    }
+
+#if defined(WIN16)
+    if (requestedSize > segmentSize) {
+    PR_DELETE(segInfo);
+    return 0;
+    }
+#endif
+
+    /* Get more memory from the OS */
+    if (exactly) {
+    allocSize = requestedSize;
+    base = (char *) PR_MALLOC(requestedSize);
+    } else {
+    allocSize = requestedSize;
+    allocSize = (allocSize + _pr_pageSize - 1L) >> _pr_pageShift;
+    allocSize <<= _pr_pageShift;
+    base = (char*)_MD_GrowGCHeap(&allocSize);
+    }
+    if (!base) {
+    PR_DELETE(segInfo);
+    return 0;
+    }
+
+    nhbits = (PRInt32)(
+        (allocSize + PR_BYTES_PER_WORD - 1L) >> PR_BYTES_PER_WORD_LOG2);
+    nhbytes = ((nhbits + PR_BITS_PER_WORD - 1L) >> PR_BITS_PER_WORD_LOG2)
+    * sizeof(PRWord);
+
+    /* Get bitmap memory from malloc heap */
+#if defined(WIN16)
+    PR_ASSERT( nhbytes < MAX_ALLOC_SIZE );
+#endif
+    hbits = (PRWord *) PR_CALLOC((PRUint32)nhbytes);
+    if (!hbits) {
+    /* Loser! */
+    PR_DELETE(segInfo);
+    if (exactly) {
+        PR_DELETE(base);
+    } else {
+      /* XXX do something about this */
+      /* _MD_FreeGCSegment(base, allocSize); */
+    }
+    return 0;
+    }
+
+    /*
+    ** Setup new segment.
+    */
+    sp = &segs[nsegs++];
+    segInfo->base = sp->base = base;
+    segInfo->limit = sp->limit = base + allocSize;
+    segInfo->hbits = sp->hbits = hbits;
+    sp->info = segInfo;
+    segInfo->fromMalloc = exactly;
+    memset(base, 0, allocSize);
+
+#ifdef GCMETER
+    if (_pr_gcMeter & _GC_METER_GROWTH) {
+        fprintf(stderr, "[GC: new segment base=%p size=%ld]\n",
+                sp->base, (long) allocSize);
+    }
+#endif    
+
+    _pr_gcData.allocMemory += allocSize;
+    _pr_gcData.freeMemory  += allocSize;
+
+    if (!exactly) {
+    PRInt32 bin;
+
+        /* Put free memory into a freelist bin */
+        cp = (GCFreeChunk *) base;
+        cp->segment = sp;
+        cp->chunkSize = allocSize;
+        InlineBinNumber(bin, allocSize)
+        cp->next = bins[bin];
+        bins[bin] = cp;
+    if (bin < minBin) minBin = bin;
+    if (bin > maxBin) maxBin = bin;
+    } else {
+        /*
+        ** When exactly allocating the entire segment is given over to a
+        ** single object to prevent fragmentation
+        */
+    }
+
+    if (!_pr_gcData.lowSeg) {
+    _pr_gcData.lowSeg  = (PRWord*) sp->base;
+    _pr_gcData.highSeg = (PRWord*) sp->limit;
+    } else {
+    if ((PRWord*)sp->base < _pr_gcData.lowSeg) {
+        _pr_gcData.lowSeg = (PRWord*) sp->base;
+    }
+    if ((PRWord*)sp->limit > _pr_gcData.highSeg) {
+        _pr_gcData.highSeg = (PRWord*) sp->limit;
+    }
+    }
+
+    /* 
+    ** Get rid of the GC pointer in case it shows up in some uninitialized
+    ** local stack variable later (while scanning the C stack looking for
+    ** roots).
+    */ 
+    memset(&base, 0, sizeof(base));  /* optimizers beware */
+
+    PR_LOG(_pr_msgc_lm, PR_LOG_WARNING, ("grow heap: total gc memory now %d",
+                      _pr_gcData.allocMemory));
+
+    return sp;
+}
+
+#ifdef USE_EXTEND_HEAP
+static PRBool ExtendHeap(PRInt32 requestedSize) {
+  GCSeg* sp;
+  PRUint32 allocSize;
+  PRInt32 oldSize, newSize;
+  PRInt32 newHBits, newHBytes;
+  PRInt32 oldHBits, oldHBytes;
+  PRWord* hbits;
+  GCFreeChunk* cp;
+  PRInt32 bin;
+
+  /* Can't extend nothing */
+  if (nsegs == 0) return PR_FALSE;
+
+  /* Round up requested size to the size of a page */
+  allocSize = (PRUint32) requestedSize;
+  allocSize = (allocSize + _pr_pageSize - 1L) >> _pr_pageShift;
+  allocSize <<= _pr_pageShift;
+
+  /* Malloc some memory for the new hbits array */
+  sp = segs;
+  oldSize = sp->limit - sp->base;
+  newSize = oldSize + allocSize;
+  newHBits = (newSize + PR_BYTES_PER_WORD - 1L) >> PR_BYTES_PER_WORD_LOG2;
+  newHBytes = ((newHBits + PR_BITS_PER_WORD - 1L) >> PR_BITS_PER_WORD_LOG2)
+    * sizeof(PRWord);
+  hbits = (PRWord*) PR_MALLOC(newHBytes);
+  if (0 == hbits) return PR_FALSE;
+
+  /* Attempt to extend the last segment by the desired amount */
+  if (_MD_ExtendGCHeap(sp->base, oldSize, newSize)) {
+    oldHBits = (oldSize + PR_BYTES_PER_WORD - 1L) >> PR_BYTES_PER_WORD_LOG2;
+    oldHBytes = ((oldHBits + PR_BITS_PER_WORD - 1L) >> PR_BITS_PER_WORD_LOG2)
+      * sizeof(PRWord);
+
+    /* Copy hbits from old memory into new memory */
+    memset(hbits, 0, newHBytes);
+    memcpy(hbits, sp->hbits, oldHBytes);
+    PR_DELETE(sp->hbits);
+    memset(sp->base + oldSize, 0, allocSize);
+
+    /* Adjust segment state */
+    sp->limit += allocSize;
+    sp->hbits = hbits;
+    sp->info->limit = sp->limit;
+    sp->info->hbits = hbits;
+
+    /* Put free memory into a freelist bin */
+    cp = (GCFreeChunk *) (sp->base + oldSize);
+    cp->segment = sp;
+    cp->chunkSize = allocSize;
+    InlineBinNumber(bin, allocSize)
+    cp->next = bins[bin];
+    bins[bin] = cp;
+    if (bin < minBin) minBin = bin;
+    if (bin > maxBin) maxBin = bin;
+
+    /* Prevent a pointer that points to the free memory from showing
+       up on the call stack later on */
+    memset(&cp, 0, sizeof(cp));
+
+    /* Update heap brackets and counters */
+    if ((PRWord*)sp->limit > _pr_gcData.highSeg) {
+      _pr_gcData.highSeg = (PRWord*) sp->limit;
+    }
+    _pr_gcData.allocMemory += allocSize;
+    _pr_gcData.freeMemory  += allocSize;
+
+    return PR_TRUE;
+  }
+  PR_DELETE(hbits);
+  return PR_FALSE;
+}
+#endif /* USE_EXTEND_HEAP */
+
+static GCSeg *GrowHeapExactly(PRInt32 requestedSize)
+{
+    GCSeg *sp = DoGrowHeap(requestedSize, PR_TRUE);
+    return sp;
+}
+
+static PRBool GrowHeap(PRInt32 requestedSize)
+{
+  void *p;
+#ifdef USE_EXTEND_HEAP
+  if (ExtendHeap(requestedSize)) {
+    return PR_TRUE;
+  }
+#endif
+  p = DoGrowHeap(requestedSize, PR_FALSE);
+  return (p != NULL ? PR_TRUE : PR_FALSE);
+}
+
+/*
+** Release a segment when it is entirely free.
+*/
+static void ShrinkGCHeap(GCSeg *sp)
+{
+#ifdef GCMETER
+    if (_pr_gcMeter & _GC_METER_GROWTH) {
+        fprintf(stderr, "[GC: free segment base=%p size=%ld]\n",
+                sp->base, (long) (sp->limit - sp->base));
+    }
+#endif    
+
+    /*
+     * Put segment onto free seginfo list (we can't call free right now
+     * because we have the GC lock and all of the other threads are
+     * suspended; if one of them has the malloc lock we would deadlock)
+     */
+    sp->info->next = freeSegs;
+    freeSegs = sp->info;
+    collectorCleanupNeeded = 1;
+    _pr_gcData.allocMemory -= sp->limit - sp->base;
+    if (sp == lastInHeap) lastInHeap = 0;
+
+    /* Squish out disappearing segment from segment table */
+    --nsegs;
+    if ((sp - segs) != nsegs) {
+        *sp = segs[nsegs];
+    } else {
+        sp->base = 0;
+        sp->limit = 0;
+        sp->hbits = 0;
+    sp->info = 0;
+    }
+
+    /* Recalculate the lowSeg and highSeg values */
+    _pr_gcData.lowSeg  = (PRWord*) segs[0].base;
+    _pr_gcData.highSeg = (PRWord*) segs[0].limit;
+    for (sp = segs; sp < &segs[nsegs]; sp++) {
+    if ((PRWord*)sp->base < _pr_gcData.lowSeg) {
+        _pr_gcData.lowSeg = (PRWord*) sp->base;
+    }
+    if ((PRWord*)sp->limit > _pr_gcData.highSeg) {
+        _pr_gcData.highSeg = (PRWord*) sp->limit;
+    }
+    }
+}
+
+static void FreeSegments(void)
+{
+    GCSegInfo *si;
+
+    while (0 != freeSegs) {
+    LOCK_GC();
+    si = freeSegs;
+    if (si) {
+        freeSegs = si->next;
+    }
+    UNLOCK_GC();
+
+    if (!si) {
+        break;
+    }
+    PR_DELETE(si->base);
+    PR_DELETE(si->hbits);
+    PR_DELETE(si);
+    }
+}
+
+/************************************************************************/
+
+void ScanScanQ(GCScanQ *iscan)
+{
+    PRWord *p;
+    PRWord **pp;
+    PRWord **epp;
+    GCScanQ nextQ, *scan, *next, *temp;
+    CollectorType *ct;
+
+    if (!iscan->queued) return;
+
+    _GCTRACE(GC_MARK, ("begin scanQ @ 0x%x (%d)", iscan, iscan->queued));
+    scan = iscan;
+    next = &nextQ;
+    while (scan->queued) {
+	_GCTRACE(GC_MARK, ("continue scanQ @ 0x%x (%d)", scan, scan->queued));
+    /* Set pointer to current scanQ so that pr_liveObject can find it */
+    pScanQ = next;
+    next->queued = 0;
+
+    /* Now scan the scan Q */
+    pp = scan->q;
+    epp = &scan->q[scan->queued];
+    scan->queued = 0;
+    while (pp < epp) {
+        p = *pp++;
+        ct = &_pr_collectorTypes[GET_TYPEIX(p[0])];
+        PR_ASSERT(0 != ct->gctype.scan);
+        /* Scan object ... */
+        (*ct->gctype.scan)(p + 1);
+    }
+
+    /* Exchange pointers so that we scan next */
+    temp = scan;
+    scan = next;
+    next = temp;
+    }
+
+    pScanQ = iscan;
+    PR_ASSERT(nextQ.queued == 0);
+    PR_ASSERT(iscan->queued == 0);
+}
+
+/*
+** Called during root finding step to identify "root" pointers into the
+** GC heap. First validate if it is a real heap pointer and then mark the
+** object being pointed to and add it to the scan Q for eventual
+** scanning.
+*/
+static void PR_CALLBACK ProcessRootBlock(void **base, PRInt32 count)
+{
+    GCSeg *sp;
+    PRWord *p0, *p, h, tix, *low, *high, *segBase;
+    CollectorType *ct;
+#ifdef DEBUG
+    void **base0 = base;
+#endif
+
+    low = _pr_gcData.lowSeg;
+    high = _pr_gcData.highSeg;
+    while (--count >= 0) {
+        p0 = (PRWord*) *base++;
+        /*
+        ** XXX:  
+        ** Until Win16 maintains lowSeg and highSeg correctly,
+        ** (ie. lowSeg=MIN(all segs) and highSeg = MAX(all segs))
+        ** Allways scan through the segment list
+        */
+#if !defined(WIN16)
+        if (p0 < low) continue;                  /* below gc heap */
+        if (p0 >= high) continue;                /* above gc heap */
+#endif
+        /* NOTE: inline expansion of InHeap */
+        /* Find segment */
+    sp = lastInHeap;
+        if (!sp || !IN_SEGMENT(sp,p0)) {
+            GCSeg *esp;
+            sp = segs;
+        esp = segs + nsegs;
+            for (; sp < esp; sp++) {
+                if (IN_SEGMENT(sp, p0)) {
+                    lastInHeap = sp;
+                    goto find_object;
+                }
+            }
+            continue;
+        }
+
+      find_object:
+        /* NOTE: Inline expansion of FindObject */
+        /* Align p to it's proper boundary before we start fiddling with it */
+        p = (PRWord*) ((PRWord)p0 & ~(PR_BYTES_PER_WORD-1L));
+        segBase = (PRWord *) sp->base;
+        do {
+            if (IS_HBIT(sp, p)) {
+                goto winner;
+            }
+            p--;
+        } while (p >= segBase);
+
+        /*
+        ** We have a pointer into the heap, but it has no header
+        ** bit. This means that somehow the very first object in the heap
+        ** doesn't have a header. This is impossible so when debugging
+        ** lets abort.
+        */
+#ifdef DEBUG
+        PR_Abort();
+#endif
+
+      winner:
+        h = p[0];
+        if ((h & MARK_BIT) == 0) {
+#ifdef DEBUG
+            _GCTRACE(GC_ROOTS,
+            ("root 0x%p (%d) base0=%p off=%d",
+             p, OBJ_BYTES(h), base0, (base-1) - base0));
+#endif
+
+            /* Mark the root we just found */
+            p[0] = h | MARK_BIT;
+
+            /*
+         * See if object we just found needs scanning. It must
+         * have a scan function to be placed on the scanQ.
+         */
+            tix = (PRWord)GET_TYPEIX(h);
+        ct = &_pr_collectorTypes[tix];
+        if (0 == ct->gctype.scan) {
+        continue;
+        }
+
+            /*
+            ** Put a pointer onto the scan Q. We use the scan Q to avoid
+            ** deep recursion on the C call stack. Objects are added to
+            ** the scan Q until the scan Q fills up. At that point we
+            ** make a call to ScanScanQ which proceeds to scan each of
+            ** the objects in the Q. This limits the recursion level by a
+            ** large amount though the stack frames get larger to hold
+            ** the GCScanQ's.
+            */
+            pScanQ->q[pScanQ->queued++] = p;
+            if (pScanQ->queued == MAX_SCAN_Q) {
+                METER(_pr_scanDepth++);
+                ScanScanQ(pScanQ);
+            }
+        }
+    }
+}
+
+static void PR_CALLBACK ProcessRootPointer(void *ptr)
+{
+  PRWord *p0, *p, h, tix, *segBase;
+  GCSeg* sp;
+  CollectorType *ct;
+
+  p0 = (PRWord*) ptr;
+
+  /*
+  ** XXX:  
+  ** Until Win16 maintains lowSeg and highSeg correctly,
+  ** (ie. lowSeg=MIN(all segs) and highSeg = MAX(all segs))
+  ** Allways scan through the segment list
+  */
+#if !defined(WIN16)
+  if (p0 < _pr_gcData.lowSeg) return;                  /* below gc heap */
+  if (p0 >= _pr_gcData.highSeg) return;                /* above gc heap */
+#endif
+
+  /* NOTE: inline expansion of InHeap */
+  /* Find segment */
+  sp = lastInHeap;
+  if (!sp || !IN_SEGMENT(sp,p0)) {
+    GCSeg *esp;
+    sp = segs;
+    esp = segs + nsegs;
+    for (; sp < esp; sp++) {
+      if (IN_SEGMENT(sp, p0)) {
+    lastInHeap = sp;
+    goto find_object;
+      }
+    }
+    return;
+  }
+
+ find_object:
+  /* NOTE: Inline expansion of FindObject */
+  /* Align p to it's proper boundary before we start fiddling with it */
+    p = (PRWord*) ((PRWord)p0 & ~(BYTES_PER_WORD-1L));
+    segBase = (PRWord *) sp->base;
+    do {
+      if (IS_HBIT(sp, p)) {
+    goto winner;
+      }
+      p--;
+    } while (p >= segBase);
+
+    /*
+    ** We have a pointer into the heap, but it has no header
+    ** bit. This means that somehow the very first object in the heap
+    ** doesn't have a header. This is impossible so when debugging
+    ** lets abort.
+    */
+#ifdef DEBUG
+    PR_Abort();
+#endif
+
+ winner:
+  h = p[0];
+  if ((h & MARK_BIT) == 0) {
+#ifdef DEBUG
+    _GCTRACE(GC_ROOTS, ("root 0x%p (%d)", p, OBJ_BYTES(h)));
+#endif
+
+    /* Mark the root we just found */
+    p[0] = h | MARK_BIT;
+
+    /*
+     * See if object we just found needs scanning. It must
+     * have a scan function to be placed on the scanQ.
+     */
+    tix = (PRWord)GET_TYPEIX(h);
+    ct = &_pr_collectorTypes[tix];
+    if (0 == ct->gctype.scan) {
+      return;
+    }
+
+    /*
+    ** Put a pointer onto the scan Q. We use the scan Q to avoid
+    ** deep recursion on the C call stack. Objects are added to
+    ** the scan Q until the scan Q fills up. At that point we
+    ** make a call to ScanScanQ which proceeds to scan each of
+    ** the objects in the Q. This limits the recursion level by a
+    ** large amount though the stack frames get larger to hold
+    ** the GCScanQ's.
+    */
+    pScanQ->q[pScanQ->queued++] = p;
+    if (pScanQ->queued == MAX_SCAN_Q) {
+      METER(_pr_scanDepth++);
+      ScanScanQ(pScanQ);
+    }
+  }
+}
+
+/************************************************************************/
+
+/*
+** Empty the freelist for each segment. This is done to make sure that
+** the root finding step works properly (otherwise, if we had a pointer
+** into a free section, we might not find its header word and abort in
+** FindObject)
+*/
+static void EmptyFreelists(void)
+{
+    GCFreeChunk *cp;
+    GCFreeChunk *next;
+    GCSeg *sp;
+    PRWord *p;
+    PRInt32 chunkSize;
+    PRInt32 bin;
+
+    /*
+    ** Run over the freelist and make all of the free chunks look like
+    ** object debris.
+    */
+    for (bin = 0; bin <= NUM_BINS-1; bin++) {
+        cp = bins[bin];
+        while (cp) {
+            next = cp->next;
+            sp = cp->segment;
+            chunkSize = cp->chunkSize >> BYTES_PER_WORD_LOG2;
+            p = (PRWord*) cp;
+            PR_ASSERT(chunkSize != 0);
+            p[0] = MAKE_HEADER(FREE_MEMORY_TYPEIX, chunkSize);
+            SET_HBIT(sp, p);
+            cp = next;
+        }
+        bins[bin] = 0;
+    }
+    minBin = 31;
+    maxBin = 0;
+}
+
+typedef struct GCBlockEnd {
+    PRInt32	check;
+#ifdef GC_CHECK
+    PRInt32	requestedBytes;
+#endif
+#ifdef GC_STATS
+    PRInt32	bin;
+    PRInt64	allocTime; 
+#endif
+#ifdef GC_TRACEROOTS
+    PRInt32	traceGeneration;	
+#endif
+} GCBlockEnd;
+
+#define PR_BLOCK_END	0xDEADBEEF
+
+/************************************************************************/
+
+#ifdef GC_STATS
+
+typedef struct GCStat {
+    PRInt32	nallocs;
+    double	allocTime;
+    double	allocTimeVariance;
+    PRInt32	nfrees;
+    double	lifetime;
+    double	lifetimeVariance;
+} GCStat;
+
+#define GCSTAT_BINS	32
+
+GCStat gcstats[GCSTAT_BINS];
+
+#define GCLTFREQ_BINS	32
+
+PRInt32 gcltfreq[GCSTAT_BINS][GCLTFREQ_BINS];
+
+#include <math.h>
+
+static char* 
+pr_GetSizeString(PRUint32 size)
+{
+    char* sizeStr;
+    if (size < 1024)
+	sizeStr = PR_smprintf("<= %ld", size);
+    else if (size < 1024 * 1024)
+	sizeStr = PR_smprintf("<= %ldk", size / 1024);
+    else 
+	sizeStr = PR_smprintf("<= %ldM", size / (1024 * 1024));
+    return sizeStr;
+}
+
+static void
+pr_FreeSizeString(char *sizestr)
+{
+	PR_smprintf_free(sizestr);
+}
+
+
+static void
+pr_PrintGCAllocStats(FILE* out)
+{
+    PRInt32 i, j;
+    _PR_DebugPrint(out, "\n--Allocation-Stats-----------------------------------------------------------");
+    _PR_DebugPrint(out, "\n--Obj-Size----Count-----Avg-Alloc-Time-----------Avg-Lifetime---------%%Freed-\n");
+    for (i = 0; i < GCSTAT_BINS; i++) {
+	GCStat stat = gcstats[i];
+	double allocTimeMean = 0.0, allocTimeVariance = 0.0, lifetimeMean = 0.0, lifetimeVariance = 0.0;
+	PRUint32 maxSize = (1 << i);
+	char* sizeStr;
+	if (stat.nallocs != 0.0) {
+	    allocTimeMean = stat.allocTime / stat.nallocs;
+	    allocTimeVariance = fabs(stat.allocTimeVariance / stat.nallocs - allocTimeMean * allocTimeMean);
+	}
+	if (stat.nfrees != 0.0) {
+	    lifetimeMean = stat.lifetime / stat.nfrees;
+	    lifetimeVariance = fabs(stat.lifetimeVariance / stat.nfrees - lifetimeMean * lifetimeMean);
+	}
+	sizeStr = pr_GetSizeString(maxSize);
+	_PR_DebugPrint(out, "%10s %8lu %10.3f +- %10.3f %10.3f +- %10.3f (%2ld%%)\n",
+		       sizeStr, stat.nallocs,
+		       allocTimeMean, sqrt(allocTimeVariance),
+		       lifetimeMean, sqrt(lifetimeVariance),
+		       (stat.nallocs ? (stat.nfrees * 100 / stat.nallocs) : 0));
+	pr_FreeSizeString(sizeStr);
+    }
+    _PR_DebugPrint(out, "--Lifetime-Frequency-Counts----------------------------------------------------\n");
+    _PR_DebugPrint(out, "size\\cnt");
+    for (j = 0; j < GCLTFREQ_BINS; j++) {
+	_PR_DebugPrint(out, "\t%lu", j);
+    }
+    _PR_DebugPrint(out, "\n");
+    for (i = 0; i < GCSTAT_BINS; i++) {
+	PRInt32* freqs = gcltfreq[i];
+	_PR_DebugPrint(out, "%lu", (1 << i));
+	for (j = 0; j < GCLTFREQ_BINS; j++) {
+	    _PR_DebugPrint(out, "\t%lu", freqs[j]);
+	}
+	_PR_DebugPrint(out, "\n");
+    }
+    _PR_DebugPrint(out, "-------------------------------------------------------------------------------\n");
+}
+
+PR_PUBLIC_API(void)
+PR_PrintGCAllocStats(void)
+{
+    pr_PrintGCAllocStats(stderr);
+}
+
+#endif /* GC_STATS */
+
+/************************************************************************/
+
+/*
+** Sweep a segment, cleaning up all of the debris. Coallese the debris
+** into GCFreeChunk's which are added to the freelist bins.
+*/
+static PRBool SweepSegment(GCSeg *sp)
+{
+    PRWord h, tix;
+    PRWord *p;
+    PRWord *np;
+    PRWord *limit;
+    GCFreeChunk *cp;
+    PRInt32 bytes, chunkSize, segmentSize, totalFree;
+    CollectorType *ct;
+    PRInt32 bin;
+
+    /*
+    ** Now scan over the segment's memory in memory order, coallescing
+    ** all of the debris into a FreeChunk list.
+    */
+    totalFree = 0;
+    segmentSize = sp->limit - sp->base;
+    p = (PRWord *) sp->base;
+    limit = (PRWord *) sp->limit;
+    PR_ASSERT(segmentSize > 0);
+    while (p < limit) {
+    chunkSize = 0;
+    cp = (GCFreeChunk *) p;
+
+    /* Attempt to coallesce any neighboring free objects */
+    for (;;) {
+        PR_ASSERT(IS_HBIT(sp, p) != 0);
+        h = p[0];
+        bytes = OBJ_BYTES(h);
+        PR_ASSERT(bytes != 0);
+        np = (PRWord *) ((char *)p + bytes);
+        tix = (PRWord)GET_TYPEIX(h);
+        if ((h & MARK_BIT) && (tix != FREE_MEMORY_TYPEIX)) {
+#ifdef DEBUG
+        if (tix != FREE_MEMORY_TYPEIX) {
+            PR_ASSERT(_pr_collectorTypes[tix].flags != 0);
+        }
+#endif
+        p[0] = h & ~(MARK_BIT|FINAL_BIT);
+		_GCTRACE(GC_SWEEP, ("busy 0x%x (%d)", p, bytes));
+		break;
+	    }
+	    _GCTRACE(GC_SWEEP, ("free 0x%x (%d)", p, bytes));
+
+	    /* Found a free object */
+#ifdef GC_STATS
+	    {
+		PRInt32 userSize = bytes - sizeof(GCBlockEnd);
+		GCBlockEnd* end = (GCBlockEnd*)((char*)p + userSize);
+		if (userSize >= 0 && end->check == PR_BLOCK_END) {
+		    PRInt64 now = PR_Now();
+		    double nowd, delta;
+		    PRInt32 freq;
+		    LL_L2D(nowd, now);
+		    delta = nowd - end->allocTime;
+		    gcstats[end->bin].nfrees++;
+		    gcstats[end->bin].lifetime += delta;
+		    gcstats[end->bin].lifetimeVariance += delta * delta;
+
+		    InlineBinNumber(freq, delta);
+		    gcltfreq[end->bin][freq]++;
+
+		    end->check = 0;
+		}
+	    }
+#endif
+        CLEAR_HBIT(sp, p);
+        ct = &_pr_collectorTypes[tix];
+        if (0 != ct->gctype.free) {
+                (*ct->gctype.free)(p + 1);
+            }
+        chunkSize = chunkSize + bytes;
+        if (np == limit) {
+        /* Found the end of heap */
+        break;
+        }
+        PR_ASSERT(np < limit);
+        p = np;
+    }
+
+    if (chunkSize) {
+        _GCTRACE(GC_SWEEP, ("free chunk 0x%p to 0x%p (%d)",
+                   cp, (char*)cp + chunkSize - 1, chunkSize));
+        if (chunkSize < MIN_FREE_CHUNK_BYTES) {
+        /* Lost a tiny fragment until (maybe) next time */
+                METER(meter.wastedBytes += chunkSize);
+        p = (PRWord *) cp;
+        chunkSize >>= BYTES_PER_WORD_LOG2;
+        PR_ASSERT(chunkSize != 0);
+        p[0] = MAKE_HEADER(FREE_MEMORY_TYPEIX, chunkSize);
+        SET_HBIT(sp, p);
+        } else {
+                /* See if the chunk constitutes the entire segment */
+                if (chunkSize == segmentSize) {
+                    /* Free up the segment right now */
+            if (sp->info->fromMalloc) {
+                    ShrinkGCHeap(sp);
+                    return PR_TRUE;
+                }
+                }
+
+                /* Put free chunk into the appropriate bin */
+                cp->segment = sp;
+        cp->chunkSize = chunkSize;
+                InlineBinNumber(bin, chunkSize)
+                cp->next = bins[bin];
+                bins[bin] = cp;
+        if (bin < minBin) minBin = bin;
+        if (bin > maxBin) maxBin = bin;
+
+        /* Zero swept memory now */
+        memset(cp+1, 0, chunkSize - sizeof(*cp));
+                METER(meter.numFreeChunks++);
+        totalFree += chunkSize;
+        }
+    }
+
+    /* Advance to next object */
+    p = np;
+    }
+
+    PR_ASSERT(totalFree <= segmentSize);
+
+    _pr_gcData.freeMemory += totalFree;
+    _pr_gcData.busyMemory += (sp->limit - sp->base) - totalFree;
+    return PR_FALSE;
+}
+
+/************************************************************************/
+
+/* This is a list of all the objects that are finalizable. This is not
+   the list of objects that are awaiting finalization because they
+   have been collected. */
+PRCList _pr_finalizeableObjects;
+
+/* This is the list of objects that are awaiting finalization because
+   they have been collected. */
+PRCList _pr_finalQueue;
+
+/* Each object that requires finalization has one of these objects
+   allocated as well. The GCFinal objects are put on the
+   _pr_finalizeableObjects list until the object is collected at which
+   point the GCFinal object is moved to the _pr_finalQueue */
+typedef struct GCFinalStr {
+    PRCList links;
+    PRWord *object;
+} GCFinal;
+
+/* Find pointer to GCFinal struct from the list linkaged embedded in it */
+#define FinalPtr(_qp) \
+    ((GCFinal*) ((char*) (_qp) - offsetof(GCFinal,links)))
+
+static GCFinal *AllocFinalNode(void)
+{
+    return PR_NEWZAP(GCFinal);
+}
+
+static void FreeFinalNode(GCFinal *node)
+{
+    PR_DELETE(node);
+}
+
+/*
+** Prepare for finalization. At this point in the GC cycle we have
+** identified all of the live objects. For each object on the
+** _pr_finalizeableObjects list see if the object is alive or dead. If
+** it's dead, resurrect it and move it from the _pr_finalizeableObjects
+** list to the _pr_finalQueue (object's only get finalized once).
+**
+** Once _pr_finalizeableObjects has been processed we can finish the
+** GC and free up memory and release the threading lock. After that we
+** can invoke the finalization procs for each object that is on the
+** _pr_finalQueue.
+*/
+static void PrepareFinalize(void)
+{
+    PRCList *qp;
+    GCFinal *fp;
+    PRWord h;
+    PRWord *p;
+    void (PR_CALLBACK *livePointer)(void *ptr);
+#ifdef DEBUG
+    CollectorType *ct;
+#endif
+
+    /* This must be done under the same lock that the finalizer uses */
+    PR_ASSERT( GC_IS_LOCKED() );
+
+    /* cache this ptr */
+    livePointer = _pr_gcData.livePointer;
+
+    /*
+     * Pass #1: Identify objects that are to be finalized, set their
+     * FINAL_BIT.
+     */
+    qp = _pr_finalizeableObjects.next;
+    while (qp != &_pr_finalizeableObjects) {
+    fp = FinalPtr(qp);
+    qp = qp->next;
+    h = fp->object[0];        /* Grab header word */
+    if (h & MARK_BIT) {
+        /* Object is already alive */
+        continue;
+    }
+
+#ifdef DEBUG
+    ct = &_pr_collectorTypes[GET_TYPEIX(h)];
+    PR_ASSERT((0 != ct->flags) && (0 != ct->gctype.finalize));
+#endif
+    fp->object[0] |= FINAL_BIT;
+    _GCTRACE(GC_FINAL, ("moving %p (%d) to finalQueue",
+               fp->object, OBJ_BYTES(h)));
+    }
+
+    /*
+     * Pass #2: For each object that is going to be finalized, move it to
+     * the finalization queue and resurrect it
+     */
+    qp = _pr_finalizeableObjects.next;
+    while (qp != &_pr_finalizeableObjects) {
+    fp = FinalPtr(qp);
+    qp = qp->next;
+    h = fp->object[0];        /* Grab header word */
+    if ((h & FINAL_BIT) == 0) {
+        continue;
+    }
+
+    /* Resurrect the object and any objects it refers to */
+        p = &fp->object[1];
+    (*livePointer)(p);
+    PR_REMOVE_LINK(&fp->links);
+    PR_APPEND_LINK(&fp->links, &_pr_finalQueue);
+    }
+}
+
+/*
+** Scan the finalQ, marking each and every object on it live.  This is
+** necessary because we might do a GC before objects that are on the
+** final queue get finalized. Since there are no other references
+** (otherwise they would be on the final queue), we have to scan them.
+** This really only does work if we call the GC before the finalizer
+** has a chance to do its job.
+*/
+extern void PR_CALLBACK _PR_ScanFinalQueue(void *notused)
+{
+#ifdef XP_MAC
+#pragma unused (notused)
+#endif
+    PRCList *qp;
+    GCFinal *fp;
+    PRWord *p;
+    void ( PR_CALLBACK *livePointer)(void *ptr);
+
+    livePointer = _pr_gcData.livePointer;
+    qp = _pr_finalQueue.next;
+    while (qp != &_pr_finalQueue) {
+    fp = FinalPtr(qp);
+	_GCTRACE(GC_FINAL, ("marking 0x%x (on final queue)", fp->object));
+        p = &fp->object[1];
+    (*livePointer)(p);
+    qp = qp->next;
+    }
+}
+
+void PR_CALLBACK FinalizerLoop(void* unused)
+{
+#ifdef XP_MAC
+#pragma unused (unused)
+#endif
+    GCFinal *fp;
+    PRWord *p;
+    PRWord h, tix;
+    CollectorType *ct;
+
+    LOCK_GC();
+    for (;;) {
+	p = 0; h = 0;		/* don't let the gc find these pointers */
+    while (PR_CLIST_IS_EMPTY(&_pr_finalQueue))
+        PR_Wait(_pr_gcData.lock, PR_INTERVAL_NO_TIMEOUT);
+
+    _GCTRACE(GC_FINAL, ("begin finalization"));
+    while (_pr_finalQueue.next != &_pr_finalQueue) {
+        fp = FinalPtr(_pr_finalQueue.next);
+        PR_REMOVE_LINK(&fp->links);
+        p = fp->object;
+
+        h = p[0];        /* Grab header word */
+        tix = (PRWord)GET_TYPEIX(h);
+        ct = &_pr_collectorTypes[tix];
+	    _GCTRACE(GC_FINAL, ("finalize 0x%x (%d)", p, OBJ_BYTES(h)));
+
+        /*
+        ** Give up the GC lock so that other threads can allocate memory
+        ** while this finalization method is running. Get it back
+        ** afterwards so that the list remains thread safe.
+        */
+        UNLOCK_GC();
+        FreeFinalNode(fp);
+        PR_ASSERT(ct->gctype.finalize != 0);
+        (*ct->gctype.finalize)(p + 1);
+        LOCK_GC();
+    }
+    _GCTRACE(GC_FINAL, ("end finalization"));
+    PR_Notify(_pr_gcData.lock);
+    }
+}
+
+static void NotifyFinalizer(void)
+{
+    if (!PR_CLIST_IS_EMPTY(&_pr_finalQueue)) {
+    PR_ASSERT( GC_IS_LOCKED() );
+    PR_Notify(_pr_gcData.lock);
+    }
+}
+
+void _PR_CreateFinalizer(PRThreadScope scope)
+{
+    if (!_pr_gcData.finalizer) {
+    _pr_gcData.finalizer = PR_CreateThreadGCAble(PR_SYSTEM_THREAD,
+                                        FinalizerLoop, 0,
+                                        PR_PRIORITY_LOW, scope,
+                                        PR_UNJOINABLE_THREAD, 0);
+    
+    if (_pr_gcData.finalizer == NULL)
+        /* We are doomed if we can't start the finalizer */
+        PR_Abort();
+
+    }
+}
+
+void pr_FinalizeOnExit(void)
+{
+#ifdef DEBUG_warren
+    OutputDebugString("### Doing finalize-on-exit pass\n");
+#endif
+    PR_ForceFinalize();
+#ifdef DEBUG_warren
+    OutputDebugString("### Finalize-on-exit complete. Dumping object left to memory.out\n");
+    PR_DumpMemorySummary();
+    PR_DumpMemory(PR_TRUE);
+#endif
+}
+
+PR_IMPLEMENT(void) PR_ForceFinalize()
+{
+    LOCK_GC();
+    NotifyFinalizer();
+    while (!PR_CLIST_IS_EMPTY(&_pr_finalQueue)) {
+    PR_ASSERT( GC_IS_LOCKED() );
+    (void) PR_Wait(_pr_gcData.lock, PR_INTERVAL_NO_TIMEOUT);
+    }
+    UNLOCK_GC();
+
+    /* XXX I don't know how to make it wait (yet) */
+}
+
+/************************************************************************/
+
+typedef struct GCWeakStr {
+    PRCList links;
+    PRWord *object;
+} GCWeak;
+
+/*
+** Find pointer to GCWeak struct from the list linkaged embedded in it
+*/
+#define WeakPtr(_qp) \
+    ((GCWeak*) ((char*) (_qp) - offsetof(GCWeak,links)))
+
+PRCList _pr_weakLinks = PR_INIT_STATIC_CLIST(&_pr_weakLinks);
+PRCList _pr_freeWeakLinks = PR_INIT_STATIC_CLIST(&_pr_freeWeakLinks);
+
+#define WEAK_FREELIST_ISEMPTY() (_pr_freeWeakLinks.next == &_pr_freeWeakLinks)
+
+/*
+ * Keep objects referred to by weak free list alive until they can be
+ * freed
+ */
+static void PR_CALLBACK ScanWeakFreeList(void *notused) {
+#ifdef XP_MAC
+#pragma unused (notused)
+#endif
+    PRCList *qp = _pr_freeWeakLinks.next;
+    while (qp != &_pr_freeWeakLinks) {
+    GCWeak *wp = WeakPtr(qp);
+    qp = qp->next;
+    ProcessRootPointer(wp->object);
+    }
+}
+
+/*
+ * Empty the list of weak objects. Note that we can't call malloc/free
+ * under the cover of the GC's lock (we might deadlock), so transfer the
+ * list of free objects to a local list under the cover of the lock, then
+ * release the lock and free up the memory.
+ */
+static void EmptyWeakFreeList(void) {
+    if (!WEAK_FREELIST_ISEMPTY()) {
+    PRCList *qp, freeLinks;
+
+    PR_INIT_CLIST(&freeLinks);
+
+    /*
+     * Transfer list of free weak links from the global list to a
+     * local list.
+     */
+    LOCK_GC();
+    qp = _pr_freeWeakLinks.next;
+    while (qp != &_pr_freeWeakLinks) {
+        GCWeak *wp = WeakPtr(qp);
+        qp = qp->next;
+        PR_REMOVE_LINK(&wp->links);
+        PR_APPEND_LINK(&wp->links, &freeLinks);
+    }
+    UNLOCK_GC();
+
+    /* Free up storage now */
+    qp = freeLinks.next;
+    while (qp != &freeLinks) {
+        GCWeak *wp = WeakPtr(qp);
+        qp = qp->next;
+        PR_DELETE(wp);
+    }
+    }
+}
+
+/*
+ * Allocate a new weak node in the weak objects list
+ */
+static GCWeak *AllocWeakNode(void)
+{
+    EmptyWeakFreeList();
+    return PR_NEWZAP(GCWeak);
+}
+
+static void FreeWeakNode(GCWeak *node)
+{
+    PR_DELETE(node);
+}
+
+/*
+ * Check the weak links for validity. Note that the list of weak links is
+ * itself weak (otherwise we would keep the objects with weak links in
+ * them alive forever). As we scan the list check the weak link object
+ * itself and if it's not marked then remove it from the weak link list
+ */
+static void CheckWeakLinks(void) {
+    PRCList *qp;
+    GCWeak *wp;
+    PRWord *p, h, tix, **weakPtrAddress;
+    CollectorType *ct;
+    PRUint32 offset;
+
+    qp = _pr_weakLinks.next;
+    while (qp != &_pr_weakLinks) {
+    wp = WeakPtr(qp);
+    qp = qp->next;
+    if ((p = wp->object) != 0) {
+        h = p[0];        /* Grab header word */
+        if ((h & MARK_BIT) == 0) {
+        /*
+         * The object that has a weak link is no longer being
+         * referenced; remove it from the chain and let it get
+         * swept away by the GC. Transfer it to the list of
+         * free weak links for later freeing.
+         */
+        PR_REMOVE_LINK(&wp->links);
+        PR_APPEND_LINK(&wp->links, &_pr_freeWeakLinks);
+        collectorCleanupNeeded = 1;
+        continue;
+        }
+        
+	    /* Examine a live object that contains weak links */
+        tix = GET_TYPEIX(h);
+        ct = &_pr_collectorTypes[tix];
+        PR_ASSERT((ct->flags != 0) && (ct->gctype.getWeakLinkOffset != 0));
+        if (0 == ct->gctype.getWeakLinkOffset) {
+        /* Heap is probably corrupted */
+        continue;
+        }
+
+        /* Get offset into the object of where the weak pointer is */
+        offset = (*ct->gctype.getWeakLinkOffset)(p + 1);
+
+        /* Check the weak pointer */
+        weakPtrAddress = (PRWord**)((char*)(p + 1) + offset);
+        p = *weakPtrAddress;
+        if (p != 0) {
+        h = p[-1];    /* Grab header word for pointed to object */
+        if (h & MARK_BIT) {
+            /* Object can't be dead */
+            continue;
+        }
+        /* Break weak link to an object that is about to be swept */
+        *weakPtrAddress = 0;
+        }
+    }
+    }
+}
+
+/************************************************************************/
+
+/*
+** Perform a complete garbage collection
+*/
+
+extern GCLockHook *_pr_GCLockHook;
+
+static void dogc(void)
+{
+    RootFinder *rf;
+    GCLockHook* lhook;
+
+    GCScanQ scanQ;
+    GCSeg *sp, *esp;
+    PRInt64 start, end, diff;
+
+#if defined(GCMETER) || defined(GCTIMINGHOOK)
+    start = PR_Now();
+#endif
+
+    /*
+    ** Stop all of the other threads. This also promises to capture the
+    ** register state of each and every thread
+    */
+
+    /* 
+    ** Get all the locks that will be need during GC after SuspendAll. We 
+    ** cannot make any locking/library calls after SuspendAll.
+    */
+    if (_pr_GCLockHook) {
+        for (lhook = _pr_GCLockHook->next; lhook != _pr_GCLockHook; 
+          lhook = lhook->next) {
+          (*lhook->func)(PR_GCBEGIN, lhook->arg);
+        }
+    }
+
+    PR_SuspendAll();
+
+#ifdef GCMETER
+    /* Reset meter info */
+    if (_pr_gcMeter & _GC_METER_STATS) {
+        fprintf(stderr,
+                "[GCSTATS: busy:%ld skipped:%ld, alloced:%ld+wasted:%ld+free:%ld = total:%ld]\n",
+                (long) _pr_gcData.busyMemory,
+                (long) meter.skippedFreeChunks,
+                (long) meter.allocBytes,
+                (long) meter.wastedBytes,
+                (long) _pr_gcData.freeMemory,
+                (long) _pr_gcData.allocMemory);
+    }        
+    memset(&meter, 0, sizeof(meter));
+#endif
+
+    PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, ("begin mark phase; busy=%d free=%d total=%d",
+                     _pr_gcData.busyMemory, _pr_gcData.freeMemory,
+                     _pr_gcData.allocMemory));
+
+    if (_pr_beginGCHook) {
+    (*_pr_beginGCHook)(_pr_beginGCHookArg);
+    }
+
+    /*
+    ** Initialize scanQ to all zero's so that root finder doesn't walk
+    ** over it...
+    */
+    memset(&scanQ, 0, sizeof(scanQ));
+    pScanQ = &scanQ;
+
+    /******************************************/
+    /* MARK PHASE */
+
+    EmptyFreelists();
+
+    /* Find root's */
+    PR_LOG(_pr_msgc_lm, PR_LOG_WARNING,
+           ("begin mark phase; busy=%d free=%d total=%d",
+        _pr_gcData.busyMemory, _pr_gcData.freeMemory,
+            _pr_gcData.allocMemory));
+    METER(_pr_scanDepth = 0);
+    rf = _pr_rootFinders;
+    while (rf) {
+    _GCTRACE(GC_ROOTS, ("finding roots in %s", rf->name));
+    (*rf->func)(rf->arg);
+    rf = rf->next;
+    }
+    _GCTRACE(GC_ROOTS, ("done finding roots"));
+
+    /* Scan remaining object's that need scanning */
+    ScanScanQ(&scanQ);
+    PR_ASSERT(pScanQ == &scanQ);
+    PR_ASSERT(scanQ.queued == 0);
+    METER({
+    if (_pr_scanDepth > _pr_maxScanDepth) {
+        _pr_maxScanDepth = _pr_scanDepth;
+    }
+    });
+
+    /******************************************/
+    /* FINALIZATION PHASE */
+
+    METER(_pr_scanDepth = 0);
+    PrepareFinalize();
+
+    /* Scan any resurrected objects found during finalization */
+    ScanScanQ(&scanQ);
+    PR_ASSERT(pScanQ == &scanQ);
+    PR_ASSERT(scanQ.queued == 0);
+    METER({
+    if (_pr_scanDepth > _pr_maxScanDepth) {
+        _pr_maxScanDepth = _pr_scanDepth;
+    }
+    });
+    pScanQ = 0;
+
+    /******************************************/
+    /* SWEEP PHASE */
+
+    /*
+    ** Sweep each segment clean. While we are at it, figure out which
+    ** segment has the most free space and make that the current segment.
+    */
+    CheckWeakLinks();
+    _GCTRACE(GC_SWEEP, ("begin sweep phase"));
+    _pr_gcData.freeMemory = 0;
+    _pr_gcData.busyMemory = 0;
+    sp = segs;
+    esp = sp + nsegs;
+    while (sp < esp) {
+        if (SweepSegment(sp)) {
+            /*
+            ** Segment is now free and has been replaced with a different
+            ** segment object.
+            */
+            esp--;
+            continue;
+        }
+        sp++;
+    }
+
+#if defined(GCMETER) || defined(GCTIMINGHOOK)
+    end = PR_Now();
+#endif
+#ifdef GCMETER
+    LL_SUB(diff, end, start);
+    PR_LOG(GC, PR_LOG_ALWAYS,
+	   ("done; busy=%d free=%d chunks=%d total=%d time=%lldms",
+	    _pr_gcData.busyMemory, _pr_gcData.freeMemory,
+	    meter.numFreeChunks, _pr_gcData.allocMemory, diff));
+    if (_pr_gcMeter & _GC_METER_FREE_LIST) {
+        PRIntn bin;
+        fprintf(stderr, "Freelist bins:\n");
+        for (bin = 0; bin < NUM_BINS; bin++) {
+            GCFreeChunk *cp = bins[bin];
+            while (cp != NULL) {
+                fprintf(stderr, "%3d: %p %8ld\n",
+                        bin, cp, (long) cp->chunkSize);
+                cp = cp->next;
+            }
+        }
+    }
+#endif
+
+    if (_pr_endGCHook) {
+    (*_pr_endGCHook)(_pr_endGCHookArg);
+    }
+
+    /* clear the running total of the bytes allocated via BigAlloc() */
+    bigAllocBytes = 0;
+
+    /* And resume multi-threading */
+    PR_ResumeAll();
+
+    if (_pr_GCLockHook) {
+        for (lhook = _pr_GCLockHook->prev; lhook != _pr_GCLockHook; 
+          lhook = lhook->prev) {
+          (*lhook->func)(PR_GCEND, lhook->arg);
+        }
+    }
+
+    /* Kick finalizer */
+    NotifyFinalizer();
+#ifdef GCTIMINGHOOK
+    if (_pr_gcData.gcTimingHook) {
+	PRInt32 time;
+	LL_SUB(diff, end, start);
+	LL_L2I(time, diff);
+	_pr_gcData.gcTimingHook(time);
+    }
+#endif
+}
+
+PR_IMPLEMENT(void) PR_GC(void)
+{
+    LOCK_GC();
+    dogc();
+    UNLOCK_GC();
+
+    EmptyWeakFreeList();
+}
+
+/*******************************************************************************
+ * Heap Walker
+ ******************************************************************************/
+
+/*
+** This is yet another disgusting copy of the body of ProcessRootPointer
+** (the other being ProcessRootBlock), but we're not leveraging a single
+** function in their cases in interest of performance (avoiding the function
+** call).
+*/
+static PRInt32 PR_CALLBACK
+pr_ConservativeWalkPointer(void* ptr, PRWalkFun walkRootPointer, void* data)
+{
+  PRWord *p0, *p, *segBase;
+  GCSeg* sp;
+
+  p0 = (PRWord*) ptr;
+
+  /*
+  ** XXX:  
+  ** Until Win16 maintains lowSeg and highSeg correctly,
+  ** (ie. lowSeg=MIN(all segs) and highSeg = MAX(all segs))
+  ** Allways scan through the segment list
+  */
+#if !defined(WIN16)
+  if (p0 < _pr_gcData.lowSeg) return 0;                  /* below gc heap */
+  if (p0 >= _pr_gcData.highSeg) return 0;                /* above gc heap */
+#endif
+
+  /* NOTE: inline expansion of InHeap */
+  /* Find segment */
+  sp = lastInHeap;
+  if (!sp || !IN_SEGMENT(sp,p0)) {
+    GCSeg *esp;
+    sp = segs;
+    esp = segs + nsegs;
+    for (; sp < esp; sp++) {
+      if (IN_SEGMENT(sp, p0)) {
+	lastInHeap = sp;
+	goto find_object;
+      }
+    }
+    return 0;
+  }
+
+  find_object:
+    /* NOTE: Inline expansion of FindObject */
+    /* Align p to it's proper boundary before we start fiddling with it */
+    p = (PRWord*) ((PRWord)p0 & ~(BYTES_PER_WORD-1L));
+    segBase = (PRWord *) sp->base;
+    do {
+        if (IS_HBIT(sp, p)) {
+            goto winner;
+        }
+        p--;
+    } while (p >= segBase);
+
+    /*
+    ** We have a pointer into the heap, but it has no header
+    ** bit. This means that somehow the very first object in the heap
+    ** doesn't have a header. This is impossible so when debugging
+    ** lets abort.
+    */
+#ifdef DEBUG
+    PR_Abort();
+#endif
+    return 0;
+
+ winner:
+    return walkRootPointer(p, data);
+}
+
+static int32 PR_CALLBACK
+pr_ConservativeWalkBlock(void **base, PRInt32 count,
+			 PRWalkFun walkRootPointer, void* data)
+{
+    PRWord *p0;
+    while (--count >= 0) {
+	PRInt32 status;
+        p0 = (PRWord*) *base++;
+	status = pr_ConservativeWalkPointer(p0, walkRootPointer, data);
+	if (status) return status;
+    }
+    return 0;
+}
+
+/******************************************************************************/
+
+typedef void (*WalkObject_t)(FILE *out, GCType* tp, PRWord *obj,
+			     size_t bytes, PRBool detailed);
+typedef void (*WalkUnknown_t)(FILE *out, GCType* tp, PRWord tix, PRWord *p,
+			      size_t bytes, PRBool detailed);
+typedef void (*WalkFree_t)(FILE *out, PRWord *p, size_t size, PRBool detailed);
+typedef void (*WalkSegment_t)(FILE *out, GCSeg* sp, PRBool detailed);
+
+static void
+pr_WalkSegment(FILE* out, GCSeg* sp, PRBool detailed,
+           char* enterMsg, char* exitMsg,
+           WalkObject_t walkObject, WalkUnknown_t walkUnknown, WalkFree_t walkFree)
+{
+    PRWord *p, *limit;
+
+    p = (PRWord *) sp->base;
+    limit = (PRWord *) sp->limit;
+    if (enterMsg)
+    fprintf(out, enterMsg, p);
+    while (p < limit)
+    {
+    if (IS_HBIT(sp, p)) /* Is this an object header? */
+    {
+        PRWord h = p[0];
+        PRWord tix = GET_TYPEIX(h);
+        size_t bytes = OBJ_BYTES(h);
+        PRWord* np = (PRWord*) ((char*)p + bytes);
+
+        GCType* tp = &_pr_collectorTypes[tix].gctype;
+        if ((0 != tp) && walkObject)
+        walkObject(out, tp, p, bytes, detailed);
+        else if (walkUnknown)
+        walkUnknown(out, tp, tix, p, bytes, detailed);
+        p = np;
+    }
+    else
+    {
+        /* Must be a freelist item */
+        size_t size = ((GCFreeChunk*)p)->chunkSize;
+        if (walkFree)
+        walkFree(out, p, size, detailed);
+        p = (PRWord*)((char*)p + size);
+    }
+    }
+    if (p != limit)
+    fprintf(out, "SEGMENT OVERRUN (end should be at 0x%p)\n", limit);
+    if (exitMsg)
+    fprintf(out, exitMsg, p);
+}
+
+static void
+pr_WalkSegments(FILE *out, WalkSegment_t walkSegment, PRBool detailed)
+{
+    GCSeg *sp = segs;
+    GCSeg *esp;
+
+    LOCK_GC();
+    esp = sp + nsegs;
+    while (sp < esp)
+    {
+    walkSegment(out, sp, detailed);
+    sp++;
+    }
+    fprintf(out, "End of heap\n");
+    UNLOCK_GC();
+}
+
+/*******************************************************************************
+ * Heap Dumper
+ ******************************************************************************/
+
+PR_IMPLEMENT(void)
+PR_DumpIndent(FILE *out, int indent)
+{
+    while (--indent >= 0)
+    fprintf(out, " ");
+}
+
+static void
+PR_DumpHexWords(FILE *out, PRWord *p, int nWords,
+        int indent, int nWordsPerLine)
+{
+    while (nWords > 0)
+    {
+    int i;
+
+    PR_DumpIndent(out, indent);
+    i = nWordsPerLine;
+    if (i > nWords)
+        i = nWords;
+    nWords -= i;
+    while (i--)
+    {
+        fprintf(out, "0x%.8lX", (long) *p++);
+        if (i)
+        fputc(' ', out);
+    }
+    fputc('\n', out);
+    }
+}
+
+static void PR_CALLBACK
+pr_DumpObject(FILE *out, GCType* tp, PRWord *p, 
+          size_t bytes, PRBool detailed)
+{
+    char kindChar = tp->kindChar;
+    fprintf(out, "0x%p: 0x%.6lX %c  ",
+            p, (long) bytes, kindChar ? kindChar : '?');
+    if (tp->dump)
+    (*tp->dump)(out, (void*) (p + 1), detailed, 0);
+    if (detailed)
+    PR_DumpHexWords(out, p, bytes>>2, 22, 4);
+}
+    
+static void PR_CALLBACK
+pr_DumpUnknown(FILE *out, GCType* tp, PRWord tix, PRWord *p, 
+           size_t bytes, PRBool detailed)
+{
+    char kindChar = tp->kindChar;
+    fprintf(out, "0x%p: 0x%.6lX %c  ",
+            p, (long) bytes, kindChar ? kindChar : '?');
+    fprintf(out, "UNKNOWN KIND %ld\n", (long) tix);
+    if (detailed)
+    PR_DumpHexWords(out, p, bytes>>2, 22, 4);
+}
+
+static void PR_CALLBACK
+pr_DumpFree(FILE *out, PRWord *p, size_t size, PRBool detailed)
+{
+#if defined(XP_MAC) && XP_MAC
+# pragma unused( detailed )
+#endif
+
+    fprintf(out, "0x%p: 0x%.6lX -  FREE\n", p, (long) size);
+}
+
+static void PR_CALLBACK
+pr_DumpSegment(FILE* out, GCSeg* sp, PRBool detailed)
+{
+    pr_WalkSegment(out, sp, detailed,
+           "\n   Address: Length\n0x%p: Beginning of segment\n",
+           "0x%p: End of segment\n\n",
+           pr_DumpObject, pr_DumpUnknown, pr_DumpFree);
+}
+
+static void pr_DumpRoots(FILE *out);
+
+/*
+** Dump out the GC heap.
+*/
+PR_IMPLEMENT(void)
+PR_DumpGCHeap(FILE *out, PRBool detailed)
+{
+    fprintf(out, "\n"
+        "The kinds are:\n"
+        " U unscanned block\n"
+        " W weak link block\n"
+        " S scanned block\n"
+        " F scanned and final block\n"
+        " C class record\n"
+        " X context record\n"
+        " - free list item\n"
+        " ? other\n");
+    LOCK_GC();
+    pr_WalkSegments(out, pr_DumpSegment, detailed);
+    if (detailed)
+    pr_DumpRoots(out);
+    UNLOCK_GC();
+}
+
+PR_IMPLEMENT(void)
+PR_DumpMemory(PRBool detailed)
+{
+    PR_DumpToFile("memory.out", "Dumping memory", PR_DumpGCHeap, detailed);
+}
+
+/******************************************************************************/
+
+static int32 PR_CALLBACK
+pr_DumpRootPointer(PRWord* p, void* data)
+{
+#ifdef XP_MAC
+#pragma unused(data)
+#endif
+    PRWord h = p[0];
+    PRWord tix = GET_TYPEIX(h);
+      size_t bytes = OBJ_BYTES(h);
+      
+      GCType* tp = &_pr_collectorTypes[tix].gctype;
+      if (0 != tp)
+      pr_DumpObject(_pr_gcData.dumpOutput, tp, p, bytes, PR_FALSE);
+      else
+      pr_DumpUnknown(_pr_gcData.dumpOutput, tp, tix, p, bytes, PR_FALSE);
+    return 0;
+}
+
+static void PR_CALLBACK
+pr_ConservativeDumpRootPointer(void* ptr)
+{
+    (void)pr_ConservativeWalkPointer(ptr, (PRWalkFun) pr_DumpRootPointer, NULL);
+}
+
+static void PR_CALLBACK
+pr_ConservativeDumpRootBlock(void **base, PRInt32 count)
+{
+    (void)pr_ConservativeWalkBlock(base, count, (PRWalkFun) pr_DumpRootPointer, NULL);
+}
+
+extern int
+DumpThreadRoots(PRThread *t, int i, void *notused);
+
+static void
+pr_DumpRoots(FILE *out)
+{
+    RootFinder *rf;
+    void (*liveBlock)(void **base, PRInt32 count);
+    void (*livePointer)(void *ptr);
+    void (*processRootBlock)(void **base, PRInt32 count);
+    void (*processRootPointer)(void *ptr);
+
+    LOCK_GC();
+
+    liveBlock = _pr_gcData.liveBlock;
+    livePointer = _pr_gcData.livePointer;
+    processRootBlock = _pr_gcData.processRootBlock;
+    processRootPointer = _pr_gcData.processRootPointer;
+    
+    _pr_gcData.liveBlock = pr_ConservativeDumpRootBlock;
+    _pr_gcData.livePointer = pr_ConservativeDumpRootPointer;
+    _pr_gcData.processRootBlock = pr_ConservativeDumpRootBlock;
+    _pr_gcData.processRootPointer = pr_ConservativeDumpRootPointer;
+    _pr_gcData.dumpOutput = out;
+
+    rf = _pr_rootFinders;
+    while (rf) {
+    fprintf(out, "\n===== Roots for %s\n", rf->name);
+    (*rf->func)(rf->arg);
+    rf = rf->next;
+    }
+
+    _pr_gcData.liveBlock = liveBlock;
+    _pr_gcData.livePointer = livePointer;
+    _pr_gcData.processRootBlock = processRootBlock;
+    _pr_gcData.processRootPointer = processRootPointer;
+    _pr_gcData.dumpOutput = NULL;
+
+    UNLOCK_GC();
+}
+
+/*******************************************************************************
+ * Heap Summary Dumper
+ ******************************************************************************/
+
+PRSummaryPrinter summaryPrinter = NULL;
+void* summaryPrinterClosure = NULL;
+
+PR_IMPLEMENT(void) 
+PR_RegisterSummaryPrinter(PRSummaryPrinter fun, void* closure)
+{
+    summaryPrinter = fun;
+    summaryPrinterClosure = closure;
+}
+
+static void PR_CALLBACK
+pr_SummarizeObject(FILE *out, GCType* tp, PRWord *p,
+           size_t bytes, PRBool detailed)
+{
+#if defined(XP_MAC) && XP_MAC
+# pragma unused( out, detailed )
+#endif
+
+    if (tp->summarize)
+    (*tp->summarize)((void GCPTR*)(p + 1), bytes);
+}
+
+static void PR_CALLBACK
+pr_DumpSummary(FILE* out, GCSeg* sp, PRBool detailed)
+{
+    pr_WalkSegment(out, sp, detailed, NULL, NULL,
+           pr_SummarizeObject, NULL, NULL);
+}
+
+PR_IMPLEMENT(void)
+PR_DumpGCSummary(FILE *out, PRBool detailed)
+{
+    if (summaryPrinter) {
+    pr_WalkSegments(out, pr_DumpSummary, detailed);
+    summaryPrinter(out, summaryPrinterClosure);
+    }
+#if 0
+    fprintf(out, "\nFinalizable objects:\n");
+    {
+    PRCList *qp;
+    qp = _pr_pendingFinalQueue.next;
+    while (qp != &_pr_pendingFinalQueue) {
+        GCFinal* fp = FinalPtr(qp);
+        PRWord h = fp->object[0];        /* Grab header word */
+        PRWord tix = GET_TYPEIX(h);
+        GCType* tp = _pr_gcTypes[tix];
+        size_t bytes = OBJ_BYTES(h);
+        pr_DumpObject(out, tp, fp->object, bytes, PR_FALSE);
+        qp = qp->next;
+    }
+    }
+#endif
+}
+
+PR_IMPLEMENT(void)
+PR_DumpMemorySummary(void)
+{
+    PR_DumpToFile("memory.out", "Memory Summary", PR_DumpGCSummary, PR_FALSE);
+}
+
+/*******************************************************************************
+ * End Of Heap Walker 
+ ******************************************************************************/
+
+#ifdef GC_TRACEROOTS
+
+PRInt32 pr_traceGen = 0;
+
+static PRBool
+pr_IsMarked(PRWord* p)
+{
+    GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd));
+    PR_ASSERT(end->check == PR_BLOCK_END);
+    return end->traceGeneration == pr_traceGen;
+}
+
+static void
+pr_Mark(PRWord* p)
+{
+    GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd));
+    PR_ASSERT(end->check == PR_BLOCK_END);
+    end->traceGeneration = pr_traceGen;
+}
+
+PRWord* pr_traceObj;	/* set this in the debugger, then execute PR_TraceRoot() */
+
+static PRInt32 PR_CALLBACK
+pr_TraceRootObject(void* obj, void* data);
+
+static int32 PR_CALLBACK
+pr_TraceRootPointer(PRWord *p, void* data)
+{
+    PRInt32 printTrace = 0;
+    PRWord h = p[0];
+    PRWord tix = GET_TYPEIX(h);
+    GCType* tp = &_pr_collectorTypes[tix].gctype;
+    FILE* out = _pr_gcData.dumpOutput;
+
+    PR_ASSERT(tp);
+    if (pr_IsMarked(p))
+	return printTrace;
+
+    pr_Mark(p);
+    if (p == pr_traceObj) {
+	fprintf(out, "\n### Found path to:\n");
+	printTrace = 1;
+    }
+    else {
+	if (PR_StackSpaceLeft(PR_CurrentThread()) < 512) {
+	    fprintf(out, "\n### Path too deep (giving up):\n");
+	    printTrace = 1;
+	}
+	else if (tp->walk) {
+	    printTrace = tp->walk((void*)(p + 1), pr_TraceRootObject, data);
+	}
+	/* else there's no way to walk this object, so we
+	   haven't found what we're looking for */
+    }
+
+    if (printTrace == 1) {
+	PR_ASSERT(tp->dump);
+	fprintf(out, "0x%p: ", p);
+	tp->dump(out, (void*)(p + 1), PR_FALSE, 1);
+    }
+    return printTrace;
+}
+
+static PRInt32 PR_CALLBACK
+pr_TraceRootObject(void* obj, void* data)
+{
+    /* This version of pr_TraceRootPointer takes object
+       pointers, instead of gc header pointers. */
+    return pr_TraceRootPointer((PRWord*)obj - 1, data);
+}
+
+static void PR_CALLBACK
+pr_ConservativeTraceRootPointer(PRWord *p)
+{
+    PRInt32 status;
+    ++pr_traceGen;
+    status = pr_ConservativeWalkPointer(p, pr_TraceRootPointer, NULL);
+    if (status) {
+	FILE* out = _pr_gcData.dumpOutput;
+	fprintf(out, "### from root at 0x%p\n\n", p);
+    }
+}
+
+static void PR_CALLBACK
+pr_ConservativeTraceRootBlock(void **base, PRInt32 count)
+{
+    PRInt32 status;
+    ++pr_traceGen;
+    status = pr_ConservativeWalkBlock(base, count, pr_TraceRootPointer, NULL);
+    if (status) {
+	FILE* out = _pr_gcData.dumpOutput;
+	fprintf(out, "### from root in range 0x%p + 0x%lx\n\n",
+                base, (long) count);
+    }
+}
+
+static void
+PR_TraceRoot1(FILE* out, PRBool detailed)
+{
+    RootFinder *rf;
+    void (*liveBlock)(void **base, PRInt32 count);
+    void (*livePointer)(void *ptr);
+    void (*processRootBlock)(void **base, PRInt32 count);
+    void (*processRootPointer)(void *ptr);
+
+    LOCK_GC();
+
+    liveBlock = _pr_gcData.liveBlock;
+    livePointer = _pr_gcData.livePointer;
+    processRootBlock = _pr_gcData.processRootBlock;
+    processRootPointer = _pr_gcData.processRootPointer;
+    
+    _pr_gcData.liveBlock = pr_ConservativeTraceRootBlock;
+    _pr_gcData.livePointer = pr_ConservativeTraceRootPointer;
+    _pr_gcData.processRootBlock = pr_ConservativeTraceRootBlock;
+    _pr_gcData.processRootPointer = pr_ConservativeTraceRootPointer;
+    _pr_gcData.dumpOutput = out;
+
+    fprintf(out, "### Looking for paths to 0x%p\n\n", pr_traceObj);
+
+    rf = _pr_rootFinders;
+    while (rf) {
+	fprintf(out, "\n===== Roots for %s\n", rf->name);
+	(*rf->func)(rf->arg);
+	rf = rf->next;
+    }
+
+    _pr_gcData.liveBlock = liveBlock;
+    _pr_gcData.livePointer = livePointer;
+    _pr_gcData.processRootBlock = processRootBlock;
+    _pr_gcData.processRootPointer = processRootPointer;
+    _pr_gcData.dumpOutput = NULL;
+
+    UNLOCK_GC();
+}
+
+PR_PUBLIC_API(void)
+PR_TraceRoot()
+{
+    /*
+    ** How this works: 
+    ** Once you find the object you want to trace the roots of, set the
+    ** global variable pr_traceObj to point to it (the header, not the
+    ** java handle), and then call this routine (on Windows, you can set
+    ** a breakpoint at the end of a function that returns void (e.g. dogc)
+    ** and then do a "set next statement" to point to this routine and go.
+    ** This will dump a list of the paths from the roots to the object in
+    ** question to your memory.out file.
+    */
+    PR_DumpToFile("memory.out", "Tracing Roots", PR_TraceRoot1, PR_FALSE);
+}
+
+#endif /* GC_TRACEROOTS */
+
+/******************************************************************************/
+
+#if defined(DEBUG) && defined(WIN32)
+static void DumpApplicationHeap(FILE *out, HANDLE heap)
+{
+    PROCESS_HEAP_ENTRY entry;
+    DWORD err;
+
+    if (!HeapLock(heap))
+    OutputDebugString("Can't lock the heap.\n");
+    entry.lpData = 0;
+    fprintf(out, "   address:       size ovhd region\n");
+    while (HeapWalk(heap, &entry))
+    {
+    WORD flags = entry.wFlags;
+
+    fprintf(out, "0x%.8X: 0x%.8X 0x%.2X 0x%.2X  ", entry.lpData, entry.cbData,
+        entry.cbOverhead, entry.iRegionIndex);
+    if (flags & PROCESS_HEAP_REGION)
+        fprintf(out, "REGION  committedSize=0x%.8X uncommittedSize=0x%.8X firstBlock=0x%.8X lastBlock=0x%.8X",
+            entry.Region.dwCommittedSize, entry.Region.dwUnCommittedSize,
+            entry.Region.lpFirstBlock, entry.Region.lpLastBlock);
+    else if (flags & PROCESS_HEAP_UNCOMMITTED_RANGE)
+        fprintf(out, "UNCOMMITTED");
+    else if (flags & PROCESS_HEAP_ENTRY_BUSY)
+    {
+        if (flags & PROCESS_HEAP_ENTRY_DDESHARE)
+        fprintf(out, "DDEShare ");
+        if (flags & PROCESS_HEAP_ENTRY_MOVEABLE)
+        fprintf(out, "Moveable Block  handle=0x%.8X", entry.Block.hMem);
+        else
+        fprintf(out, "Block");
+    }
+    fprintf(out, "\n");
+    }
+    if ((err = GetLastError()) != ERROR_NO_MORE_ITEMS)
+    fprintf(out, "ERROR %d iterating through the heap\n", err);
+    if (!HeapUnlock(heap))
+    OutputDebugString("Can't unlock the heap.\n");
+}
+#endif
+
+#if defined(DEBUG) && defined(WIN32)
+static void DumpApplicationHeaps(FILE *out)
+{
+    HANDLE mainHeap;
+    HANDLE heaps[100];
+    DWORD nHeaps;
+    PRInt32 i;
+
+    mainHeap = GetProcessHeap();
+    nHeaps = GetProcessHeaps(100, heaps);
+    if (nHeaps > 100)
+    nHeaps = 0;
+    fprintf(out, "%ld heaps:\n", (long) nHeaps);
+    for (i = 0; i<nHeaps; i++)
+    {
+    HANDLE heap = heaps[i];
+
+    fprintf(out, "Heap at 0x%.8lX", (long) heap);
+    if (heap == mainHeap)
+        fprintf(out, " (main)");
+    fprintf(out, ":\n");
+    DumpApplicationHeap(out, heap);
+    fprintf(out, "\n");
+    }
+    fprintf(out, "End of heap dump\n\n");
+}
+#endif
+
+#if defined(DEBUG) && defined(WIN32)
+PR_IMPLEMENT(void) PR_DumpApplicationHeaps(void)
+{
+    FILE *out;
+
+    OutputDebugString("Dumping heaps...");
+    out = fopen("heaps.out", "a");
+    if (!out)
+    OutputDebugString("Can't open \"heaps.out\"\n");
+    else
+    {
+    struct tm *newtime;
+    time_t aclock;
+
+    time(&aclock);
+    newtime = localtime(&aclock);
+    fprintf(out, "Heap dump on %s\n", asctime(newtime));    /* Print current time */
+    DumpApplicationHeaps(out);
+    fprintf(out, "\n\n");
+    fclose(out);
+    }
+    OutputDebugString(" done\n");
+}
+#else
+
+PR_IMPLEMENT(void) PR_DumpApplicationHeaps(void)
+{
+    fprintf(stderr, "Native heap dumping is currently implemented only for Windows32.\n");
+}
+#endif
+
+/************************************************************************/
+
+/*
+** Scan the freelist bins looking for a big enough chunk of memory to
+** hold "bytes" worth of allocation. "bytes" already has the
+** per-allocation header added to it. Return a pointer to the object with
+** its per-allocation header already prepared.
+*/
+static PRWord *BinAlloc(int cbix, PRInt32 bytes, int dub)
+{
+    GCFreeChunk **cpp, *cp, *cpNext;
+    GCSeg *sp;
+    PRInt32 chunkSize, remainder;
+    PRWord *p, *np;
+    PRInt32 bin, newbin;
+
+    /* Compute bin that allocation belongs in */
+    InlineBinNumber(bin,bytes)
+    if (bin < minBin) {
+    bin = minBin;    /* Start at first filled bin */
+    }
+
+    /* Search in the bin, and larger bins, for a big enough piece */
+    for (; bin <= NUM_BINS-1; bin++) {
+        cpp = &bins[bin];
+    while ((cp = *cpp) != 0) {
+        chunkSize = cp->chunkSize;
+        if (chunkSize < bytes) {
+        /* Too small; skip it */
+            METER(meter.skippedFreeChunks++);
+        cpp = &cp->next;
+        continue;
+        }
+
+        /* We have found a hunk of memory large enough to use */
+        p = (PRWord*) cp;
+        sp = cp->segment;
+        cpNext = cp->next;
+#ifndef IS_64
+        if (dub && (((PRWord)p & (PR_BYTES_PER_DWORD-1)) == 0)) {
+        /*
+         * We are double aligning the memory and the current free
+         * chunk is aligned on an even boundary. Because header
+         * words are one word long we need to discard the first
+         * word of memory.
+         */
+        p[0] = MAKE_HEADER(FREE_MEMORY_TYPEIX, 1);
+        SET_HBIT(sp, p);
+        p++;
+        chunkSize -= PR_BYTES_PER_WORD;
+        bytes -= PR_BYTES_PER_WORD;
+        PR_ASSERT(((PRWord)p & (PR_BYTES_PER_DWORD-1)) != 0);
+        _pr_gcData.freeMemory -= PR_BYTES_PER_WORD;
+        _pr_gcData.busyMemory += PR_BYTES_PER_WORD;
+        }
+#endif
+        np = (PRWord*) ((char*) p + bytes);
+        remainder = chunkSize - bytes;
+        if (remainder >= MIN_FREE_CHUNK_BYTES) {
+        /* The left over memory is large enough to be freed. */
+        cp = (GCFreeChunk*) np;
+        cp->segment = sp;
+        cp->chunkSize = remainder;
+        InlineBinNumber(newbin, remainder)
+        if (newbin != bin) {
+            *cpp = (GCFreeChunk*) cpNext; /* remove */
+            cp->next = bins[newbin];      /* insert */
+            bins[newbin] = cp;
+            if (newbin < minBin) minBin = newbin;
+            if (newbin > maxBin) maxBin = newbin;
+        } else {
+            /* Leave it on the same list */
+            cp->next = cpNext;
+            *cpp = (GCFreeChunk*) np;
+        }
+        } else {
+        /*
+         * The left over memory is too small to be released. Just
+         * leave it attached to the chunk of memory being
+         * returned.
+         */
+        *cpp = cpNext;
+        bytes = chunkSize;
+        }
+        p[0] = MAKE_HEADER(cbix, (bytes >> PR_BYTES_PER_WORD_LOG2));
+        SET_HBIT(sp, p);
+        _pr_gcData.freeMemory -= bytes;
+        _pr_gcData.busyMemory += bytes;
+        return p;
+    }
+    }
+    return 0;
+}
+
+/*
+** Allocate a piece of memory that is "big" in it's own segment.  Make
+** the object consume the entire segment to avoid fragmentation.  When
+** the object is no longer referenced, the segment is freed.
+*/
+static PRWord *BigAlloc(int cbix, PRInt32 bytes, int dub)
+{
+    GCSeg *sp;
+    PRWord *p, h;
+    PRInt32 chunkSize;
+
+    /*
+    ** If the number of bytes allocated via BigAlloc() since the last GC
+    ** exceeds BIG_ALLOC_GC_SIZE then do a GC Now...
+    */
+    if (bigAllocBytes >= BIG_ALLOC_GC_SIZE) {
+        dogc();
+    }
+    bigAllocBytes += bytes;
+
+    /* Get a segment to hold this allocation */
+    sp = GrowHeapExactly(bytes);
+
+    if (sp) {
+        p = (PRWord*) sp->base;
+        chunkSize = sp->limit - sp->base;
+
+        /* All memory is double aligned on 64 bit machines... */
+#ifndef IS_64
+        if (dub && (((PRWord)p & (PR_BYTES_PER_DWORD-1)) == 0)) {
+            /*
+            ** Consume the first word of the chunk with a dummy
+            ** unreferenced object.
+            */
+            p[0] = MAKE_HEADER(FREE_MEMORY_TYPEIX, 1);
+            SET_HBIT(sp, p);
+            p++;
+            chunkSize -= PR_BYTES_PER_WORD;
+            _pr_gcData.freeMemory -= PR_BYTES_PER_WORD;
+            _pr_gcData.busyMemory += PR_BYTES_PER_WORD;
+            PR_ASSERT(((PRWord)p & (PR_BYTES_PER_DWORD-1)) != 0);
+        }
+#endif
+
+#if defined(WIN16)
+            /* All memory MUST be aligned on 32bit boundaries */
+            PR_ASSERT( (((PRWord)p) & (PR_BYTES_PER_WORD-1)) == 0 );
+#endif
+
+        /* Consume the *entire* segment with a single allocation */
+        h = MAKE_HEADER(cbix, (chunkSize >> PR_BYTES_PER_WORD_LOG2));
+        p[0] = h;
+        SET_HBIT(sp, p);
+        _pr_gcData.freeMemory -= chunkSize;
+        _pr_gcData.busyMemory += chunkSize;
+    return p;
+    }
+    return 0;
+}
+
+/* we disable gc allocation during low memory conditions */
+static PRBool allocationEnabled = PR_TRUE;
+
+PR_IMPLEMENT(void) PR_EnableAllocation(PRBool yesOrNo)
+{
+    allocationEnabled = yesOrNo;
+}
+
+static void CollectorCleanup(void) {
+    while (collectorCleanupNeeded) {
+    LOCK_GC();
+    collectorCleanupNeeded = 0;
+    UNLOCK_GC();
+    if (freeSegs) {
+        FreeSegments();
+    }
+    if (!WEAK_FREELIST_ISEMPTY()) {
+        EmptyWeakFreeList();
+    }
+    }
+}
+
+/******************************************************************************/
+
+#ifdef GC_CHECK
+static PRInt32 allocationCount;
+
+static void EarthShatteringKaBoom(PRInt32 whichOne) {
+    long* p = 0;
+    *p = 0;
+}
+
+/* Check a segment of heap memory. Verify that the object memory
+   hasn't been overwritten (past the end at least) */
+static void CheckSegment(GCSeg* sp) {
+    PRWord h, tix;
+    PRWord *p, *lastp, *np, *limit;
+
+    lastp = p = (PRWord *) sp->base;
+    limit = (PRWord *) sp->limit;
+    while (p < limit) {
+    if (IS_HBIT(sp, p)) {
+	    char *cp, i;
+	    GCBlockEnd* end;
+	    PRWord bytes, requestedBytes;
+
+	    h = p[0];
+	    tix = GET_TYPEIX(h);
+	    bytes = OBJ_BYTES(h);
+	    np = (PRWord *) ((char *)p + bytes);
+	    if (tix != FREE_MEMORY_TYPEIX) {
+                PRInt32 test;	/* msdev get's fooled without this local */
+		/* A live object is here. The last word in the object will
+		   contain the objects requestedSize */
+		end = (GCBlockEnd*)((char*)(p) + bytes - sizeof(GCBlockEnd));
+		test = end->check;
+		if (test != PR_BLOCK_END) {
+		    PR_ASSERT(test == PR_BLOCK_END);
+		}
+		requestedBytes = end->requestedBytes;
+		if (requestedBytes >= bytes) EarthShatteringKaBoom(0);
+		cp = (char*)(p + 1) + requestedBytes;
+		i = (char) 0xff;
+		while (cp < (char*)end) {
+            if (*cp != i) EarthShatteringKaBoom(1);
+            cp++;
+            i--;
+        }
+        }
+        lastp = p;
+        p = np;
+    } else {
+        /* Must be a freelist item */
+        GCFreeChunk *cp = (GCFreeChunk*) p;
+        if ((PRInt32)cp->chunkSize < (PRInt32)sizeof(GCFreeChunk)) {
+            EarthShatteringKaBoom(3);
+        }
+        lastp = p;
+        p = (PRWord*) ((char*)p + cp->chunkSize);
+    }
+    }
+}
+
+static void CheckHeap(void) {
+    GCSeg *sp = segs;
+    GCSeg *esp = sp + nsegs;
+    while (sp < esp) {
+    CheckSegment(sp);
+    sp++;
+    }
+}
+
+#endif /* GC_CHECK */
+
+/******************************************************************************/
+
+#ifdef DEBUG
+long gc_thrash = -1L;
+#endif
+
+/*
+** Allocate memory from the GC Heap. Performs garbage collections if
+** memory gets tight and grows the heap as needed. May return NULL if
+** memory cannot be found.
+*/
+PR_IMPLEMENT(PRWord GCPTR *)PR_AllocMemory(
+    PRWord requestedBytes, PRInt32 tix, PRWord flags)
+{
+    PRWord *p;
+    CollectorType *ct;
+    PRInt32 bytes;
+    GCFinal *final = 0;
+    GCWeak *weak = 0;
+    int dub = flags & PR_ALLOC_DOUBLE;
+    PRInt32 objBytes;
+#ifdef GC_STATS
+    PRInt64 allocTime, ldelta;
+#endif
+
+    if (!allocationEnabled) return NULL;
+
+    PR_ASSERT(requestedBytes >= 0);
+    PR_ASSERT(_pr_collectorTypes[tix].flags != 0);
+
+#ifdef DEBUG
+    if (_pr_do_a_dump) {
+    /*
+    ** Collect, pause for a second (lets finalizer run), and then GC
+    ** again.
+    */
+    PR_GC();
+    PR_Sleep(PR_MicrosecondsToInterval(1000000L));
+    PR_GC();
+    PR_DumpGCHeap(_pr_dump_file, PR_TRUE);
+    _pr_do_a_dump = 0;
+    }
+#endif
+
+#ifdef GC_STATS
+    allocTime = PR_Now();
+#endif
+    bytes = (PRInt32) requestedBytes;
+
+    /*
+    ** Align bytes to a multiple of a PRWord, then add in enough space
+    ** to hold the header word.
+    **
+    ** MSVC 1.52 crashed on the ff. code because of the "complex" shifting :-(
+    */
+#if !defined(WIN16) 
+    /* Check for possible overflow of bytes before performing add */
+    if ((MAX_INT - PR_BYTES_PER_WORD) < bytes ) return NULL;
+    bytes = (bytes + PR_BYTES_PER_WORD - 1) >> PR_BYTES_PER_WORD_LOG2;
+    bytes <<= PR_BYTES_PER_WORD_LOG2;
+    /* Check for possible overflow of bytes before performing add */
+    if ((MAX_INT - sizeof(PRWord)) < bytes ) return NULL;
+    bytes += sizeof(PRWord);
+#else 
+    /* 
+    ** For WIN16 the shifts have been broken out into separate statements
+    ** to prevent the compiler from crashing...
+    */
+    {
+        PRWord shiftVal;
+
+        /* Check for possible overflow of bytes before performing add */
+        if ((MAX_INT - PR_BYTES_PER_WORD) < bytes ) return NULL;
+        bytes += PR_BYTES_PER_WORD - 1L;
+        shiftVal = PR_BYTES_PER_WORD_LOG2;
+        bytes >>= shiftVal;
+        bytes <<= shiftVal;
+        /* Check for possible overflow of bytes before performing add */
+        if ((MAX_INT - sizeof(PRWord)) < bytes ) return NULL;
+        bytes += sizeof(PRWord);
+    }
+#endif
+    /*
+     * Add in an extra word of memory for double-aligned memory. Some
+     * percentage of the time this will waste a word of memory (too
+     * bad). Howver, it makes the allocation logic much simpler and
+     * faster.
+     */
+#ifndef IS_64
+    if (dub) {
+        /* Check for possible overflow of bytes before performing add */
+        if ((MAX_INT - PR_BYTES_PER_WORD) < bytes ) return NULL;
+        bytes += PR_BYTES_PER_WORD;
+    }
+#endif
+
+#ifdef GC_CHECK
+    if (_pr_gcData.flags & GC_CHECK) {
+        /* Bloat the allocation a bit so that we can lay down
+           a check pattern that we will validate */
+        /* Check for possible overflow of bytes before performing add */
+        if ((MAX_INT - PR_BYTES_PER_WORD * 3) < bytes ) return NULL;
+        bytes += PR_BYTES_PER_WORD * 3;
+    }
+#endif
+
+#if defined(GC_CHECK) || defined(GC_STATS) || defined(GC_TRACEROOTS)
+    if ((MAX_INT - sizeof(GCBlockEnd)) < bytes ) return NULL;
+    bytes += sizeof(GCBlockEnd);
+#endif
+
+    PR_ASSERT( bytes < MAX_ALLOC_SIZE );
+    /*
+    ** Java can ask for objects bigger than MAX_ALLOC_SIZE,
+    ** but it won't get them.
+    */
+    if (bytes >= MAX_ALLOC_SIZE) return NULL;
+
+#ifdef DEBUG
+    if (gc_thrash == -1L ? (gc_thrash = (long)PR_GetEnv("GC_THRASH")):gc_thrash) PR_GC();
+#endif
+
+    ct = &_pr_collectorTypes[tix];
+    if (ct->flags & (_GC_TYPE_FINAL|_GC_TYPE_WEAK)) {
+    if (0 != ct->gctype.finalize) {
+        /*
+        ** Allocate a GCFinal struct for this object in advance. Don't put
+        ** it on the pending list until we have allocated the object
+        */
+        final = AllocFinalNode();
+        if (!final) {
+        /* XXX THIS IS NOT ACCEPTABLE*/
+		PR_ASSERT(0);
+        return 0;
+        }
+    }
+    if (0 != ct->gctype.getWeakLinkOffset) {
+        /*
+        ** Allocate a GCWeak struct for this object in advance. Don't put
+        ** it on the weak links list until we have allocated the object
+        */
+        weak = AllocWeakNode();
+        if (!weak) {
+        /* XXX THIS IS NOT ACCEPTABLE*/
+        if (0 != final) {
+            FreeFinalNode(final);
+        }
+		PR_ASSERT(0);
+        return 0;
+        }
+    }
+    }
+
+    LOCK_GC();
+#ifdef GC_CHECK
+    if (_pr_gcData.flags & GC_CHECK) CheckHeap();
+    allocationCount++;
+#endif
+
+    /* Check for overflow of maximum size we can handle */
+    if (bytes > MAX_ALLOC) goto lost;
+
+    /* Try default allocation */
+    p = ((bytes >= BIG_ALLOC) && (nsegs < MAX_SEGS)) ?
+        BigAlloc(tix, bytes, dub) : BinAlloc(tix, bytes, dub);
+    if (0 == p) {
+#ifdef GC_STATS
+        LL_SUB(ldelta, PR_Now(), allocTime);
+#endif
+        /* Collect some memory */
+        _GCTRACE(GC_ALLOC, ("force GC: want %d", bytes));
+        dogc();
+        PR_ASSERT( GC_IS_LOCKED() );
+
+        /* After a collection we check and see if we should grow the
+        ** heap. We grow the heap when the amount of memory free is less
+        ** than a certain percentage of the heap size. We don't check to
+        ** see if the grow succeeded because our fallback strategy in
+        ** either case is to try one more time to allocate. */
+        if ((_pr_gcData.allocMemory < _pr_gcData.maxMemory)
+        && ((_pr_gcData.freeMemory <
+            ((_pr_gcData.allocMemory * MIN_FREE_THRESHOLD_AFTER_GC) / 100L))
+        || (_pr_gcData.freeMemory < bytes))) {
+            GrowHeap(PR_MAX(bytes, segmentSize));
+        }
+#ifdef GC_STATS
+        LL_ADD(allocTime, PR_Now(), ldelta);
+#endif
+
+        /* Try again */
+        p = ((bytes >= BIG_ALLOC) && (nsegs < MAX_SEGS)) ?
+            BigAlloc(tix, bytes, dub) : BinAlloc(tix, bytes, dub);
+        if (0 == p) {
+            /* Well that lost big time. Memory must be pretty well fragmented */
+            if (!GrowHeap(PR_MAX(bytes, segmentSize))) goto lost;
+            p = BinAlloc(tix, bytes, dub);
+            if (0 == p) goto lost;
+        }
+    }
+
+    /* Zero out the portion of the object memory that was used by
+       the GCFreeChunk structure (skip the first word because it
+       was already overwritten by the gc header word) */
+    objBytes = OBJ_BYTES(p[0]);
+    if (objBytes > sizeof(PRWord)) p[1] = 0;
+    if (objBytes > sizeof(PRWord)*2) p[2] = 0;
+
+    if (final) {
+	_GCTRACE(GC_ALLOC, ("alloc 0x%x (%d) final=0x%x",
+                p, bytes, final));
+    final->object = p;
+    PR_APPEND_LINK(&final->links, &_pr_finalizeableObjects);
+    } else {
+	_GCTRACE(GC_ALLOC, ("alloc 0x%x (%d)", p, bytes));
+    }
+    if (weak) {
+    weak->object = p;
+    PR_APPEND_LINK(&weak->links, &_pr_weakLinks);
+    }
+    METER(meter.allocBytes += bytes);
+    METER(meter.wastedBytes += (bytes - requestedBytes));
+    UNLOCK_GC();
+
+    if (collectorCleanupNeeded) {
+	CollectorCleanup();
+    }
+
+#if defined(GC_CHECK) || defined(GC_STATS) || defined(GC_TRACEROOTS)
+    {
+	GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd));
+	end->check = PR_BLOCK_END;
+    }
+#endif
+#ifdef GC_STATS
+    {
+	PRInt64 now = PR_Now();
+	double delta;
+	PRInt32 bin;
+	GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd));
+
+	end->allocTime = allocTime;
+	LL_SUB(ldelta, now, allocTime);
+	LL_L2D(delta, ldelta);
+	InlineBinNumber(bin, requestedBytes);
+	end->bin = bin;
+	gcstats[bin].nallocs++;
+	gcstats[bin].allocTime += delta;
+	gcstats[bin].allocTimeVariance += delta * delta;
+    }
+#endif
+#ifdef GC_CHECK
+    if (_pr_gcData.flags & GC_CHECK) {
+    /* Place a pattern in the memory that was allocated that was not
+       requested. We will check the pattern later. */
+    char* cp = (char*)(p + 1) + requestedBytes;
+	GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd));
+	char i = (char) 0xff;
+	while (cp < (char*)end) {
+	    *cp++ = i--;
+	}
+	end->requestedBytes = requestedBytes;
+	CheckHeap();
+    }
+#endif
+    return p + 1;
+
+  lost:
+    /* Out of memory */
+    UNLOCK_GC();
+    if (final) {
+    FreeFinalNode(final);
+    }
+    if (weak) {
+    FreeWeakNode(weak);
+    }
+    if (collectorCleanupNeeded) {
+    CollectorCleanup();
+    }
+    return 0;
+}
+
+/* Shortcut allocator for objects that do not require finalization or
+   are weak objects */
+PR_IMPLEMENT(PRWord GCPTR *)
+PR_AllocSimpleMemory(PRWord requestedBytes, PRInt32 tix)
+{
+    PRWord *p;
+    PRInt32 bytes;
+    PRInt32 objBytes;
+#ifdef GC_STATS
+    PRInt64 allocTime, ldelta;
+#endif
+
+    if (!allocationEnabled) return NULL;
+
+    PR_ASSERT(requestedBytes >= 0);
+    PR_ASSERT(_pr_collectorTypes[tix].flags != 0);
+
+#ifdef DEBUG
+    if (_pr_do_a_dump) {
+	/*
+	** Collect, pause for a second (lets finalizer run), and then GC
+	** again.
+	*/
+	PR_GC();
+	PR_Sleep(PR_MicrosecondsToInterval(1000000L));
+	PR_GC();
+	PR_DumpGCHeap(_pr_dump_file, PR_TRUE);
+	_pr_do_a_dump = 0;
+    }
+#endif
+
+#ifdef GC_STATS
+    allocTime = PR_NowMS();
+#endif
+    bytes = (PRInt32) requestedBytes;
+
+    /*
+    ** Align bytes to a multiple of a PRWord, then add in enough space
+    ** to hold the header word.
+    **
+    ** MSVC 1.52 crashed on the ff. code because of the "complex" shifting :-(
+    */
+#if !defined(WIN16) 
+    bytes = (bytes + PR_BYTES_PER_WORD - 1) >> PR_BYTES_PER_WORD_LOG2;
+    bytes <<= PR_BYTES_PER_WORD_LOG2;
+    bytes += sizeof(PRWord);
+#else 
+    /* 
+    ** For WIN16 the shifts have been broken out into separate statements
+    ** to prevent the compiler from crashing...
+    */
+    {
+    PRWord shiftVal;
+
+    bytes += PR_BYTES_PER_WORD - 1L;
+    shiftVal = PR_BYTES_PER_WORD_LOG2;
+    bytes >>= shiftVal;
+    bytes <<= shiftVal;
+    bytes += sizeof(PRWord);
+    }
+#endif
+    
+    /*
+     * Add in an extra word of memory for double-aligned memory. Some
+     * percentage of the time this will waste a word of memory (too
+     * bad). Howver, it makes the allocation logic much simpler and
+     * faster.
+     */
+#ifndef IS_64
+    bytes += PR_BYTES_PER_WORD;
+#endif
+
+#ifdef GC_CHECK
+    if (_pr_gcData.flags & GC_CHECK) {
+    /* Bloat the allocation a bit so that we can lay down
+       a check pattern that we will validate */
+    bytes += PR_BYTES_PER_WORD * 2;
+    }
+#endif
+
+#if defined(GC_CHECK) || defined(GC_STATS) || defined(GC_TRACEROOTS)
+    bytes += sizeof(GCBlockEnd);
+#endif
+
+#if defined(WIN16)
+    PR_ASSERT( bytes < MAX_ALLOC_SIZE );
+#endif
+    /* Java can ask for objects bigger than 4M, but it won't get them */
+    if (bytes >= MAX_ALLOC_SIZE) {
+        return NULL;
+    }
+#ifdef DEBUG
+    if (gc_thrash == -1L
+	? (gc_thrash = (long)PR_GetEnv("GC_THRASH"))
+	: gc_thrash) {
+	PR_GC();
+    }
+#endif
+
+    LOCK_GC();
+#ifdef GC_CHECK
+    if (_pr_gcData.flags & GC_CHECK) {
+    CheckHeap();
+    }
+    allocationCount++;
+#endif
+
+    /* Try default allocation */
+    if ((bytes >= BIG_ALLOC) && (nsegs < MAX_SEGS)) {
+    p = BigAlloc(tix, bytes, 1);
+    } else {
+    p = BinAlloc(tix, bytes, 1);
+    }
+    if (0 == p) {
+#ifdef GC_STATS
+      LL_SUB(ldelta, PR_Now(), allocTime);
+#endif
+      /* Collect some memory */
+      _GCTRACE(GC_ALLOC, ("force GC: want %d", bytes));
+      dogc();
+      PR_ASSERT( GC_IS_LOCKED() );
+
+      /* After a collection we check and see if we should grow the
+     heap. We grow the heap when the amount of memory free is less
+     than a certain percentage of the heap size. We don't check to
+     see if the grow succeeded because our fallback strategy in
+     either case is to try one more time to allocate. */
+      if ((_pr_gcData.allocMemory < _pr_gcData.maxMemory) &&
+      (_pr_gcData.freeMemory <
+       ((_pr_gcData.allocMemory * MIN_FREE_THRESHOLD_AFTER_GC) / 100L))) {
+    GrowHeap(PR_MAX(bytes, segmentSize));
+      }
+#ifdef GC_STATS
+      LL_ADD(allocTime, PR_Now(), ldelta);
+#endif
+
+      /* Try one last time */
+      if ((bytes >= BIG_ALLOC) && (nsegs < MAX_SEGS)) {
+    p = BigAlloc(tix, bytes, 1);
+      } else {
+    p = BinAlloc(tix, bytes, 1);
+      }
+      if (0 == p) {
+    /* Well that lost big time. Memory must be pretty well fragmented */
+    if (!GrowHeap(PR_MAX(bytes, segmentSize))) {
+      goto lost;
+    }
+    p = BinAlloc(tix, bytes, 1);
+    if (0 == p) goto lost;
+      }
+    }
+
+    /* Zero out the portion of the object memory that was used by
+       the GCFreeChunk structure (skip the first word because it
+       was already overwritten by the gc header word) */
+    objBytes = OBJ_BYTES(p[0]);
+    if (objBytes > sizeof(PRWord)) p[1] = 0;
+    if (objBytes > sizeof(PRWord)*2) p[2] = 0;
+
+    METER(meter.allocBytes += bytes);
+    METER(meter.wastedBytes += (bytes - requestedBytes));
+    UNLOCK_GC();
+
+    if (collectorCleanupNeeded) {
+	CollectorCleanup();
+    }
+
+#if defined(GC_CHECK) || defined(GC_STATS) || defined(GC_TRACEROOTS)
+    {
+	GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd));
+	end->check = PR_BLOCK_END;
+    }
+#endif
+#ifdef GC_STATS
+    {
+	PRInt64 now = PR_Now();
+	double delta;
+	int32 bin;
+	GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd));
+
+	end->allocTime = allocTime;
+	LL_SUB(ldelta, now, allocTime);
+	LL_L2D(delta, ldelta);
+	InlineBinNumber(bin, requestedBytes);
+	end->bin = bin;
+	gcstats[bin].nallocs++;
+	gcstats[bin].allocTime += delta;
+	gcstats[bin].allocTimeVariance += delta * delta;
+    }
+#endif
+#ifdef GC_CHECK
+    if (_pr_gcData.flags & GC_CHECK) {
+    /* Place a pattern in the memory that was allocated that was not
+       requested. We will check the pattern later. */
+    char* cp = (char*)(p + 1) + requestedBytes;
+	GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd));
+	char i = (char) 0xff;
+	while (cp < (char*)end) {
+	    *cp++ = i--;
+	}
+	end->requestedBytes = requestedBytes;
+	CheckHeap();
+    }
+#endif
+    return p + 1;
+
+  lost:
+    /* Out of memory */
+    UNLOCK_GC();
+    if (collectorCleanupNeeded) {
+    CollectorCleanup();
+    }
+    return 0;
+}
+
+/************************************************************************/
+
+PR_IMPLEMENT(PRWord) PR_GetObjectHeader(void *ptr) {
+    GCSeg *sp;
+    PRWord *h;
+
+    if (ptr == 0) return 0;
+    sp = InHeap(ptr);
+    if (sp == 0) return 0;
+    h = (PRWord*)FindObject(sp, (PRWord*)ptr);
+    return GC_GET_USER_BITS(h[0]);
+}
+
+PR_IMPLEMENT(PRWord) PR_SetObjectHeader(void *ptr, PRWord newUserBits) {
+    GCSeg *sp;
+    PRWord *h, rv;
+
+    if (ptr == 0) return 0;
+    sp = InHeap(ptr);
+    if (sp == 0) return 0;
+    h = (PRWord*)FindObject(sp, (PRWord*)ptr);
+    rv = GC_GET_USER_BITS(h[0]);
+    h[0] = (h[0] & ~GC_USER_BITS) |
+    ((newUserBits << GC_USER_BITS_SHIFT) & GC_USER_BITS);
+    return rv;
+}
+
+PR_IMPLEMENT(void) PR_InitGC(
+    PRWord flags, PRInt32 initialHeapSize, PRInt32 segSize, PRThreadScope scope)
+{
+    static char firstTime = 1;
+
+    if (!firstTime) return;
+    firstTime = 0;
+
+    _pr_msgc_lm = PR_NewLogModule("msgc");
+    _pr_pageShift = PR_GetPageShift();
+    _pr_pageSize = PR_GetPageSize();
+
+#if defined(WIN16)
+    PR_ASSERT( initialHeapSize < MAX_ALLOC_SIZE );
+#endif
+
+  /* Setup initial heap size and initial segment size */
+  if (0 != segSize) segmentSize = segSize;
+#ifdef DEBUG
+    GC = PR_NewLogModule("GC");
+    {
+    char *ev = PR_GetEnv("GC_SEGMENT_SIZE");
+    if (ev && ev[0]) {
+      PRInt32 newSegmentSize = atoi(ev);
+      if (0 != newSegmentSize) segmentSize = newSegmentSize;
+    }
+    ev = PR_GetEnv("GC_INITIAL_HEAP_SIZE");
+    if (ev && ev[0]) {
+      PRInt32 newInitialHeapSize = atoi(ev);
+      if (0 != newInitialHeapSize) initialHeapSize = newInitialHeapSize;
+    }
+    ev = PR_GetEnv("GC_FLAGS");
+    if (ev && ev[0]) {
+        flags |= atoi(ev);
+    }
+#ifdef GCMETER
+        ev = PR_GetEnv("GC_METER");
+        if (ev && ev[0]) {
+            _pr_gcMeter = atoi(ev);
+        }
+#endif
+    }
+#endif
+  if (0 == initialHeapSize) initialHeapSize = segmentSize;
+  if (initialHeapSize < segmentSize) initialHeapSize = segmentSize;
+
+  _pr_gcData.maxMemory   = MAX_SEGS * segmentSize;
+  _pr_gcData.liveBlock  = ProcessRootBlock;
+  _pr_gcData.livePointer = ProcessRootPointer;
+  _pr_gcData.processRootBlock  = ProcessRootBlock;
+  _pr_gcData.processRootPointer = ProcessRootPointer;
+  _pr_gcData.dumpOutput = NULL;
+
+  PR_INIT_CLIST(&_pr_finalizeableObjects);
+    PR_INIT_CLIST(&_pr_finalQueue);
+    _PR_InitGC(flags);
+
+    /* Create finalizer thread */
+    _PR_CreateFinalizer(scope);
+
+  /* Allocate the initial segment for the heap */
+  minBin = 31;
+  maxBin = 0;
+  GrowHeap(initialHeapSize);
+    PR_RegisterRootFinder(ScanWeakFreeList, "scan weak free list", 0);
+}
+
+#if defined(WIN16)
+/*
+** For WIN16 the GC_IN_HEAP() macro must call the private InHeap function.
+** This public wrapper function makes this possible...
+*/
+PR_IMPLEMENT(PRBool)
+PR_GC_In_Heap(void *object)
+{
+    return InHeap( object ) != NULL;    
+}
+#endif
+
+
+/** Added by Vishy for sanity checking a few GC structures **/
+/** Can use SanityCheckGC to debug corrupted GC Heap situations **/
+
+#ifdef DEBUG
+
+static int SegmentOverlaps(int i, int j)
+{
+  return
+    (((segs[i].limit > segs[j].base) && (segs[i].base < segs[j].base)) ||
+     ((segs[j].limit > segs[i].base) && (segs[j].base < segs[i].base)));
+}
+
+static void NoSegmentOverlaps(void)
+{
+  int i,j;
+
+  for (i = 0; i < nsegs; i++)
+    for (j = i+1 ; j < nsegs ; j++)
+      PR_ASSERT(!SegmentOverlaps(i,j));
+}
+
+static void SegInfoCheck(void)
+{
+  int i;
+  for (i = 0 ; i < nsegs ; i++)
+    PR_ASSERT((segs[i].info->hbits) &&
+	      (segs[i].info->hbits == segs[i].hbits) &&
+	      (segs[i].info->base == segs[i].base) &&
+	      (segs[i].info->limit == segs[i].limit));
+}
+
+static void SanityCheckGC()
+{
+  NoSegmentOverlaps();
+  SegInfoCheck();
+}
+
+#endif
+
+#if defined(DEBUG) && defined(WIN32)
+
+extern void *baseaddr;
+extern void *lastaddr;
+
+PR_IMPLEMENT(void)
+PR_PrintGCStats(void)
+{
+    long reportedSegSpace = _pr_gcData.busyMemory + _pr_gcData.freeMemory;
+    char* msg;
+    long largeCount = 0, largeSize = 0;
+    long segCount = 0, segSize = 0;
+    long freeCount = 0, freeSize = 0;
+    GCSeg *sp, *esp;
+    GCSegInfo* si;
+
+    LOCK_GC();
+
+    sp = segs;
+    esp = sp + nsegs;
+    while (sp < esp) {
+    long size = sp->info->limit - sp->info->base;
+    segCount++;
+    segSize += size;
+        if (sp->info->fromMalloc) {
+        largeCount++;
+        largeSize += size;
+    }
+        sp++;
+    }
+
+    si = freeSegs;
+    while (si != NULL) {
+    long size = si->limit - si->base;
+    freeCount++;
+    freeSize += size;
+    si = si->next;
+    }
+    
+    msg = PR_smprintf("\
+# GC Stats:\n\
+#   vm space:\n\
+#     range:      %ld - %ld\n\
+#     size:       %ld\n\
+#   segments:\n\
+#     range:      %ld - %ld\n\
+#     count:      %ld (reported: %ld)\n\
+#     size:       %ld (reported: %ld)\n\
+#     free count: %ld\n\
+#     free size:  %ld\n\
+#     busy objs:  %ld (%ld%%)\n\
+#     free objs:  %ld (%ld%%)\n\
+#   large blocks:\n\
+#     count:      %ld\n\
+#     total size: %ld (%ld%%)\n\
+#     avg size:   %ld\n\
+",
+              /* vm space */
+              (long)baseaddr, (long)lastaddr,
+              (long)lastaddr - (long)baseaddr,
+              /* segments */
+              _pr_gcData.lowSeg, _pr_gcData.highSeg,
+              segCount, nsegs,
+              segSize, reportedSegSpace,
+              freeCount,
+              freeSize,
+              _pr_gcData.busyMemory,
+              (_pr_gcData.busyMemory * 100 / reportedSegSpace),
+              _pr_gcData.freeMemory,
+              (_pr_gcData.freeMemory * 100 / reportedSegSpace),
+              /* large blocks */
+              largeCount,
+              largeSize, (largeSize * 100 / reportedSegSpace),
+              (largeCount ? largeSize / largeCount : 0)
+              );
+    UNLOCK_GC();
+    fprintf(stderr, msg);
+    OutputDebugString(msg);
+    PR_smprintf_free(msg);
+#ifdef GC_STATS
+    PR_PrintGCAllocStats();
+#endif
+}
+#endif
+
+PR_IMPLEMENT(void)
+PR_DumpToFile(char* filename, char* msg, PRFileDumper dump, PRBool detailed)
+{
+    FILE *out;
+    OutputDebugString(msg);
+    out = fopen(filename, "a");
+    if (!out) {
+	char buf[64];
+	PR_ASSERT(strlen(filename) < sizeof(buf) - 16);
+	PR_snprintf(buf, sizeof(buf), "Can't open \"%s\"\n",
+		    filename);
+	OutputDebugString(buf);
+    }
+    else
+    {
+	struct tm *newtime;
+	time_t aclock;
+	int i;
+
+	time(&aclock);
+	newtime = localtime(&aclock);
+	fprintf(out, "%s on %s\n", msg, asctime(newtime));  /* Print current time */
+	dump(out, detailed);
+	fprintf(out, "\n\n");
+	for (i = 0; i < 80; i++)
+	    fprintf(out, "=");
+	fprintf(out, "\n\n");
+	fclose(out);
+    }
+    OutputDebugString(" done\n");
+}
+
new file mode 100644
--- /dev/null
+++ b/lib/msgc/src/unixgc.c
@@ -0,0 +1,136 @@
+/* -*- 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.
+ */
+
+#include "prlock.h"
+#include "prlog.h"
+#include "prmem.h"
+#include "gcint.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#define _PR_GC_VMBASE 0x40000000
+
+#if defined(SOLARIS)
+#define _MD_MMAP_FLAGS MAP_SHARED
+#elif defined(OSF1) || defined(RELIANTUNIX)
+#define _MD_MMAP_FLAGS MAP_PRIVATE|MAP_FIXED
+#else
+#define _MD_MMAP_FLAGS MAP_PRIVATE
+#endif
+
+static PRInt32 zero_fd = -1;
+static PRLock *zero_fd_lock = NULL;
+
+void _MD_InitGC(void)
+{
+#ifdef DEBUG
+    /*
+     * Disable using mmap(2) if NSPR_NO_MMAP is set
+     */
+    if (getenv("NSPR_NO_MMAP")) {
+        zero_fd = -2;
+        return;
+    }
+#endif
+    zero_fd = open("/dev/zero",O_RDWR , 0);
+    zero_fd_lock = PR_NewLock();
+}
+
+/* This static variable is used by _MD_GrowGCHeap and _MD_ExtendGCHeap */
+static void *lastaddr = (void*) _PR_GC_VMBASE;
+
+void *_MD_GrowGCHeap(PRUint32 *sizep)
+{
+	void *addr;
+	PRUint32 size;
+
+	size = *sizep;
+
+	PR_Lock(zero_fd_lock);
+	if (zero_fd < 0) {
+		goto mmap_loses;
+	}
+
+	/* Extend the mapping */
+	addr = mmap(lastaddr, size, PROT_READ|PROT_WRITE|PROT_EXEC,
+	    _MD_MMAP_FLAGS,
+	    zero_fd, 0);
+	if (addr == (void*)-1) {
+		zero_fd = -1;
+		goto mmap_loses;
+	}
+	lastaddr = ((char*)addr + size);
+#ifdef DEBUG
+	PR_LOG(_pr_msgc_lm, PR_LOG_WARNING,
+	    ("GC: heap extends from %08x to %08x\n",
+	    _PR_GC_VMBASE,
+	    _PR_GC_VMBASE + (char*)lastaddr - (char*)_PR_GC_VMBASE));
+#endif
+	PR_Unlock(zero_fd_lock);
+	return addr;
+
+mmap_loses:
+	PR_Unlock(zero_fd_lock);
+	return PR_MALLOC(size);
+}
+
+/* XXX - This is disabled.  MAP_FIXED just does not work. */
+#if 0
+PRBool _MD_ExtendGCHeap(char *base, PRInt32 oldSize, PRInt32 newSize) {
+	PRBool rv = PR_FALSE;
+	void* addr;
+	PRInt32 allocSize = newSize - oldSize;
+
+	PR_Lock(zero_fd_lock);
+	addr = mmap(base + oldSize, allocSize, PROT_READ|PROT_WRITE|PROT_EXEC,
+	    _MD_MMAP_FLAGS | MAP_FIXED, zero_fd, 0);
+	if (addr == (void*)-1) {
+		goto loser;
+	}
+	if (addr != (void*) (base + oldSize)) {
+		munmap(base + oldSize, allocSize);
+		goto loser;
+	}
+	lastaddr = ((char*)base + newSize);
+	PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS,
+	    ("GC: heap now extends from %p to %p",
+	    base, base + newSize));
+	rv = PR_TRUE;
+
+loser:
+	PR_Unlock(zero_fd_lock);
+	return rv;
+}
+#else
+PRBool _MD_ExtendGCHeap(char *base, PRInt32 oldSize, PRInt32 newSize) {
+	return PR_FALSE;
+}
+#endif
+
+void _MD_FreeGCSegment(void *base, PRInt32 len)
+{
+	if (zero_fd < 0) {
+		PR_DELETE(base);
+	} else {
+		(void) munmap(base, len);
+	}
+}
new file mode 100644
--- /dev/null
+++ b/lib/msgc/src/win16gc.c
@@ -0,0 +1,57 @@
+/* -*- 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.
+ */
+#if defined(WIN16)
+#include <windows.h>
+#endif
+#include "prtypes.h"
+#include <stdlib.h>
+
+#define MAX_SEGMENT_SIZE (65536l - 4096l)
+
+/************************************************************************/
+/*
+** Machine dependent GC Heap management routines:
+**    _MD_GrowGCHeap
+*/
+/************************************************************************/
+
+void _MD_InitGC(void) {}
+
+extern void *
+_MD_GrowGCHeap(PRUint32 *sizep)
+{
+    void *addr;
+
+    if( *sizep > MAX_SEGMENT_SIZE ) {
+        *sizep = MAX_SEGMENT_SIZE;
+    }
+
+    addr = malloc((size_t)*sizep);
+    return addr;
+}
+
+HINSTANCE _pr_hInstance;
+
+int CALLBACK LibMain( HINSTANCE hInst, WORD wDataSeg, 
+                      WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+    _pr_hInstance = hInst;
+    return TRUE;
+}
+
+
new file mode 100644
--- /dev/null
+++ b/lib/msgc/src/win32gc.c
@@ -0,0 +1,110 @@
+/* -*- 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.
+ */
+
+/*
+ * GC related routines
+ *
+ */
+#include <windows.h>
+#include "prlog.h"
+
+extern PRLogModuleInfo* _pr_msgc_lm;
+
+#define GC_VMBASE               0x40000000
+#define GC_VMLIMIT              0x00FFFFFF
+
+/************************************************************************/
+/*
+** Machine dependent GC Heap management routines:
+**    _MD_GrowGCHeap
+*/
+/************************************************************************/
+
+void *baseaddr = (void*) GC_VMBASE;
+void *lastaddr = (void*) GC_VMBASE;
+
+void _MD_InitGC() {}
+
+void *_MD_GrowGCHeap(PRUint32 *sizep)
+{
+    void *addr;
+    size_t size;
+
+    /* Reserve a block of memory for the GC */
+    if( lastaddr == baseaddr ) {
+        addr = VirtualAlloc( (void *)GC_VMBASE, GC_VMLIMIT, MEM_RESERVE, PAGE_READWRITE );
+
+        /* 
+        ** If the GC_VMBASE address is already mapped, then let the OS choose a 
+        ** base address that is available...
+        */
+        if (addr == NULL) {
+            addr = VirtualAlloc( NULL, GC_VMLIMIT, MEM_RESERVE, PAGE_READWRITE );
+
+            baseaddr = lastaddr = addr;
+            if (addr == NULL) {
+                PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, ("GC: unable to allocate heap: LastError=%ld",
+                       GetLastError()));
+                return 0;
+            }
+        }
+    }
+    size = *sizep;
+
+    /* Extend the mapping */
+    addr = VirtualAlloc( lastaddr, size, MEM_COMMIT, PAGE_READWRITE );
+    if (addr == NULL) {
+        return 0;
+    }
+
+    lastaddr = ((char*)addr + size);
+    PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS,
+	   ("GC: heap extends from %08x to %08x",
+	    baseaddr, (long)baseaddr + (char*)lastaddr - (char*)baseaddr));
+
+    return addr;
+}
+
+PRBool _MD_ExtendGCHeap(char *base, PRInt32 oldSize, PRInt32 newSize) {
+  void* addr;
+
+  addr = VirtualAlloc( base + oldSize, newSize - oldSize,
+		       MEM_COMMIT, PAGE_READWRITE );
+  if (NULL == addr) {
+    PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, ("GC: unable to extend heap: LastError=%ld",
+		     GetLastError()));
+    return PR_FALSE;
+  }
+  if (base + oldSize != (char*)addr) {
+    PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, ("GC: segment extension returned %x instead of %x",
+		     addr, base + oldSize));
+    VirtualFree(addr, newSize - oldSize, MEM_DECOMMIT);
+    return PR_FALSE;
+  }
+  lastaddr = base + newSize;
+  PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS,
+	 ("GC: heap now extends from %p to %p",
+	  base, base + newSize));
+  return PR_TRUE;
+}
+
+
+void _MD_FreeGCSegment(void *base, PRInt32 len)
+{
+     (void)VirtualFree(base, 0, MEM_RELEASE);
+}
new file mode 100644
--- /dev/null
+++ b/lib/msgc/tests/Makefile
@@ -0,0 +1,283 @@
+#
+# 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.
+#
+
+#! gmake
+
+MOD_DEPTH = ../../..
+
+include $(MOD_DEPTH)/config/config.mk
+
+ifeq ($(OS_TARGET), WIN16)
+OS_CFLAGS = $(OS_EXE_CFLAGS)
+W16STDIO = $(MOD_DEPTH)/pr/src/md/windows/$(OBJDIR)/w16stdio.$(OBJ_SUFFIX)
+endif
+
+ifeq ($(OS_TARGET), OS2)
+OS_CFLAGS = $(OS_EXE_CFLAGS)
+endif
+
+CSRCS = gc1.c thrashgc.c
+
+ifeq ($(OS_ARCH), WINNT)
+PROG_SUFFIX = .exe
+else
+PROG_SUFFIX =
+endif
+
+PROGS = $(addprefix $(OBJDIR)/, $(CSRCS:.c=$(PROG_SUFFIX)))
+
+TARGETS = $(PROGS) $(OBJS)
+
+INCLUDES = -I$(DIST)/include
+
+# Setting the variables LDOPTS and LIBPR.  We first initialize
+# them to the default values, then adjust them for some platforms.
+LDOPTS = -L$(DIST)/lib
+NSPR_VERSION = $(MOD_VERSION)
+GC_VERSION = $(MOD_VERSION)
+LIBPR = -lnspr$(NSPR_VERSION)
+LIBPLC = -lplc$(NSPR_VERSION)
+LIBGC = -lmsgc$(GC_VERSION)
+
+ifeq ($(OS_ARCH), WINNT)
+ifeq ($(OS_TARGET), WIN16)
+  LIBPR = $(DIST)/lib/nspr$(NSPR_VERSION).lib
+  LIBPLC = $(DIST)/lib/plc$(NSPR_VERSION).lib
+  LIBGC= $(DIST)/lib/msgc$(GC_VERSION).lib
+else
+ifeq ($(OS_TARGET),OS2)
+  LDOPTS = -NOE -DEBUG -nologo -PMTYPE:VIO
+  LIBPR = $(DIST)/lib/nspr$(NSPR_VERSION).lib
+  LIBPLC = $(DIST)/lib/plc$(NSPR_VERSION).lib
+  LIBGC= $(DIST)/lib/msgc$(GC_VERSION).lib
+else
+  LDOPTS = -NOLOGO -DEBUG -DEBUGTYPE:CV -INCREMENTAL:NO
+  LIBPR = $(DIST)/lib/libnspr$(NSPR_VERSION).$(LIB_SUFFIX)
+  LIBPLC = $(DIST)/lib/libplc$(NSPR_VERSION).$(LIB_SUFFIX)
+  LIBGC= $(DIST)/lib/libmsgc$(GC_VERSION).$(LIB_SUFFIX)
+endif
+endif
+endif
+
+ifneq ($(OS_ARCH), WINNT)
+PWD = $(shell pwd)
+endif
+
+ifeq ($(OS_ARCH), IRIX)
+LDOPTS += -rpath $(PWD)/$(DIST)/lib -rdata_shared
+
+ifeq ($(USE_N32),1)
+LDOPTS += -n32
+endif
+
+endif
+
+ifeq ($(OS_ARCH), OSF1)
+# I haven't figured out how to pass -rpath to cc on OSF1 V3.2, so
+# we do static linking.
+ifeq ($(OS_RELEASE), V3.2)
+  LIBPR = $(DIST)/lib/libnspr$(NSPR_VERSION).a
+  LIBPLC = $(DIST)/lib/libplc$(NSPR_VERSION).a
+  LIBGC = $(DIST)/lib/libmsgc$(GC_VERSION).a
+  EXTRA_LIBS = -lc_r
+else
+  LDOPTS += -rpath $(PWD)/$(DIST)/lib
+endif
+endif
+
+ifeq ($(OS_ARCH), HP-UX)
+LDOPTS += -Wl,+s,+b,$(PWD)/$(DIST)/lib
+endif
+
+# AIX
+ifeq ($(OS_ARCH),AIX)
+ifeq ($(CLASSIC_NSPR),1)
+LDOPTS += -blibpath:.:$(PWD)/$(DIST)/lib:/usr/lpp/xlC/lib:/usr/lib:/lib
+else
+LDOPTS += -blibpath:.:$(PWD)/$(DIST)/lib:/usr/lib/threads:/usr/lpp/xlC/lib:/usr/lib:/lib
+endif
+ifeq ($(OS_ARCH)$(OS_RELEASE),AIX4.1)
+LIBPR = -lnspr$(NSPR_VERSION)_shr
+LIBPLC = -lplc$(NSPR_VERSION)_shr
+LIBGC = -lmsgc$(GC_VERSION)_shr
+else
+LDOPTS += -brtl
+EXTRA_LIBS = -ldl
+endif
+endif
+
+# Solaris
+ifeq ($(OS_ARCH), SunOS)
+ifneq ($(OS_RELEASE), 4.1.3_U1)
+ifdef NS_USE_GCC
+LDOPTS += -Xlinker -R -Xlinker $(PWD)/$(DIST)/lib
+else
+LDOPTS += -R $(PWD)/$(DIST)/lib
+endif
+endif
+
+ifneq ($(LOCAL_THREADS_ONLY),1)
+# SunOS 5.4 and 5.5 need to link with -lthread or -lpthread,
+# even though we already linked with these system libraries
+# when we built libnspr.so.
+ifeq ($(OS_RELEASE), 5.4)
+EXTRA_LIBS = -lthread
+endif
+
+ifeq ($(OS_RELEASE), 5.5)
+ifdef USE_PTHREADS
+EXTRA_LIBS = -lpthread
+else
+EXTRA_LIBS = -lthread
+endif
+endif
+endif # LOCAL_THREADS_ONLY
+endif # SunOS
+
+ifeq ($(OS_ARCH),NEC)
+EXTRA_LIBS = $(OS_LIBS)
+# This hardcodes in the executable programs the directory to find
+# libnspr.so etc. at program startup.  Equivalent to the -R or -rpath
+# option for ld on other platforms.
+export LD_RUN_PATH = $(PWD)/$(DIST)/lib
+endif
+
+ifeq ($(OS_ARCH), NCR)
+# XXX: We see some strange problems when we link with libnspr.so.
+# So for now we use static libraries on NCR.  The shared library
+# stuff below is commented out.
+LIBPR = $(DIST)/lib/libnspr$(NSPR_VERSION).a
+LIBPLC = $(DIST)/lib/libplc$(NSPR_VERSION).a
+LIBGC = $(DIST)/lib/libmsgc$(GC_VERSION).a
+EXTRA_LIBS = -lsocket -lnsl -ldl
+
+# NCR needs to link against -lsocket -lnsl (and -lc, which is linked
+# implicitly by $(CC)) again even though we already linked with these
+# system libraries when we built libnspr.so.
+#EXTRA_LIBS = -lsocket -lnsl
+# This hardcodes in the executable programs the directory to find
+# libnspr.so etc. at program startup.  Equivalent to the -R or -rpath 
+# option for ld on other platforms.
+#export LD_RUN_PATH = $(PWD)/$(DIST)/lib
+endif
+
+ifeq ($(OS_ARCH), Linux)
+ifeq ($(OS_RELEASE), 1.2)
+EXTRA_LIBS = -ldl
+endif
+endif
+
+ifeq ($(OS_ARCH), SCOOS)
+# SCO Unix needs to link against -lsocket again even though we
+# already linked with these system libraries when we built libnspr.so.
+EXTRA_LIBS = -lsocket
+# This hardcodes in the executable programs the directory to find
+# libnspr.so etc. at program startup.  Equivalent to the -R or -rpath 
+# option for ld on other platforms.
+export LD_RUN_PATH = $(PWD)/$(DIST)/lib
+endif
+
+ifeq ($(OS_ARCH),SINIX)
+EXTRA_LIBS = -lsocket -lnsl -lresolv -ldl
+# This hardcodes in the executable programs the directory to find
+# libnspr.so etc. at program startup.  Equivalent to the -R or -rpath
+# option for ld on other platforms.
+export LD_RUN_PATH = $(PWD)/$(DIST)/lib
+endif
+
+ifeq ($(OS_ARCH), UNIXWARE)
+export LD_RUN_PATH = $(PWD)/$(DIST)/lib
+endif
+
+ifeq ($(OS_ARCH),BSD_OS)
+EXTRA_LIBS = -ldl
+endif
+
+#####################################################
+#
+# The rules
+#
+#####################################################
+
+include $(MOD_DEPTH)/config/rules.mk
+
+AIX_PRE_4_2 = 0
+ifeq ($(OS_ARCH),AIX)
+ifneq ($(OS_RELEASE),4.2)
+ifneq ($(USE_PTHREADS), 1)
+#AIX_PRE_4_2 = 1
+endif
+endif
+endif
+
+ifeq ($(AIX_PRE_4_2),1)
+
+# AIX releases prior to 4.2 need a special two-step linking hack
+# in order to both override the system select() and be able to 
+# get at the original system select().
+#
+# We use a pattern rule in ns/nspr20/config/rules.mk to generate
+# the .$(OBJ_SUFFIX) file from the .c source file, then do the
+# two-step linking hack below.
+
+$(OBJDIR)/%: $(OBJDIR)/%.$(OBJ_SUFFIX)
+	@$(MAKE_OBJDIR)
+	rm -f $@ $(AIX_TMP)
+	$(CC) $(AIX_LINK_OPTS) -o $(AIX_TMP) $< $(DIST)/lib/libnspr$(NSPR_VERSION).a
+	$(CC) -o $@ $(AIX_TMP) $(AIX_WRAP)
+	rm -f $(AIX_TMP)
+
+else
+
+# All platforms that are not AIX pre-4.2.
+
+$(OBJDIR)/%$(PROG_SUFFIX): $(OBJDIR)/%.$(OBJ_SUFFIX)
+	@$(MAKE_OBJDIR)
+ifeq ($(OS_ARCH), WINNT)
+ifeq ($(OS_TARGET),WIN16)
+	echo system windows >w16link
+	echo name $@  >>w16link
+	echo option map >>w16link
+#	echo option CASEEXACT >>w16link
+	echo option stack=16K >>w16link
+	echo debug $(DEBUGTYPE) all >>w16link
+	echo file >>w16link
+	echo $< ,  >>w16link
+	echo $(W16STDIO) >>w16link
+	echo library  >>w16link
+	echo $(LIBPR),	     >>w16link
+	echo $(LIBPLC),		>>w16link
+	echo $(LIBGC),		 >>w16link
+	echo winsock.lib     >>w16link
+	wlink @w16link.
+else
+ifeq ($(OS_TARGET),OS2)
+	$(LINK) $(LDOPTS) $< $(LIBGC) $(LIBPLC) $(LIBPR) so32dll.lib tcp32dll.lib -MAP:$(@:.exe=.map) -out:$@
+else
+	link $(LDOPTS) $< $(LIBGC) $(LIBPLC) $(LIBPR) wsock32.lib -out:$@
+endif
+endif
+else
+	$(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBGC) $(LIBPLC) $(LIBPR) $(EXTRA_LIBS) -o $@
+endif
+
+endif
+
+export:: $(TARGETS)
+export:: install
+clean::
+	rm -f $(TARGETS)
new file mode 100644
--- /dev/null
+++ b/lib/msgc/tests/gc1.c
@@ -0,0 +1,238 @@
+/* -*- 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.
+ */
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "prgc.h"
+#include "prinit.h"
+#include "prmon.h"
+#include "prinrval.h"
+#ifndef XP_MAC
+#include "private/pprthred.h"
+#else
+#include "pprthred.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef XP_MAC
+#include "prlog.h"
+#define printf PR_LogPrint
+extern void SetupMacPrintfLog(char *logFile);
+#endif
+
+static PRMonitor *mon;
+static PRInt32 threads, waiting, iterations;
+static PRInt32 scanCount, finalizeCount, freeCount;
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+
+typedef struct Array {
+    PRUintn size;
+    void *body[1];
+} Array;
+
+int arrayTypeIndex;
+
+static void PR_CALLBACK ScanArray(void *a)
+{
+/*	printf ("In ScanArray a = %X size = %d \n", a, a->size); */
+	scanCount++;
+}
+
+static void PR_CALLBACK FinalizeArray(void *a)
+{
+/*	printf ("In FinalizeArray a = %X size = %d \n", a, a->size); */	
+	finalizeCount++;
+}
+
+static void PR_CALLBACK FreeArray(void *a)
+{
+/*	printf ("In FreeArray\n");	*/
+	freeCount++;
+}
+
+static Array *NewArray(PRUintn size)
+{
+    Array *a;
+
+    a = (Array *)PR_AllocMemory(sizeof(Array) + size*sizeof(void*) - 1*sizeof(void*),
+                       arrayTypeIndex, PR_ALLOC_CLEAN);
+
+/*	printf ("In NewArray a = %X \n", a); */	
+
+    if (a)
+        a->size = size;
+    return a;
+}
+
+GCType arrayType = {
+    ScanArray,
+    FinalizeArray,
+    0,
+    0,
+    FreeArray,
+    0
+};
+
+static void Initialize(void)
+{
+    PR_InitGC(0, 0, 0, PR_GLOBAL_THREAD);
+    arrayTypeIndex = PR_RegisterType(&arrayType);
+}
+
+static void PR_CALLBACK AllocateLikeMad(void *arg)
+{
+    Array *prev;
+    PRInt32 i;
+	PRInt32 count;
+
+	count = (PRInt32)arg;
+    prev = 0;
+    for (i = 0; i < count; i++) {
+        Array *leak = NewArray(i & 511);
+        if ((i & 1023) == 0) {
+            prev = 0;                   /* forget */
+        } else {
+            if (i & 1) {
+                prev = leak;            /* remember */
+            }
+        }
+    }
+    PR_EnterMonitor(mon);
+    waiting++;
+    PR_Notify(mon);
+    PR_ExitMonitor(mon);
+}
+
+int main(int argc, char **argv)
+{
+    PRIntervalTime start, stop, usec;
+    double d;
+    PRIntn i, totalIterations;
+	/* 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 = PL_CreateOptState(argc, argv, "dt:c:");
+
+	threads = 10;
+	iterations = 100;
+
+	while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+    {
+        if (PL_OPT_BAD == os) {
+            fprintf(stderr, "Invalid command-line option\n");
+            exit(1);
+        }
+        switch (opt->option)
+        {
+        case 'd':  /* debug mode */
+			debug_mode = 1;
+            break;
+        case 't':  /* number of threads */
+            threads = atoi(opt->value);
+            break;
+        case 'c':  /* iteration count */
+            iterations = atoi(opt->value);
+            break;
+        default:
+            break;
+        }
+    }
+	PL_DestroyOptState(opt);
+
+    fprintf(stderr, "t is %ld, i is %ld\n", (long) threads, (long) iterations);
+	/* main test */
+
+    PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 5);
+    PR_STDIO_INIT();
+    Initialize();
+
+#ifdef XP_MAC
+	SetupMacPrintfLog("gc1.log");
+	debug_mode = 1;
+#endif
+
+    /* Spin all of the allocator threads and then wait for them to exit */
+    start = PR_IntervalNow();
+    mon = PR_NewMonitor();
+    PR_EnterMonitor(mon);
+    waiting = 0;
+    for (i = 0; i < threads; i++) {
+        (void) PR_CreateThreadGCAble(PR_USER_THREAD,
+                               AllocateLikeMad, (void*)iterations,
+						      PR_PRIORITY_NORMAL,
+						      PR_LOCAL_THREAD,
+		    				  PR_UNJOINABLE_THREAD,
+						      0);
+    }
+    while (waiting != threads) {
+        PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
+    }
+    PR_ExitMonitor(mon);
+
+	PR_GC();
+	PR_ForceFinalize();	
+
+	totalIterations = iterations * threads;
+/*
+	if (scanCount != totalIterations)
+		printf ("scanCount discrepancy scanCount = %d totalIterations = %d \n", 
+			scanCount, totalIterations);
+	if (freeCount != totalIterations)
+		printf ("freeCount discrepancy freeCount = %d totalIterations = %d \n", 
+			freeCount, totalIterations);
+	if ((finalizeCount != totalIterations) && (finalizeCount != (totalIterations-1)))
+		printf ("finalizeCount discrepancy finalizeCount = %d totalIterations = %d \n", 
+			finalizeCount,totalIterations);
+*/
+
+    stop = PR_IntervalNow();
+    
+    usec = stop = stop - start;
+    d = (double)usec;
+
+    if (debug_mode) printf("%40s: %6.2f usec\n", "GC allocation", d / (iterations * threads));
+	else {
+		if (d == 0.0) failed_already = PR_TRUE;
+
+	}
+
+    PR_Cleanup();
+	if(failed_already)	
+	{
+	    printf("FAIL\n");
+		return 1;
+	}
+	else
+	{
+	    printf("PASS\n");
+		return 0;
+	}
+}
new file mode 100644
--- /dev/null
+++ b/lib/msgc/tests/thrashgc.c
@@ -0,0 +1,255 @@
+/* -*- 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.
+ */
+
+/***********************************************************************
+** Name: thrashgc
+**
+** Description: test garbace collection functions.
+**
+** Modification History:
+** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+**	         The debug mode will print all of the printfs associated with this test.
+**			 The regress mode will be the default mode. Since the regress tool limits
+**           the output to a one line status:PASS or FAIL,all of the printf statements
+**			 have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+**			recognize the return code from tha main program.
+***********************************************************************/
+/***********************************************************************
+** Includes
+***********************************************************************/
+#include "prthread.h"
+#include "prgc.h"
+#include "prprf.h"
+#include "prinrval.h"
+#include "prlock.h"
+#include "prinit.h"
+#include "prcvar.h"
+
+#ifndef XP_MAC
+#include "private/pprthred.h"
+#else
+#include "pprthred.h"
+#endif
+
+#include <stdio.h>
+#include <memory.h>
+#include <string.h>
+
+
+#ifdef XP_MAC
+#include "prlog.h"
+#define printf PR_LogPrint
+extern void SetupMacPrintfLog(char *logFile);
+#endif
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+static char* progname;
+static PRInt32 loops = 1000;
+static int tix1, tix2, tix3;
+static GCInfo* gcInfo;
+static PRLock* stderrLock;
+
+typedef struct Type1 Type1;
+typedef struct Type2 Type2;
+
+struct Type1 {
+  Type2* atwo;
+  Type1* next;
+};
+
+struct Type2 {
+  void* buf;
+};
+
+static void PR_CALLBACK ScanType1(void *obj) {
+  gcInfo->livePointer(((Type1 *)obj)->atwo);
+  gcInfo->livePointer(((Type1 *)obj)->next);
+}
+
+static void PR_CALLBACK ScanType2(void *obj) {
+  gcInfo->livePointer(((Type2 *)obj)->buf);
+}
+
+static GCType type1 = {
+    ScanType1
+};
+
+static GCType type2 = {
+    ScanType2
+/*  (void (*)(void*)) ScanType2 */
+};
+
+static GCType type3 = {
+  0
+};
+
+Type1* NewType1(void) {
+    Type1* p = (Type1*) PR_AllocMemory(sizeof(Type1), tix1, PR_ALLOC_DOUBLE);
+    PR_ASSERT(p != NULL);
+    return p;
+}
+
+Type2* NewType2(void) {
+    Type2* p = (Type2*) PR_AllocMemory(sizeof(Type2), tix2, PR_ALLOC_DOUBLE);
+    PR_ASSERT(p != NULL);
+    return p;
+}
+
+void* NewBuffer(PRInt32 size) {
+    void* p = PR_AllocMemory(size, tix3, PR_ALLOC_DOUBLE);
+    PR_ASSERT(p != NULL);
+    return p;
+}
+
+/* Allocate alot of garbage */
+static void PR_CALLBACK AllocStuff(void *unused) {
+  PRInt32 i;
+  void* danglingRefs[50];
+  PRIntervalTime start, end;
+  char msg[100];
+
+  start = PR_IntervalNow();
+  for (i = 0; i < loops; i++) {
+    void* p;
+    if (i & 1) {
+      Type1* t1 = NewType1();
+      t1->atwo = NewType2();
+      t1->next = NewType1();
+      t1->atwo->buf = NewBuffer(100);
+      p = t1;
+    } else {
+      Type2* t2 = NewType2();
+      t2->buf = NewBuffer(i & 16383);
+      p = t2;
+    }
+    if ((i % 10) == 0) {
+      memmove(&danglingRefs[0], &danglingRefs[1], 49*sizeof(void*));
+      danglingRefs[49] = p;
+    }
+  }
+  end = PR_IntervalNow();
+  if (debug_mode) PR_snprintf(msg, sizeof(msg), "Thread %p: %ld allocations took %ld ms",
+	      PR_GetCurrentThread(), loops,
+	      PR_IntervalToMilliseconds((PRIntervalTime) (end - start)));
+  PR_Lock(stderrLock);
+#ifndef XP_MAC
+  fprintf(stderr, "%s\n", msg);
+#else
+  if (debug_mode) printf("%s\n", msg);
+#endif
+  PR_Unlock(stderrLock);
+  }
+
+static void usage(char *progname) {
+#ifndef XP_MAC
+  fprintf(stderr, "Usage: %s [-t threads] [-l loops]\n", progname);
+#else
+  printf("Usage: %s [-t threads] [-l loops]\n", progname);
+#endif
+  exit(-1);
+}
+
+static int realMain(int argc, char **argv, char *notused) {
+  int i;
+  int threads = 0;
+
+#ifndef XP_MAC
+  progname = strrchr(argv[0], '/');
+  if (progname == 0) progname = argv[0];
+  for (i = 1; i < argc; i++) {
+    if (strcmp(argv[i], "-t") == 0) {
+      if (i == argc - 1) {
+	usage(progname);
+      }
+      threads = atoi(argv[++i]);
+      if (threads < 0) threads = 0;
+      if (threads > 10000) threads = 10000;
+      continue;
+    }
+    if (strcmp(argv[i], "-l") == 0) {
+      if (i == argc - 1) {
+	usage(progname);
+      }
+      loops = atoi(argv[++i]);
+      continue;
+    }
+    usage(progname);
+  }
+#else
+	threads = 50;
+#endif
+
+  for (i = 0; i < threads; i++) {
+    PRThread* thread;
+
+    /* XXXXX */
+    thread = PR_CreateThreadGCAble(PR_USER_THREAD,  /* thread type */
+			     AllocStuff,  /* start function */
+			     NULL,  /* arg */
+			     PR_PRIORITY_NORMAL,  /* priority */
+			     PR_LOCAL_THREAD,  /* thread scope */
+			     PR_UNJOINABLE_THREAD,  /* thread state */
+			     0);   /* stack size */
+    if (thread == 0) {
+#ifndef XP_MAC
+      fprintf(stderr, "%s: no more threads (only %d were created)\n",
+	      progname, i);
+#else
+      printf("%s: no more threads (only %d were created)\n",
+	      progname, i);
+#endif
+      break;
+    }
+  }
+  AllocStuff(NULL);
+  return 0;
+}
+
+static int padMain(int argc, char **argv) {
+  char pad[512];
+  return realMain(argc, argv, pad);
+}
+
+int main(int argc, char **argv) {
+  int rv;
+
+  debug_mode = 1;
+  
+  PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+  PR_SetThreadGCAble();
+
+#ifdef XP_MAC
+  SetupMacPrintfLog("thrashgc.log");
+  debug_mode = 1;
+#endif
+
+  PR_InitGC(0, 0, 0, PR_GLOBAL_THREAD);
+  PR_STDIO_INIT();
+  stderrLock = PR_NewLock();
+  tix1 = PR_RegisterType(&type1);
+  tix2 = PR_RegisterType(&type2);
+  tix3 = PR_RegisterType(&type3);
+  gcInfo = PR_GetGCInfo();
+  rv = padMain(argc, argv);
+  printf("PASS\n");
+  PR_Cleanup();
+  return rv;
+}
new file mode 100644
--- /dev/null
+++ b/lib/prstreams/Makefile
@@ -0,0 +1,109 @@
+#
+# 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.
+#
+
+#! gmake
+
+MOD_DEPTH = ../..
+
+include $(MOD_DEPTH)/config/config.mk
+
+# Disable optimization of the nspr on SunOS4.1.3
+ifeq ($(OS_ARCH),SunOS)
+ifeq ($(OS_RELEASE),4.1.3_U1)
+OPTIMIZER =
+endif
+endif
+ifeq ($(OS_ARCH), IRIX)
+CFLAGS += -KPIC
+ifneq ($(OS_RELEASE),5.3)
+CFLAGS += -exceptions
+endif
+endif
+
+INCLUDES = -I$(DIST)/include -I../../../include
+
+HEADERS = *.h
+
+CXXSRCS =           \
+	prstrms.cpp    \
+	$(NULL)
+
+OBJS = $(addprefix $(OBJDIR)/,$(CXXSRCS:.cpp=.$(OBJ_SUFFIX)))
+
+ifeq ($(OS_ARCH), WINNT)
+ifeq (,$(filter-out WIN16 OS2,$(OS_TARGET)))
+EXTRA_LIBS = $(DIST)/lib/nspr$(MOD_VERSION).lib
+else
+DLLBASE=/BASE:0x30000000
+RES=$(OBJDIR)/prstrms.res
+RESNAME=$(MOD_DEPTH)/pr/src/nspr.rc
+OS_LIBS = user32.lib
+EXTRA_LIBS = $(DIST)/lib/libnspr$(MOD_VERSION).lib
+endif
+else
+ifeq ($(OS_ARCH), AIX)
+  ifeq ($(OS_RELEASE), 4.1)
+    ifeq ($(CLASSIC_NSPR),1)
+    OS_LIBS += -lC -lc
+    else
+    OS_LIBS += -lC_r -lc_r
+    endif
+  else
+    ifeq ($(CLASSIC_NSPR),1)
+    MKSHLIB = /usr/lpp/xlC/bin/makeC++SharedLib -p 0
+    else
+    MKSHLIB = /usr/lpp/xlC/bin/makeC++SharedLib_r -p 0
+    endif
+    OS_LIBS += -ldl
+  endif
+endif
+ifeq ($(OS_ARCH)$(OS_RELEASE), AIX4.1)
+EXTRA_LIBS = -L$(DIST)/lib -lnspr$(MOD_VERSION)_shr
+else
+EXTRA_LIBS = -L$(DIST)/lib -lnspr$(MOD_VERSION)
+endif
+endif
+
+# On NCR and SCOOS, we can't link with extra libraries when
+# we build a shared library.  If we do so, the linker doesn't
+# complain, but we would run into weird problems at run-time.
+# Therefore on these platforms, we link just the object files.
+ifeq ($(OS_ARCH),NCR)
+EXTRA_LIBS =
+endif
+ifeq ($(OS_ARCH),SCOOS)
+EXTRA_LIBS =
+endif
+
+ifeq ($(OS_ARCH), UNIXWARE)
+OS_LIBS += -lC
+endif
+
+LIBRARY_NAME    = prstrms
+LIBRARY_VERSION = $(MOD_VERSION)
+
+RELEASE_HEADERS = $(HEADERS)
+RELEASE_HEADERS_DEST = $(RELEASE_INCLUDE_DIR)
+RELEASE_LIBS    = $(TARGETS)
+
+include $(MOD_DEPTH)/config/rules.mk
+
+export:: $(TARGETS) $(HEADERS)
+	$(INSTALL) -m 444 $(HEADERS) $(DIST)/include
+	$(INSTALL) -m 444 $(TARGETS) $(DIST)/lib
+
+install:: export
new file mode 100644
--- /dev/null
+++ b/lib/prstreams/prstrms.cpp
@@ -0,0 +1,525 @@
+/* -*- 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.
+ */
+
+/*
+ * Robin J. Maxwell 11-22-96
+ */
+
+#include "prstrms.h"
+#include <string.h> // memmove
+
+//
+// Definition of macros _PRSTR_BP, _PRSTR_DELBUF, and _PRSTR_DELBUF_C.
+//
+// _PRSTR_BP is the protected member of class ios that is returned
+// by the public method rdbuf().
+//
+// _PRSTR_DELBUF is the method or data member of class ios, if available,
+// with which we can ensure that the ios destructor does not delete
+// the associated streambuf.  If such a method or data member does not
+// exist, define _PRSTR_DELBUF to be empty.
+//
+//