added.
authorRyan C. Gordon <icculus@icculus.org>
Mon, 02 Oct 2000 03:03:13 +0000
changeset 741 cf5ba2ca7837
parent 740 50e12e22a85c
child 742 0b88b5b5a27c
added.
libgc/cord/README
libgc/cord/SCOPTIONS.amiga
libgc/cord/SMakefile.amiga
libgc/cord/cord.h
libgc/cord/cordbscs.c
libgc/cord/cordprnt.c
libgc/cord/cordtest.c
libgc/cord/cordxtra.c
libgc/cord/de.c
libgc/cord/de_cmds.h
libgc/cord/de_win.ICO
libgc/cord/de_win.RC
libgc/cord/de_win.c
libgc/cord/de_win.h
libgc/cord/ec.h
libgc/cord/gc.h
libgc/cord/private/cord_pos.h
libgc/include/backptr.h
libgc/include/cord.h
libgc/include/ec.h
libgc/include/gc.h
libgc/include/gc_alloc.h
libgc/include/gc_copy_descr.h
libgc/include/gc_cpp.h
libgc/include/gc_gcj.h
libgc/include/gc_inl.h
libgc/include/gc_inline.h
libgc/include/gc_nursery.h
libgc/include/gc_typed.h
libgc/include/javaxfc.h
libgc/include/leak_detector.h
libgc/include/new_gc_alloc.h
libgc/include/private/cord_pos.h
libgc/include/private/gc_hdrs.h
libgc/include/private/gc_priv.h
libgc/include/private/gcconfig.h
libgc/include/weakpointer.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/cord/README	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,31 @@
+Copyright (c) 1993-1994 by Xerox Corporation.  All rights reserved.
+
+THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+
+Permission is hereby granted to use or copy this program
+for any purpose,  provided the above notices are retained on all copies.
+Permission to modify the code and to distribute modified code is granted,
+provided the above notices are retained, and a notice that the code was
+modified is included with the above copyright notice.
+
+Please send bug reports to Hans-J. Boehm (boehm@sgi.com).
+
+This is a string packages that uses a tree-based representation.
+See cord.h for a description of the functions provided.  Ec.h describes
+"extensible cords", which are essentially output streams that write
+to a cord.  These allow for efficient construction of cords without
+requiring a bound on the size of a cord.
+
+de.c is a very dumb text editor that illustrates the use of cords.
+It maintains a list of file versions.  Each version is simply a
+cord representing the file contents.  Nonetheless, standard
+editing operations are efficient, even on very large files.
+(Its 3 line "user manual" can be obtained by invoking it without
+arguments.  Note that ^R^N and ^R^P move the cursor by
+almost a screen.  It does not understand tabs, which will show
+up as highlighred "I"s.  Use the UNIX "expand" program first.)
+To build the editor, type "make cord/de" in the gc directory.
+
+This package assumes an ANSI C compiler such as gcc.  It will
+not compile with an old-style K&R compiler.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/cord/SCOPTIONS.amiga	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,14 @@
+MATH=STANDARD
+CPU=68030
+NOSTACKCHECK
+OPTIMIZE
+VERBOSE
+NOVERSION
+NOICONS
+OPTIMIZERTIME
+INCLUDEDIR=/
+DEFINE AMIGA
+LIBRARY=cord.lib
+LIBRARY=/gc.lib
+IGNORE=100
+IGNORE=161
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/cord/SMakefile.amiga	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,20 @@
+# Makefile for cord.lib
+# Michel Schinz 1994/07/20
+
+OBJS = cordbscs.o cordprnt.o cordxtra.o
+
+all: cord.lib cordtest
+
+cordbscs.o: cordbscs.c
+cordprnt.o: cordprnt.c
+cordxtra.o: cordxtra.c
+cordtest.o: cordtest.c
+
+cord.lib: $(OBJS)
+	oml cord.lib r $(OBJS)
+
+cordtest: cordtest.o cord.lib
+	sc cordtest.o link
+
+clean:
+	delete cord.lib cordtest \#?.o \#?.lnk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/cord/cord.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,327 @@
+/* 
+ * Copyright (c) 1993-1994 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ * Author: Hans-J. Boehm (boehm@parc.xerox.com)
+ */
+/* Boehm, October 5, 1995 4:20 pm PDT */
+ 
+/*
+ * Cords are immutable character strings.  A number of operations
+ * on long cords are much more efficient than their strings.h counterpart.
+ * In particular, concatenation takes constant time independent of the length
+ * of the arguments.  (Cords are represented as trees, with internal
+ * nodes representing concatenation and leaves consisting of either C
+ * strings or a functional description of the string.)
+ *
+ * The following are reasonable applications of cords.  They would perform
+ * unacceptably if C strings were used:
+ * - A compiler that produces assembly language output by repeatedly
+ *   concatenating instructions onto a cord representing the output file.
+ * - A text editor that converts the input file to a cord, and then
+ *   performs editing operations by producing a new cord representing
+ *   the file after echa character change (and keeping the old ones in an
+ *   edit history)
+ *
+ * For optimal performance, cords should be built by
+ * concatenating short sections.
+ * This interface is designed for maximum compatibility with C strings.
+ * ASCII NUL characters may be embedded in cords using CORD_from_fn.
+ * This is handled correctly, but CORD_to_char_star will produce a string
+ * with embedded NULs when given such a cord. 
+ *
+ * This interface is fairly big, largely for performance reasons.
+ * The most basic constants and functions:
+ *
+ * CORD - the type of a cord;
+ * CORD_EMPTY - empty cord;
+ * CORD_len(cord) - length of a cord;
+ * CORD_cat(cord1,cord2) - concatenation of two cords;
+ * CORD_substr(cord, start, len) - substring (or subcord);
+ * CORD_pos i;  CORD_FOR(i, cord) {  ... CORD_pos_fetch(i) ... } -
+ *    examine each character in a cord.  CORD_pos_fetch(i) is the char.
+ * CORD_fetch(int i) - Retrieve i'th character (slowly).
+ * CORD_cmp(cord1, cord2) - compare two cords.
+ * CORD_from_file(FILE * f) - turn a read-only file into a cord.
+ * CORD_to_char_star(cord) - convert to C string.
+ *   (Non-NULL C constant strings are cords.)
+ * CORD_printf (etc.) - cord version of printf. Use %r for cords.
+ */
+# ifndef CORD_H
+
+# define CORD_H
+# include <stddef.h>
+# include <stdio.h>
+/* Cords have type const char *.  This is cheating quite a bit, and not	*/
+/* 100% portable.  But it means that nonempty character string		*/
+/* constants may be used as cords directly, provided the string is	*/
+/* never modified in place.  The empty cord is represented by, and	*/
+/* can be written as, 0.						*/
+
+typedef const char * CORD;
+
+/* An empty cord is always represented as nil 	*/
+# define CORD_EMPTY 0
+
+/* Is a nonempty cord represented as a C string? */
+#define CORD_IS_STRING(s) (*(s) != '\0')
+
+/* Concatenate two cords.  If the arguments are C strings, they may 	*/
+/* not be subsequently altered.						*/
+CORD CORD_cat(CORD x, CORD y);
+
+/* Concatenate a cord and a C string with known length.  Except for the	*/
+/* empty string case, this is a special case of CORD_cat.  Since the	*/
+/* length is known, it can be faster.					*/
+/* The string y is shared with the resulting CORD.  Hence it should	*/
+/* not be altered by the caller.					*/
+CORD CORD_cat_char_star(CORD x, const char * y, size_t leny);
+
+/* Compute the length of a cord */
+size_t CORD_len(CORD x);
+
+/* Cords may be represented by functions defining the ith character */
+typedef char (* CORD_fn)(size_t i, void * client_data);
+
+/* Turn a functional description into a cord. 	*/
+CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len);
+
+/* Return the substring (subcord really) of x with length at most n,	*/
+/* starting at position i.  (The initial character has position 0.)	*/
+CORD CORD_substr(CORD x, size_t i, size_t n);
+
+/* Return the argument, but rebalanced to allow more efficient   	*/
+/* character retrieval, substring operations, and comparisons.		*/
+/* This is useful only for cords that were built using repeated 	*/
+/* concatenation.  Guarantees log time access to the result, unless	*/
+/* x was obtained through a large number of repeated substring ops	*/
+/* or the embedded functional descriptions take longer to evaluate.	*/
+/* May reallocate significant parts of the cord.  The argument is not	*/
+/* modified; only the result is balanced.				*/
+CORD CORD_balance(CORD x);
+
+/* The following traverse a cord by applying a function to each 	*/
+/* character.  This is occasionally appropriate, especially where	*/
+/* speed is crucial.  But, since C doesn't have nested functions,	*/
+/* clients of this sort of traversal are clumsy to write.  Consider	*/
+/* the functions that operate on cord positions instead.		*/
+
+/* Function to iteratively apply to individual characters in cord.	*/
+typedef int (* CORD_iter_fn)(char c, void * client_data);
+
+/* Function to apply to substrings of a cord.  Each substring is a 	*/
+/* a C character string, not a general cord.				*/
+typedef int (* CORD_batched_iter_fn)(const char * s, void * client_data);
+# define CORD_NO_FN ((CORD_batched_iter_fn)0)
+
+/* Apply f1 to each character in the cord, in ascending order,		*/
+/* starting at position i. If						*/
+/* f2 is not CORD_NO_FN, then multiple calls to f1 may be replaced by	*/
+/* a single call to f2.  The parameter f2 is provided only to allow	*/
+/* some optimization by the client.  This terminates when the right	*/
+/* end of this string is reached, or when f1 or f2 return != 0.  In the	*/
+/* latter case CORD_iter returns != 0.  Otherwise it returns 0.		*/
+/* The specified value of i must be < CORD_len(x).			*/
+int CORD_iter5(CORD x, size_t i, CORD_iter_fn f1,
+	       CORD_batched_iter_fn f2, void * client_data);
+
+/* A simpler version that starts at 0, and without f2:	*/
+int CORD_iter(CORD x, CORD_iter_fn f1, void * client_data);
+# define CORD_iter(x, f1, cd) CORD_iter5(x, 0, f1, CORD_NO_FN, cd)
+
+/* Similar to CORD_iter5, but end-to-beginning.	No provisions for	*/
+/* CORD_batched_iter_fn.						*/
+int CORD_riter4(CORD x, size_t i, CORD_iter_fn f1, void * client_data);
+
+/* A simpler version that starts at the end:	*/
+int CORD_riter(CORD x, CORD_iter_fn f1, void * client_data);
+
+/* Functions that operate on cord positions.  The easy way to traverse	*/
+/* cords.  A cord position is logically a pair consisting of a cord	*/
+/* and an index into that cord.  But it is much faster to retrieve a	*/
+/* charcter based on a position than on an index.  Unfortunately,	*/
+/* positions are big (order of a few 100 bytes), so allocate them with	*/
+/* caution.								*/
+/* Things in cord_pos.h should be treated as opaque, except as		*/
+/* described below.  Also note that					*/
+/* CORD_pos_fetch, CORD_next and CORD_prev have both macro and function	*/
+/* definitions.  The former may evaluate their argument more than once. */
+# include "private/cord_pos.h"
+
+/*
+	Visible definitions from above:
+	
+	typedef <OPAQUE but fairly big> CORD_pos[1];
+	
+	* Extract the cord from a position:
+	CORD CORD_pos_to_cord(CORD_pos p);
+	
+	* Extract the current index from a position:
+	size_t CORD_pos_to_index(CORD_pos p);
+	
+	* Fetch the character located at the given position:
+	char CORD_pos_fetch(CORD_pos p);
+	
+	* Initialize the position to refer to the given cord and index.
+	* Note that this is the most expensive function on positions:
+	void CORD_set_pos(CORD_pos p, CORD x, size_t i);
+	
+	* Advance the position to the next character.
+	* P must be initialized and valid.
+	* Invalidates p if past end:
+	void CORD_next(CORD_pos p);
+	
+	* Move the position to the preceding character.
+	* P must be initialized and valid.
+	* Invalidates p if past beginning:
+	void CORD_prev(CORD_pos p);
+	
+	* Is the position valid, i.e. inside the cord?
+	int CORD_pos_valid(CORD_pos p);
+*/
+# define CORD_FOR(pos, cord) \
+    for (CORD_set_pos(pos, cord, 0); CORD_pos_valid(pos); CORD_next(pos))
+
+			
+/* An out of memory handler to call.  May be supplied by client.	*/
+/* Must not return.							*/
+extern void (* CORD_oom_fn)(void);
+
+/* Dump the representation of x to stdout in an implementation defined	*/
+/* manner.  Intended for debugging only.				*/
+void CORD_dump(CORD x);
+
+/* The following could easily be implemented by the client.  They are	*/
+/* provided in cordxtra.c for convenience.				*/
+
+/* Concatenate a character to the end of a cord.	*/
+CORD CORD_cat_char(CORD x, char c);
+
+/* Concatenate n cords.	*/
+CORD CORD_catn(int n, /* CORD */ ...);
+
+/* Return the character in CORD_substr(x, i, 1)  	*/
+char CORD_fetch(CORD x, size_t i);
+
+/* Return < 0, 0, or > 0, depending on whether x < y, x = y, x > y	*/
+int CORD_cmp(CORD x, CORD y);
+
+/* A generalization that takes both starting positions for the 		*/
+/* comparison, and a limit on the number of characters to be compared.	*/
+int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start, size_t len);
+
+/* Find the first occurrence of s in x at position start or later.	*/
+/* Return the position of the first character of s in x, or		*/
+/* CORD_NOT_FOUND if there is none.					*/
+size_t CORD_str(CORD x, size_t start, CORD s);
+
+/* Return a cord consisting of i copies of (possibly NUL) c.  Dangerous	*/
+/* in conjunction with CORD_to_char_star.				*/
+/* The resulting representation takes constant space, independent of i.	*/
+CORD CORD_chars(char c, size_t i);
+# define CORD_nul(i) CORD_chars('\0', (i))
+
+/* Turn a file into cord.  The file must be seekable.  Its contents	*/
+/* must remain constant.  The file may be accessed as an immediate	*/
+/* result of this call and/or as a result of subsequent accesses to 	*/
+/* the cord.  Short files are likely to be immediately read, but	*/
+/* long files are likely to be read on demand, possibly relying on 	*/
+/* stdio for buffering.							*/
+/* We must have exclusive access to the descriptor f, i.e. we may	*/
+/* read it at any time, and expect the file pointer to be		*/
+/* where we left it.  Normally this should be invoked as		*/
+/* CORD_from_file(fopen(...))						*/
+/* CORD_from_file arranges to close the file descriptor when it is no	*/
+/* longer needed (e.g. when the result becomes inaccessible).		*/ 
+/* The file f must be such that ftell reflects the actual character	*/
+/* position in the file, i.e. the number of characters that can be 	*/
+/* or were read with fread.  On UNIX systems this is always true.  On	*/
+/* MS Windows systems, f must be opened in binary mode.			*/
+CORD CORD_from_file(FILE * f);
+
+/* Equivalent to the above, except that the entire file will be read	*/
+/* and the file pointer will be closed immediately.			*/
+/* The binary mode restriction from above does not apply.		*/
+CORD CORD_from_file_eager(FILE * f);
+
+/* Equivalent to the above, except that the file will be read on demand.*/
+/* The binary mode restriction applies.					*/
+CORD CORD_from_file_lazy(FILE * f);
+
+/* Turn a cord into a C string.	The result shares no structure with	*/
+/* x, and is thus modifiable.						*/
+char * CORD_to_char_star(CORD x);
+
+/* Turn a C string into a CORD.  The C string is copied, and so may	*/
+/* subsequently be modified.						*/
+CORD CORD_from_char_star(const char *s);
+
+/* Identical to the above, but the result may share structure with	*/
+/* the argument and is thus not modifiable.				*/
+const char * CORD_to_const_char_star(CORD x); 
+
+/* Write a cord to a file, starting at the current position.  No	*/
+/* trailing NULs are newlines are added.				*/
+/* Returns EOF if a write error occurs, 1 otherwise.			*/
+int CORD_put(CORD x, FILE * f);
+
+/* "Not found" result for the following two functions.			*/
+# define CORD_NOT_FOUND ((size_t)(-1))
+
+/* A vague analog of strchr.  Returns the position (an integer, not	*/
+/* a pointer) of the first occurrence of (char) c inside x at position 	*/
+/* i or later. The value i must be < CORD_len(x).			*/
+size_t CORD_chr(CORD x, size_t i, int c);
+
+/* A vague analog of strrchr.  Returns index of the last occurrence	*/
+/* of (char) c inside x at position i or earlier. The value i		*/
+/* must be < CORD_len(x).						*/
+size_t CORD_rchr(CORD x, size_t i, int c);
+
+
+/* The following are also not primitive, but are implemented in 	*/
+/* cordprnt.c.  They provide functionality similar to the ANSI C	*/
+/* functions with corresponding names, but with the following		*/
+/* additions and changes:						*/
+/* 1. A %r conversion specification specifies a CORD argument.  Field	*/
+/*    width, precision, etc. have the same semantics as for %s.		*/
+/*    (Note that %c,%C, and %S were already taken.)			*/
+/* 2. The format string is represented as a CORD.		        */
+/* 3. CORD_sprintf and CORD_vsprintf assign the result through the 1st	*/ 	/*    argument.	Unlike their ANSI C versions, there is no need to guess	*/
+/*    the correct buffer size.						*/
+/* 4. Most of the conversions are implement through the native 		*/
+/*    vsprintf.  Hence they are usually no faster, and 			*/
+/*    idiosyncracies of the native printf are preserved.  However,	*/
+/*    CORD arguments to CORD_sprintf and CORD_vsprintf are NOT copied;	*/
+/*    the result shares the original structure.  This may make them	*/
+/*    very efficient in some unusual applications.			*/
+/*    The format string is copied.					*/
+/* All functions return the number of characters generated or -1 on	*/
+/* error.  This complies with the ANSI standard, but is inconsistent	*/
+/* with some older implementations of sprintf.				*/
+
+/* The implementation of these is probably less portable than the rest	*/
+/* of this package.							*/
+
+#ifndef CORD_NO_IO
+
+#include <stdarg.h>
+
+int CORD_sprintf(CORD * out, CORD format, ...);
+int CORD_vsprintf(CORD * out, CORD format, va_list args);
+int CORD_fprintf(FILE * f, CORD format, ...);
+int CORD_vfprintf(FILE * f, CORD format, va_list args);
+int CORD_printf(CORD format, ...);
+int CORD_vprintf(CORD format, va_list args);
+
+#endif /* CORD_NO_IO */
+
+# endif /* CORD_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/cord/cordbscs.c	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,915 @@
+/*
+ * Copyright (c) 1993-1994 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ * Author: Hans-J. Boehm (boehm@parc.xerox.com)
+ */
+/* Boehm, October 3, 1994 5:19 pm PDT */
+# include "gc.h"
+# include "cord.h"
+# include <stdlib.h>
+# include <stdio.h>
+# include <string.h>
+
+/* An implementation of the cord primitives.  These are the only 	*/
+/* Functions that understand the representation.  We perform only	*/
+/* minimal checks on arguments to these functions.  Out of bounds	*/
+/* arguments to the iteration functions may result in client functions	*/
+/* invoked on garbage data.  In most cases, client functions should be	*/
+/* programmed defensively enough that this does not result in memory	*/
+/* smashes.								*/ 
+
+typedef void (* oom_fn)(void);
+
+oom_fn CORD_oom_fn = (oom_fn) 0;
+
+# define OUT_OF_MEMORY {  if (CORD_oom_fn != (oom_fn) 0) (*CORD_oom_fn)(); \
+			  ABORT("Out of memory\n"); }
+# define ABORT(msg) { fprintf(stderr, "%s\n", msg); abort(); }
+
+typedef unsigned long word;
+
+typedef union {
+    struct Concatenation {
+    	char null;
+	char header;
+	char depth;	/* concatenation nesting depth. */
+	unsigned char left_len;
+			/* Length of left child if it is sufficiently	*/
+			/* short; 0 otherwise.				*/
+#	    define MAX_LEFT_LEN 255
+	word len;
+	CORD left;	/* length(left) > 0	*/
+	CORD right;	/* length(right) > 0	*/
+    } concatenation;
+    struct Function {
+	char null;
+	char header;
+	char depth;	/* always 0	*/
+	char left_len;	/* always 0	*/
+	word len;
+	CORD_fn fn;
+	void * client_data;
+    } function;
+    struct Generic {
+    	char null;
+	char header;
+	char depth;
+	char left_len;
+	word len;
+    } generic;
+    char string[1];
+} CordRep;
+
+# define CONCAT_HDR 1
+	
+# define FN_HDR 4
+# define SUBSTR_HDR 6
+	/* Substring nodes are a special case of function nodes.  	*/
+	/* The client_data field is known to point to a substr_args	*/
+	/* structure, and the function is either CORD_apply_access_fn 	*/
+	/* or CORD_index_access_fn.					*/
+
+/* The following may be applied only to function and concatenation nodes: */
+#define IS_CONCATENATION(s)  (((CordRep *)s)->generic.header == CONCAT_HDR)
+
+#define IS_FUNCTION(s)  ((((CordRep *)s)->generic.header & FN_HDR) != 0)
+
+#define IS_SUBSTR(s) (((CordRep *)s)->generic.header == SUBSTR_HDR)
+
+#define LEN(s) (((CordRep *)s) -> generic.len)
+#define DEPTH(s) (((CordRep *)s) -> generic.depth)
+#define GEN_LEN(s) (CORD_IS_STRING(s) ? strlen(s) : LEN(s))
+
+#define LEFT_LEN(c) ((c) -> left_len != 0? \
+				(c) -> left_len \
+				: (CORD_IS_STRING((c) -> left) ? \
+					(c) -> len - GEN_LEN((c) -> right) \
+					: LEN((c) -> left)))
+
+#define SHORT_LIMIT (sizeof(CordRep) - 1)
+	/* Cords shorter than this are C strings */
+
+
+/* Dump the internal representation of x to stdout, with initial 	*/
+/* indentation level n.							*/
+void CORD_dump_inner(CORD x, unsigned n)
+{
+    register size_t i;
+    
+    for (i = 0; i < (size_t)n; i++) {
+        fputs("  ", stdout);
+    }
+    if (x == 0) {
+      	fputs("NIL\n", stdout);
+    } else if (CORD_IS_STRING(x)) {
+        for (i = 0; i <= SHORT_LIMIT; i++) {
+            if (x[i] == '\0') break;
+            putchar(x[i]);
+        }
+        if (x[i] != '\0') fputs("...", stdout);
+        putchar('\n');
+    } else if (IS_CONCATENATION(x)) {
+        register struct Concatenation * conc =
+        			&(((CordRep *)x) -> concatenation);
+        printf("Concatenation: %p (len: %d, depth: %d)\n",
+               x, (int)(conc -> len), (int)(conc -> depth));
+        CORD_dump_inner(conc -> left, n+1);
+        CORD_dump_inner(conc -> right, n+1);
+    } else /* function */{
+        register struct Function * func =
+        			&(((CordRep *)x) -> function);
+        if (IS_SUBSTR(x)) printf("(Substring) ");
+        printf("Function: %p (len: %d): ", x, (int)(func -> len));
+        for (i = 0; i < 20 && i < func -> len; i++) {
+            putchar((*(func -> fn))(i, func -> client_data));
+        }
+        if (i < func -> len) fputs("...", stdout);
+        putchar('\n');
+    }
+}
+
+/* Dump the internal representation of x to stdout	*/
+void CORD_dump(CORD x)
+{
+    CORD_dump_inner(x, 0);
+    fflush(stdout);
+}
+
+CORD CORD_cat_char_star(CORD x, const char * y, size_t leny)
+{
+    register size_t result_len;
+    register size_t lenx;
+    register int depth;
+    
+    if (x == CORD_EMPTY) return(y);
+    if (leny == 0) return(x);
+    if (CORD_IS_STRING(x)) {
+        lenx = strlen(x);
+        result_len = lenx + leny;
+        if (result_len <= SHORT_LIMIT) {
+            register char * result = GC_MALLOC_ATOMIC(result_len+1);
+        
+            if (result == 0) OUT_OF_MEMORY;
+            memcpy(result, x, lenx);
+            memcpy(result + lenx, y, leny);
+            result[result_len] = '\0';
+            return((CORD) result);
+        } else {
+            depth = 1;
+        }
+    } else {
+    	register CORD right;
+    	register CORD left;
+    	register char * new_right;
+    	register size_t right_len;
+    	
+    	lenx = LEN(x);
+    	
+        if (leny <= SHORT_LIMIT/2
+    	    && IS_CONCATENATION(x)
+            && CORD_IS_STRING(right = ((CordRep *)x) -> concatenation.right)) {
+            /* Merge y into right part of x. */
+            if (!CORD_IS_STRING(left = ((CordRep *)x) -> concatenation.left)) {
+            	right_len = lenx - LEN(left);
+            } else if (((CordRep *)x) -> concatenation.left_len != 0) {
+                right_len = lenx - ((CordRep *)x) -> concatenation.left_len;
+            } else {
+            	right_len = strlen(right);
+            }
+            result_len = right_len + leny;  /* length of new_right */
+            if (result_len <= SHORT_LIMIT) {
+            	new_right = GC_MALLOC_ATOMIC(result_len + 1);
+            	memcpy(new_right, right, right_len);
+            	memcpy(new_right + right_len, y, leny);
+            	new_right[result_len] = '\0';
+            	y = new_right;
+            	leny = result_len;
+            	x = left;
+            	lenx -= right_len;
+            	/* Now fall through to concatenate the two pieces: */
+            }
+            if (CORD_IS_STRING(x)) {
+                depth = 1;
+            } else {
+                depth = DEPTH(x) + 1;
+            }
+        } else {
+            depth = DEPTH(x) + 1;
+        }
+        result_len = lenx + leny;
+    }
+    {
+      /* The general case; lenx, result_len is known: */
+    	register struct Concatenation * result;
+    	
+    	result = GC_NEW(struct Concatenation);
+    	if (result == 0) OUT_OF_MEMORY;
+    	result->header = CONCAT_HDR;
+    	result->depth = depth;
+    	if (lenx <= MAX_LEFT_LEN) result->left_len = lenx;
+    	result->len = result_len;
+    	result->left = x;
+    	result->right = y;
+    	if (depth > MAX_DEPTH) {
+    	    return(CORD_balance((CORD)result));
+    	} else {
+    	    return((CORD) result);
+    	}
+    }
+}
+
+
+CORD CORD_cat(CORD x, CORD y)
+{
+    register size_t result_len;
+    register int depth;
+    register size_t lenx;
+    
+    if (x == CORD_EMPTY) return(y);
+    if (y == CORD_EMPTY) return(x);
+    if (CORD_IS_STRING(y)) {
+        return(CORD_cat_char_star(x, y, strlen(y)));
+    } else if (CORD_IS_STRING(x)) {
+        lenx = strlen(x);
+        depth = DEPTH(y) + 1;
+    } else {
+        register int depthy = DEPTH(y);
+        
+        lenx = LEN(x);
+        depth = DEPTH(x) + 1;
+        if (depthy >= depth) depth = depthy + 1;
+    }
+    result_len = lenx + LEN(y);
+    {
+    	register struct Concatenation * result;
+    	
+    	result = GC_NEW(struct Concatenation);
+    	if (result == 0) OUT_OF_MEMORY;
+    	result->header = CONCAT_HDR;
+    	result->depth = depth;
+    	if (lenx <= MAX_LEFT_LEN) result->left_len = lenx;
+    	result->len = result_len;
+    	result->left = x;
+    	result->right = y;
+    	return((CORD) result);
+    }
+}
+
+
+
+CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len)
+{
+    if (len <= 0) return(0);
+    if (len <= SHORT_LIMIT) {
+        register char * result;
+        register size_t i;
+        char buf[SHORT_LIMIT+1];
+        register char c;
+        
+        for (i = 0; i < len; i++) {
+            c = (*fn)(i, client_data);
+            if (c == '\0') goto gen_case;
+            buf[i] = c;
+        }
+        buf[i] = '\0';
+        result = GC_MALLOC_ATOMIC(len+1);
+        if (result == 0) OUT_OF_MEMORY;
+        strcpy(result, buf);
+        result[len] = '\0';
+        return((CORD) result);
+    }
+  gen_case:
+    {
+    	register struct Function * result;
+    	
+    	result = GC_NEW(struct Function);
+    	if (result == 0) OUT_OF_MEMORY;
+    	result->header = FN_HDR;
+    	/* depth is already 0 */
+    	result->len = len;
+    	result->fn = fn;
+    	result->client_data = client_data;
+    	return((CORD) result);
+    }
+}
+
+size_t CORD_len(CORD x)
+{
+    if (x == 0) {
+     	return(0);
+    } else {
+	return(GEN_LEN(x));
+    }
+}
+
+struct substr_args {
+    CordRep * sa_cord;
+    size_t sa_index;
+};
+
+char CORD_index_access_fn(size_t i, void * client_data)
+{
+    register struct substr_args *descr = (struct substr_args *)client_data;
+    
+    return(((char *)(descr->sa_cord))[i + descr->sa_index]);
+}
+
+char CORD_apply_access_fn(size_t i, void * client_data)
+{
+    register struct substr_args *descr = (struct substr_args *)client_data;
+    register struct Function * fn_cord = &(descr->sa_cord->function);
+    
+    return((*(fn_cord->fn))(i + descr->sa_index, fn_cord->client_data));
+}
+
+/* A version of CORD_substr that simply returns a function node, thus	*/
+/* postponing its work.	The fourth argument is a function that may	*/
+/* be used for efficient access to the ith character.			*/
+/* Assumes i >= 0 and i + n < length(x).				*/
+CORD CORD_substr_closure(CORD x, size_t i, size_t n, CORD_fn f)
+{
+    register struct substr_args * sa = GC_NEW(struct substr_args);
+    CORD result;
+    
+    if (sa == 0) OUT_OF_MEMORY;
+    sa->sa_cord = (CordRep *)x;
+    sa->sa_index = i;
+    result = CORD_from_fn(f, (void *)sa, n);
+    ((CordRep *)result) -> function.header = SUBSTR_HDR;
+    return (result);
+}
+
+# define SUBSTR_LIMIT (10 * SHORT_LIMIT)
+	/* Substrings of function nodes and flat strings shorter than 	*/
+	/* this are flat strings.  Othewise we use a functional 	*/
+	/* representation, which is significantly slower to access.	*/
+
+/* A version of CORD_substr that assumes i >= 0, n > 0, and i + n < length(x).*/
+CORD CORD_substr_checked(CORD x, size_t i, size_t n)
+{
+    if (CORD_IS_STRING(x)) {
+        if (n > SUBSTR_LIMIT) {
+            return(CORD_substr_closure(x, i, n, CORD_index_access_fn));
+        } else {
+            register char * result = GC_MALLOC_ATOMIC(n+1);
+            
+            if (result == 0) OUT_OF_MEMORY;
+            strncpy(result, x+i, n);
+            result[n] = '\0';
+            return(result);
+        }
+    } else if (IS_CONCATENATION(x)) {
+    	register struct Concatenation * conc
+    			= &(((CordRep *)x) -> concatenation);
+    	register size_t left_len;
+    	register size_t right_len;
+    	
+    	left_len = LEFT_LEN(conc);
+    	right_len = conc -> len - left_len;
+    	if (i >= left_len) {
+    	    if (n == right_len) return(conc -> right);
+    	    return(CORD_substr_checked(conc -> right, i - left_len, n));
+    	} else if (i+n <= left_len) {
+    	    if (n == left_len) return(conc -> left);
+    	    return(CORD_substr_checked(conc -> left, i, n));
+    	} else {
+    	    /* Need at least one character from each side. */
+    	    register CORD left_part;
+    	    register CORD right_part;
+    	    register size_t left_part_len = left_len - i;
+     	
+    	    if (i == 0) {
+    	        left_part = conc -> left;
+    	    } else {
+    	        left_part = CORD_substr_checked(conc -> left, i, left_part_len);
+    	    }
+    	    if (i + n == right_len + left_len) {
+    	         right_part = conc -> right;
+    	    } else {
+    	         right_part = CORD_substr_checked(conc -> right, 0,
+    	    				          n - left_part_len);
+    	    }
+    	    return(CORD_cat(left_part, right_part));
+    	}
+    } else /* function */ {
+        if (n > SUBSTR_LIMIT) {
+            if (IS_SUBSTR(x)) {
+            	/* Avoid nesting substring nodes.	*/
+            	register struct Function * f = &(((CordRep *)x) -> function);
+            	register struct substr_args *descr =
+            			(struct substr_args *)(f -> client_data);
+            	
+            	return(CORD_substr_closure((CORD)descr->sa_cord,
+            				   i + descr->sa_index,
+            				   n, f -> fn));
+            } else {
+                return(CORD_substr_closure(x, i, n, CORD_apply_access_fn));
+            }
+        } else {
+            char * result;
+            register struct Function * f = &(((CordRep *)x) -> function);
+            char buf[SUBSTR_LIMIT+1];
+            register char * p = buf;
+            register char c;
+            register int j;
+            register int lim = i + n;
+            
+            for (j = i; j < lim; j++) {
+            	c = (*(f -> fn))(j, f -> client_data);
+            	if (c == '\0') {
+            	    return(CORD_substr_closure(x, i, n, CORD_apply_access_fn));
+            	}
+            	*p++ = c;
+            }
+            *p = '\0';
+            result = GC_MALLOC_ATOMIC(n+1);
+            if (result == 0) OUT_OF_MEMORY;
+            strcpy(result, buf);
+            return(result);
+        }
+    }
+}
+
+CORD CORD_substr(CORD x, size_t i, size_t n)
+{
+    register size_t len = CORD_len(x);
+    
+    if (i >= len || n <= 0) return(0);
+    	/* n < 0 is impossible in a correct C implementation, but	*/
+    	/* quite possible  under SunOS 4.X.				*/
+    if (i + n > len) n = len - i;
+#   ifndef __STDC__
+      if (i < 0) ABORT("CORD_substr: second arg. negative");
+    	/* Possible only if both client and C implementation are buggy.	*/
+    	/* But empirically this happens frequently.			*/
+#   endif
+    return(CORD_substr_checked(x, i, n));
+}
+
+/* See cord.h for definition.  We assume i is in range.	*/
+int CORD_iter5(CORD x, size_t i, CORD_iter_fn f1,
+			 CORD_batched_iter_fn f2, void * client_data)
+{
+    if (x == 0) return(0);
+    if (CORD_IS_STRING(x)) {
+    	register const char *p = x+i;
+    	
+    	if (*p == '\0') ABORT("2nd arg to CORD_iter5 too big");
+        if (f2 != CORD_NO_FN) {
+            return((*f2)(p, client_data));
+        } else {
+	    while (*p) {
+                if ((*f1)(*p, client_data)) return(1);
+                p++;
+	    }
+	    return(0);
+        }
+    } else if (IS_CONCATENATION(x)) {
+    	register struct Concatenation * conc
+    			= &(((CordRep *)x) -> concatenation);
+    	
+    	
+    	if (i > 0) {
+    	    register size_t left_len = LEFT_LEN(conc);
+    	    
+    	    if (i >= left_len) {
+    	        return(CORD_iter5(conc -> right, i - left_len, f1, f2,
+    	        		  client_data));
+    	    }
+    	}
+    	if (CORD_iter5(conc -> left, i, f1, f2, client_data)) {
+    	    return(1);
+    	}
+    	return(CORD_iter5(conc -> right, 0, f1, f2, client_data));
+    } else /* function */ {
+        register struct Function * f = &(((CordRep *)x) -> function);
+        register size_t j;
+        register size_t lim = f -> len;
+        
+        for (j = i; j < lim; j++) {
+            if ((*f1)((*(f -> fn))(j, f -> client_data), client_data)) {
+                return(1);
+            }
+        }
+        return(0);
+    }
+}
+			
+#undef CORD_iter
+int CORD_iter(CORD x, CORD_iter_fn f1, void * client_data)
+{
+    return(CORD_iter5(x, 0, f1, CORD_NO_FN, client_data));
+}
+
+int CORD_riter4(CORD x, size_t i, CORD_iter_fn f1, void * client_data)
+{
+    if (x == 0) return(0);
+    if (CORD_IS_STRING(x)) {
+	register const char *p = x + i;
+	register char c;
+               
+	for(;;) {
+	    c = *p;
+	    if (c == '\0') ABORT("2nd arg to CORD_riter4 too big");
+            if ((*f1)(c, client_data)) return(1);
+	    if (p == x) break;
+            p--;
+	}
+	return(0);
+    } else if (IS_CONCATENATION(x)) {
+    	register struct Concatenation * conc
+    			= &(((CordRep *)x) -> concatenation);
+    	register CORD left_part = conc -> left;
+    	register size_t left_len;
+    	
+    	left_len = LEFT_LEN(conc);
+    	if (i >= left_len) {
+    	    if (CORD_riter4(conc -> right, i - left_len, f1, client_data)) {
+    	    	return(1);
+    	    }
+    	    return(CORD_riter4(left_part, left_len - 1, f1, client_data));
+    	} else {
+    	    return(CORD_riter4(left_part, i, f1, client_data));
+    	}
+    } else /* function */ {
+        register struct Function * f = &(((CordRep *)x) -> function);
+        register size_t j;
+        
+        for (j = i; ; j--) {
+            if ((*f1)((*(f -> fn))(j, f -> client_data), client_data)) {
+                return(1);
+            }
+            if (j == 0) return(0);
+        }
+    }
+}
+
+int CORD_riter(CORD x, CORD_iter_fn f1, void * client_data)
+{
+    return(CORD_riter4(x, CORD_len(x) - 1, f1, client_data));
+}
+
+/*
+ * The following functions are concerned with balancing cords.
+ * Strategy:
+ * Scan the cord from left to right, keeping the cord scanned so far
+ * as a forest of balanced trees of exponentialy decreasing length.
+ * When a new subtree needs to be added to the forest, we concatenate all
+ * shorter ones to the new tree in the appropriate order, and then insert
+ * the result into the forest.
+ * Crucial invariants:
+ * 1. The concatenation of the forest (in decreasing order) with the
+ *     unscanned part of the rope is equal to the rope being balanced.
+ * 2. All trees in the forest are balanced.
+ * 3. forest[i] has depth at most i.
+ */
+
+typedef struct {
+    CORD c;
+    size_t len;		/* Actual length of c 	*/
+} ForestElement;
+
+static size_t min_len [ MAX_DEPTH ];
+
+static int min_len_init = 0;
+
+int CORD_max_len;
+
+typedef ForestElement Forest [ MAX_DEPTH ];
+			/* forest[i].len >= fib(i+1)	        */
+			/* The string is the concatenation	*/
+			/* of the forest in order of DECREASING */
+			/* indices.				*/
+
+void CORD_init_min_len()
+{
+    register int i;
+    register size_t last, previous, current;
+        
+    min_len[0] = previous = 1;
+    min_len[1] = last = 2;
+    for (i = 2; i < MAX_DEPTH; i++) {
+    	current = last + previous;
+    	if (current < last) /* overflow */ current = last;
+    	min_len[i] = current;
+    	previous = last;
+    	last = current;
+    }
+    CORD_max_len = last - 1;
+    min_len_init = 1;
+}
+
+
+void CORD_init_forest(ForestElement * forest, size_t max_len)
+{
+    register int i;
+    
+    for (i = 0; i < MAX_DEPTH; i++) {
+    	forest[i].c = 0;
+    	if (min_len[i] > max_len) return;
+    }
+    ABORT("Cord too long");
+}
+
+/* Add a leaf to the appropriate level in the forest, cleaning		*/
+/* out lower levels as necessary.					*/
+/* Also works if x is a balanced tree of concatenations; however	*/
+/* in this case an extra concatenation node may be inserted above x;	*/
+/* This node should not be counted in the statement of the invariants.	*/
+void CORD_add_forest(ForestElement * forest, CORD x, size_t len)
+{
+    register int i = 0;
+    register CORD sum = CORD_EMPTY;
+    register size_t sum_len = 0;
+    
+    while (len > min_len[i + 1]) {
+    	if (forest[i].c != 0) {
+    	    sum = CORD_cat(forest[i].c, sum);
+    	    sum_len += forest[i].len;
+    	    forest[i].c = 0;
+    	}
+        i++;
+    }
+    /* Sum has depth at most 1 greter than what would be required 	*/
+    /* for balance.							*/
+    sum = CORD_cat(sum, x);
+    sum_len += len;
+    /* If x was a leaf, then sum is now balanced.  To see this		*/
+    /* consider the two cases in which forest[i-1] either is or is 	*/
+    /* not empty.							*/
+    while (sum_len >= min_len[i]) {
+    	if (forest[i].c != 0) {
+    	    sum = CORD_cat(forest[i].c, sum);
+    	    sum_len += forest[i].len;
+    	    /* This is again balanced, since sum was balanced, and has	*/
+    	    /* allowable depth that differs from i by at most 1.	*/
+    	    forest[i].c = 0;
+    	}
+        i++;
+    }
+    i--;
+    forest[i].c = sum;
+    forest[i].len = sum_len;
+}
+
+CORD CORD_concat_forest(ForestElement * forest, size_t expected_len)
+{
+    register int i = 0;
+    CORD sum = 0;
+    size_t sum_len = 0;
+    
+    while (sum_len != expected_len) {
+    	if (forest[i].c != 0) {
+    	    sum = CORD_cat(forest[i].c, sum);
+    	    sum_len += forest[i].len;
+    	}
+        i++;
+    }
+    return(sum);
+}
+
+/* Insert the frontier of x into forest.  Balanced subtrees are	*/
+/* treated as leaves.  This potentially adds one to the depth	*/
+/* of the final tree.						*/
+void CORD_balance_insert(CORD x, size_t len, ForestElement * forest)
+{
+    register int depth;
+    
+    if (CORD_IS_STRING(x)) {
+        CORD_add_forest(forest, x, len);
+    } else if (IS_CONCATENATION(x)
+               && ((depth = DEPTH(x)) >= MAX_DEPTH
+                   || len < min_len[depth])) {
+    	register struct Concatenation * conc
+    			= &(((CordRep *)x) -> concatenation);
+    	size_t left_len = LEFT_LEN(conc);
+    	
+    	CORD_balance_insert(conc -> left, left_len, forest);
+    	CORD_balance_insert(conc -> right, len - left_len, forest);
+    } else /* function or balanced */ {
+    	CORD_add_forest(forest, x, len);
+    }
+}
+
+
+CORD CORD_balance(CORD x)
+{
+    Forest forest;
+    register size_t len;
+    
+    if (x == 0) return(0);
+    if (CORD_IS_STRING(x)) return(x);
+    if (!min_len_init) CORD_init_min_len();
+    len = LEN(x);
+    CORD_init_forest(forest, len);
+    CORD_balance_insert(x, len, forest);
+    return(CORD_concat_forest(forest, len));
+}
+
+
+/* Position primitives	*/
+
+/* Private routines to deal with the hard cases only: */
+
+/* P contains a prefix of the  path to cur_pos.	Extend it to a full	*/
+/* path and set up leaf info.						*/
+/* Return 0 if past the end of cord, 1 o.w.				*/
+void CORD__extend_path(register CORD_pos p)
+{
+     register struct CORD_pe * current_pe = &(p[0].path[p[0].path_len]);
+     register CORD top = current_pe -> pe_cord;
+     register size_t pos = p[0].cur_pos;
+     register size_t top_pos = current_pe -> pe_start_pos;
+     register size_t top_len = GEN_LEN(top);
+     
+     /* Fill in the rest of the path. */
+       while(!CORD_IS_STRING(top) && IS_CONCATENATION(top)) {
+     	 register struct Concatenation * conc =
+     	 		&(((CordRep *)top) -> concatenation);
+     	 register size_t left_len;
+     	 
+     	 left_len = LEFT_LEN(conc);
+     	 current_pe++;
+     	 if (pos >= top_pos + left_len) {
+     	     current_pe -> pe_cord = top = conc -> right;
+     	     current_pe -> pe_start_pos = top_pos = top_pos + left_len;
+     	     top_len -= left_len;
+     	 } else {
+     	     current_pe -> pe_cord = top = conc -> left;
+     	     current_pe -> pe_start_pos = top_pos;
+     	     top_len = left_len;
+     	 }
+     	 p[0].path_len++;
+       }
+     /* Fill in leaf description for fast access. */
+       if (CORD_IS_STRING(top)) {
+         p[0].cur_leaf = top;
+         p[0].cur_start = top_pos;
+         p[0].cur_end = top_pos + top_len;
+       } else {
+         p[0].cur_end = 0;
+       }
+       if (pos >= top_pos + top_len) p[0].path_len = CORD_POS_INVALID;
+}
+
+char CORD__pos_fetch(register CORD_pos p)
+{
+    /* Leaf is a function node */
+    struct CORD_pe * pe = &((p)[0].path[(p)[0].path_len]);
+    CORD leaf = pe -> pe_cord;
+    register struct Function * f = &(((CordRep *)leaf) -> function);
+    
+    if (!IS_FUNCTION(leaf)) ABORT("CORD_pos_fetch: bad leaf");
+    return ((*(f -> fn))(p[0].cur_pos - pe -> pe_start_pos, f -> client_data));
+}
+
+void CORD__next(register CORD_pos p)
+{
+    register size_t cur_pos = p[0].cur_pos + 1;
+    register struct CORD_pe * current_pe = &((p)[0].path[(p)[0].path_len]);
+    register CORD leaf = current_pe -> pe_cord;
+    
+    /* Leaf is not a string or we're at end of leaf */
+    p[0].cur_pos = cur_pos;
+    if (!CORD_IS_STRING(leaf)) {
+    	/* Function leaf	*/
+    	register struct Function * f = &(((CordRep *)leaf) -> function);
+    	register size_t start_pos = current_pe -> pe_start_pos;
+    	register size_t end_pos = start_pos + f -> len;
+    	
+    	if (cur_pos < end_pos) {
+    	  /* Fill cache and return. */
+    	    register size_t i;
+    	    register size_t limit = cur_pos + FUNCTION_BUF_SZ;
+    	    register CORD_fn fn = f -> fn;
+    	    register void * client_data = f -> client_data;
+    	    
+    	    if (limit > end_pos) {
+    	        limit = end_pos;
+    	    }
+    	    for (i = cur_pos; i < limit; i++) {
+    	        p[0].function_buf[i - cur_pos] =
+    	        	(*fn)(i - start_pos, client_data);
+    	    }
+    	    p[0].cur_start = cur_pos;
+    	    p[0].cur_leaf = p[0].function_buf;
+    	    p[0].cur_end = limit;
+    	    return;
+    	}
+    }
+    /* End of leaf	*/
+    /* Pop the stack until we find two concatenation nodes with the 	*/
+    /* same start position: this implies we were in left part.		*/
+    {
+    	while (p[0].path_len > 0
+    	       && current_pe[0].pe_start_pos != current_pe[-1].pe_start_pos) {
+    	    p[0].path_len--;
+    	    current_pe--;
+    	}
+    	if (p[0].path_len == 0) {
+	    p[0].path_len = CORD_POS_INVALID;
+            return;
+	}
+    }
+    p[0].path_len--;
+    CORD__extend_path(p);
+}
+
+void CORD__prev(register CORD_pos p)
+{
+    register struct CORD_pe * pe = &(p[0].path[p[0].path_len]);
+    
+    if (p[0].cur_pos == 0) {
+        p[0].path_len = CORD_POS_INVALID;
+        return;
+    }
+    p[0].cur_pos--;
+    if (p[0].cur_pos >= pe -> pe_start_pos) return;
+    
+    /* Beginning of leaf	*/
+    
+    /* Pop the stack until we find two concatenation nodes with the 	*/
+    /* different start position: this implies we were in right part.	*/
+    {
+    	register struct CORD_pe * current_pe = &((p)[0].path[(p)[0].path_len]);
+    	
+    	while (p[0].path_len > 0
+    	       && current_pe[0].pe_start_pos == current_pe[-1].pe_start_pos) {
+    	    p[0].path_len--;
+    	    current_pe--;
+    	}
+    }
+    p[0].path_len--;
+    CORD__extend_path(p);
+}
+
+#undef CORD_pos_fetch
+#undef CORD_next
+#undef CORD_prev
+#undef CORD_pos_to_index
+#undef CORD_pos_to_cord
+#undef CORD_pos_valid
+
+char CORD_pos_fetch(register CORD_pos p)
+{
+    if (p[0].cur_start <= p[0].cur_pos && p[0].cur_pos < p[0].cur_end) {
+    	return(p[0].cur_leaf[p[0].cur_pos - p[0].cur_start]);
+    } else {
+        return(CORD__pos_fetch(p));
+    }
+}
+
+void CORD_next(CORD_pos p)
+{
+    if (p[0].cur_pos < p[0].cur_end - 1) {
+    	p[0].cur_pos++;
+    } else {
+    	CORD__next(p);
+    }
+}
+
+void CORD_prev(CORD_pos p)
+{
+    if (p[0].cur_end != 0 && p[0].cur_pos > p[0].cur_start) {
+    	p[0].cur_pos--;
+    } else {
+    	CORD__prev(p);
+    }
+}
+
+size_t CORD_pos_to_index(CORD_pos p)
+{
+    return(p[0].cur_pos);
+}
+
+CORD CORD_pos_to_cord(CORD_pos p)
+{
+    return(p[0].path[0].pe_cord);
+}
+
+int CORD_pos_valid(CORD_pos p)
+{
+    return(p[0].path_len != CORD_POS_INVALID);
+}
+
+void CORD_set_pos(CORD_pos p, CORD x, size_t i)
+{
+    if (x == CORD_EMPTY) {
+    	p[0].path_len = CORD_POS_INVALID;
+    	return;
+    }
+    p[0].path[0].pe_cord = x;
+    p[0].path[0].pe_start_pos = 0;
+    p[0].path_len = 0;
+    p[0].cur_pos = i;
+    CORD__extend_path(p);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/cord/cordprnt.c	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,390 @@
+/* 
+ * Copyright (c) 1993-1994 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+/* An sprintf implementation that understands cords.  This is probably	*/
+/* not terribly portable.  It assumes an ANSI stdarg.h.  It further	*/
+/* assumes that I can make copies of va_list variables, and read 	*/
+/* arguments repeatedly by applyting va_arg to the copies.  This	*/
+/* could be avoided at some performance cost.				*/
+/* We also assume that unsigned and signed integers of various kinds	*/
+/* have the same sizes, and can be cast back and forth.			*/
+/* We assume that void * and char * have the same size.			*/
+/* All this cruft is needed because we want to rely on the underlying	*/
+/* sprintf implementation whenever possible.				*/
+/* Boehm, September 21, 1995 6:00 pm PDT */
+
+#include "cord.h"
+#include "ec.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include "gc.h"
+
+#define CONV_SPEC_LEN 50	/* Maximum length of a single	*/
+				/* conversion specification.	*/
+#define CONV_RESULT_LEN 50	/* Maximum length of any 	*/
+				/* conversion with default	*/
+				/* width and prec.		*/
+
+
+static int ec_len(CORD_ec x)
+{
+    return(CORD_len(x[0].ec_cord) + (x[0].ec_bufptr - x[0].ec_buf));
+}
+
+/* Possible nonumeric precision values.	*/
+# define NONE -1
+# define VARIABLE -2
+/* Copy the conversion specification from CORD_pos into the buffer buf	*/
+/* Return negative on error.						*/
+/* Source initially points one past the leading %.			*/
+/* It is left pointing at the conversion type.				*/
+/* Assign field width and precision to *width and *prec.		*/
+/* If width or prec is *, VARIABLE is assigned.				*/
+/* Set *left to 1 if left adjustment flag is present.			*/
+/* Set *long_arg to 1 if long flag ('l' or 'L') is present, or to	*/
+/* -1 if 'h' is present.						*/
+static int extract_conv_spec(CORD_pos source, char *buf,
+			     int * width, int *prec, int *left, int * long_arg)
+{
+    register int result = 0;
+    register int current_number = 0;
+    register int saw_period = 0;
+    register int saw_number;
+    register int chars_so_far = 0;
+    register char current;
+    
+    *width = NONE;
+    buf[chars_so_far++] = '%';
+    while(CORD_pos_valid(source)) {
+        if (chars_so_far >= CONV_SPEC_LEN) return(-1);
+        current = CORD_pos_fetch(source);
+        buf[chars_so_far++] = current;
+        switch(current) {
+	  case '*':
+	    saw_number = 1;
+	    current_number = VARIABLE;
+	    break;
+          case '0':
+            if (!saw_number) {
+                /* Zero fill flag; ignore */
+                break;
+            } /* otherwise fall through: */
+          case '1':
+	  case '2':
+	  case '3':
+	  case '4':
+	  case '5':
+          case '6':
+	  case '7':
+	  case '8':
+	  case '9':
+	    saw_number = 1;
+	    current_number *= 10;
+	    current_number += current - '0';
+	    break;
+	  case '.':
+	    saw_period = 1;
+	    if(saw_number) {
+	        *width = current_number;
+	        saw_number = 0;
+	    }
+	    current_number = 0;
+	    break;
+	  case 'l':
+	  case 'L':
+	    *long_arg = 1;
+	    current_number = 0;
+	    break;
+	  case 'h':
+	    *long_arg = -1;
+	    current_number = 0;
+	    break;
+	  case ' ':
+	  case '+':
+	  case '#':
+	    current_number = 0;
+	    break;
+	  case '-':
+	    *left = 1;
+	    current_number = 0;
+	    break;
+	  case 'd':
+	  case 'i':
+	  case 'o':
+	  case 'u':
+	  case 'x':
+	  case 'X':
+	  case 'f':
+	  case 'e':
+	  case 'E':
+	  case 'g':
+	  case 'G':
+	  case 'c':
+	  case 'C':
+	  case 's':
+	  case 'S':
+	  case 'p':
+	  case 'n':
+	  case 'r':
+	    goto done;          
+          default:
+            return(-1);
+        }
+        CORD_next(source);
+    }
+    return(-1);
+  done:
+    if (saw_number) {
+    	if (saw_period) {
+    	    *prec = current_number;
+    	} else {
+    	    *prec = NONE;
+    	    *width = current_number;
+    	}
+    } else {
+    	*prec = NONE;
+    }
+    buf[chars_so_far] = '\0';
+    return(result);
+}
+
+int CORD_vsprintf(CORD * out, CORD format, va_list args)
+{
+    CORD_ec result;
+    register int count;
+    register char current;
+    CORD_pos pos;
+    char conv_spec[CONV_SPEC_LEN + 1];
+    
+    CORD_ec_init(result);
+    for (CORD_set_pos(pos, format, 0); CORD_pos_valid(pos); CORD_next(pos)) {
+       	current = CORD_pos_fetch(pos);
+       	if (current == '%') {
+            CORD_next(pos);
+            if (!CORD_pos_valid(pos)) return(-1);
+            current = CORD_pos_fetch(pos);
+            if (current == '%') {
+               	CORD_ec_append(result, current);
+            } else {
+             	int width, prec;
+             	int left_adj = 0;
+             	int long_arg = 0;
+		CORD arg;
+		size_t len;
+               
+              	if (extract_conv_spec(pos, conv_spec,
+              			      &width, &prec,
+              			      &left_adj, &long_arg) < 0) {
+              	    return(-1);
+              	}
+              	current = CORD_pos_fetch(pos);
+            	switch(current) {
+            	    case 'n':
+            	    	/* Assign length to next arg */
+            	    	if (long_arg == 0) {
+            	    	    int * pos_ptr;
+            	    	    pos_ptr = va_arg(args, int *);
+            	    	    *pos_ptr = ec_len(result);
+            	    	} else if (long_arg > 0) {
+            	    	    long * pos_ptr;
+            	    	    pos_ptr = va_arg(args, long *);
+            	    	    *pos_ptr = ec_len(result);
+            	    	} else {
+            	    	    short * pos_ptr;
+            	    	    pos_ptr = va_arg(args, short *);
+            	    	    *pos_ptr = ec_len(result);
+            	    	}
+            	    	goto done;
+            	    case 'r':
+            	    	/* Append cord and any padding	*/
+            	    	if (width == VARIABLE) width = va_arg(args, int);
+            	    	if (prec == VARIABLE) prec = va_arg(args, int);
+			arg = va_arg(args, CORD);
+			len = CORD_len(arg);
+			if (prec != NONE && len > prec) {
+			  if (prec < 0) return(-1);
+			  arg = CORD_substr(arg, 0, prec);
+			  len = prec;
+			}
+			if (width != NONE && len < width) {
+			  char * blanks = GC_MALLOC_ATOMIC(width-len+1);
+
+			  memset(blanks, ' ', width-len);
+			  blanks[width-len] = '\0';
+			  if (left_adj) {
+			    arg = CORD_cat(arg, blanks);
+			  } else {
+			    arg = CORD_cat(blanks, arg);
+			  }
+			}
+			CORD_ec_append_cord(result, arg);
+            	    	goto done;
+		    case 'c':
+			if (width == NONE && prec == NONE) {
+			    register char c;
+
+			    c = va_arg(args, int);
+			    CORD_ec_append(result, c);
+			    goto done;
+			}
+			break;
+		    case 's':
+		        if (width == NONE && prec == NONE) {
+			    char * str = va_arg(args, char *);
+			    register char c;
+
+			    while (c = *str++) {
+			        CORD_ec_append(result, c);
+			    }
+			    goto done;
+			}
+			break;
+            	    default:
+            	        break;
+            	}
+            	/* Use standard sprintf to perform conversion */
+            	{
+            	    register char * buf;
+            	    va_list vsprintf_args = args;
+            	    	/* The above does not appear to be sanctioned	*/
+            	    	/* by the ANSI C standard.			*/
+            	    int max_size = 0;
+            	    int res;
+            	    	
+            	    if (width == VARIABLE) width = va_arg(args, int);
+            	    if (prec == VARIABLE) prec = va_arg(args, int);
+            	    if (width != NONE) max_size = width;
+            	    if (prec != NONE && prec > max_size) max_size = prec;
+            	    max_size += CONV_RESULT_LEN;
+            	    if (max_size >= CORD_BUFSZ) {
+            	        buf = GC_MALLOC_ATOMIC(max_size + 1);
+            	    } else {
+            	        if (CORD_BUFSZ - (result[0].ec_bufptr-result[0].ec_buf)
+            	            < max_size) {
+            	            CORD_ec_flush_buf(result);
+            	        }
+            	        buf = result[0].ec_bufptr;
+            	    }
+            	    switch(current) {
+            	        case 'd':
+            	        case 'i':
+            	        case 'o':
+            	        case 'u':
+            	        case 'x':
+            	        case 'X':
+            	        case 'c':
+            	            if (long_arg <= 0) {
+            	              (void) va_arg(args, int);
+            	            } else if (long_arg > 0) {
+            	              (void) va_arg(args, long);
+            	            }
+            	            break;
+            	        case 's':
+            	        case 'p':
+            	            (void) va_arg(args, char *);
+            	            break;
+            	        case 'f':
+            	        case 'e':
+            	        case 'E':
+            	        case 'g':
+            	        case 'G':
+            	            (void) va_arg(args, double);
+            	            break;
+            	        default:
+            	            return(-1);
+            	    }
+            	    res = vsprintf(buf, conv_spec, vsprintf_args);
+            	    len = (size_t)res;
+            	    if ((char *)(GC_word)res == buf) {
+            	    	/* old style vsprintf */
+            	    	len = strlen(buf);
+            	    } else if (res < 0) {
+            	        return(-1);
+            	    }
+            	    if (buf != result[0].ec_bufptr) {
+            	        register char c;
+
+			while (c = *buf++) {
+			    CORD_ec_append(result, c);
+		        }
+		    } else {
+		        result[0].ec_bufptr = buf + len;
+		    }
+            	}
+              done:;
+            }
+        } else {
+            CORD_ec_append(result, current);
+        }
+    }
+    count = ec_len(result);
+    *out = CORD_balance(CORD_ec_to_cord(result));
+    return(count);
+}
+
+int CORD_sprintf(CORD * out, CORD format, ...)
+{
+    va_list args;
+    int result;
+    
+    va_start(args, format);
+    result = CORD_vsprintf(out, format, args);
+    va_end(args);
+    return(result);
+}
+
+int CORD_fprintf(FILE * f, CORD format, ...)
+{
+    va_list args;
+    int result;
+    CORD out;
+    
+    va_start(args, format);
+    result = CORD_vsprintf(&out, format, args);
+    va_end(args);
+    if (result > 0) CORD_put(out, f);
+    return(result);
+}
+
+int CORD_vfprintf(FILE * f, CORD format, va_list args)
+{
+    int result;
+    CORD out;
+    
+    result = CORD_vsprintf(&out, format, args);
+    if (result > 0) CORD_put(out, f);
+    return(result);
+}
+
+int CORD_printf(CORD format, ...)
+{
+    va_list args;
+    int result;
+    CORD out;
+    
+    va_start(args, format);
+    result = CORD_vsprintf(&out, format, args);
+    va_end(args);
+    if (result > 0) CORD_put(out, stdout);
+    return(result);
+}
+
+int CORD_vprintf(CORD format, va_list args)
+{
+    int result;
+    CORD out;
+    
+    result = CORD_vsprintf(&out, format, args);
+    if (result > 0) CORD_put(out, stdout);
+    return(result);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/cord/cordtest.c	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,228 @@
+/* 
+ * Copyright (c) 1993-1994 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+/* Boehm, August 24, 1994 11:58 am PDT */
+# include "cord.h"
+# include <string.h>
+# include <stdio.h>
+/* This is a very incomplete test of the cord package.  It knows about	*/
+/* a few internals of the package (e.g. when C strings are returned)	*/
+/* that real clients shouldn't rely on.					*/
+
+# define ABORT(string) \
+{ int x = 0; fprintf(stderr, "FAILED: %s\n", string); x = 1 / x; abort(); }
+
+int count;
+
+int test_fn(char c, void * client_data)
+{
+    if (client_data != (void *)13) ABORT("bad client data");
+    if (count < 64*1024+1) {
+        if ((count & 1) == 0) {
+            if (c != 'b') ABORT("bad char");
+        } else {
+            if (c != 'a') ABORT("bad char");
+        }
+        count++;
+        return(0);
+    } else {
+        if (c != 'c') ABORT("bad char");
+        count++;
+        return(1);
+    }
+}
+
+char id_cord_fn(size_t i, void * client_data)
+{
+    return((char)i);
+}
+
+void test_basics()
+{
+    CORD x = CORD_from_char_star("ab");
+    register int i;
+    char c;
+    CORD y;
+    CORD_pos p;
+    
+    x = CORD_cat(x,x);
+    if (!CORD_IS_STRING(x)) ABORT("short cord should usually be a string");
+    if (strcmp(x, "abab") != 0) ABORT("bad CORD_cat result");
+    
+    for (i = 1; i < 16; i++) {
+        x = CORD_cat(x,x);
+    }
+    x = CORD_cat(x,"c");
+    if (CORD_len(x) != 128*1024+1) ABORT("bad length");
+    
+    count = 0;
+    if (CORD_iter5(x, 64*1024-1, test_fn, CORD_NO_FN, (void *)13) == 0) {
+        ABORT("CORD_iter5 failed");
+    }
+    if (count != 64*1024 + 2) ABORT("CORD_iter5 failed");
+    
+    count = 0;
+    CORD_set_pos(p, x, 64*1024-1);
+    while(CORD_pos_valid(p)) {
+       	(void) test_fn(CORD_pos_fetch(p), (void *)13);
+	CORD_next(p);
+    }
+    if (count != 64*1024 + 2) ABORT("Position based iteration failed");
+    
+    y = CORD_substr(x, 1023, 5);
+    if (!CORD_IS_STRING(y)) ABORT("short cord should usually be a string");
+    if (strcmp(y, "babab") != 0) ABORT("bad CORD_substr result");
+    
+    y = CORD_substr(x, 1024, 8);
+    if (!CORD_IS_STRING(y)) ABORT("short cord should usually be a string");
+    if (strcmp(y, "abababab") != 0) ABORT("bad CORD_substr result");
+    
+    y = CORD_substr(x, 128*1024-1, 8);
+    if (!CORD_IS_STRING(y)) ABORT("short cord should usually be a string");
+    if (strcmp(y, "bc") != 0) ABORT("bad CORD_substr result");
+    
+    x = CORD_balance(x);
+    if (CORD_len(x) != 128*1024+1) ABORT("bad length");
+    
+    count = 0;
+    if (CORD_iter5(x, 64*1024-1, test_fn, CORD_NO_FN, (void *)13) == 0) {
+        ABORT("CORD_iter5 failed");
+    }
+    if (count != 64*1024 + 2) ABORT("CORD_iter5 failed");
+    
+    y = CORD_substr(x, 1023, 5);
+    if (!CORD_IS_STRING(y)) ABORT("short cord should usually be a string");
+    if (strcmp(y, "babab") != 0) ABORT("bad CORD_substr result");
+    y = CORD_from_fn(id_cord_fn, 0, 13);
+    i = 0;
+    CORD_set_pos(p, y, i);
+    while(CORD_pos_valid(p)) {
+        c = CORD_pos_fetch(p);
+       	if(c != i) ABORT("Traversal of function node failed");
+	CORD_next(p); i++;
+    }
+    if (i != 13) ABORT("Bad apparent length for function node");
+}
+
+void test_extras()
+{
+#   if defined(__OS2__)
+#	define FNAME1 "tmp1"
+#	define FNAME2 "tmp2"
+#   elif defined(AMIGA)
+#	define FNAME1 "T:tmp1"
+#	define FNAME2 "T:tmp2"
+#   else
+#	define FNAME1 "/tmp/cord_test"
+#	define FNAME2 "/tmp/cord_test2"
+#   endif
+    register int i;
+    CORD y = "abcdefghijklmnopqrstuvwxyz0123456789";
+    CORD x = "{}";
+    CORD w, z;
+    FILE *f;
+    FILE *f1a, *f1b, *f2;
+    
+    w = CORD_cat(CORD_cat(y,y),y);
+    z = CORD_catn(3,y,y,y);
+    if (CORD_cmp(w,z) != 0) ABORT("CORD_catn comparison wrong");
+    for (i = 1; i < 100; i++) {
+        x = CORD_cat(x, y);
+    }
+    z = CORD_balance(x);
+    if (CORD_cmp(x,z) != 0) ABORT("balanced string comparison wrong");
+    if (CORD_cmp(x,CORD_cat(z, CORD_nul(13))) >= 0) ABORT("comparison 2");
+    if (CORD_cmp(CORD_cat(x, CORD_nul(13)), z) <= 0) ABORT("comparison 3");
+    if (CORD_cmp(x,CORD_cat(z, "13")) >= 0) ABORT("comparison 4");
+    if ((f = fopen(FNAME1, "w")) == 0) ABORT("open failed");
+    if (CORD_put(z,f) == EOF) ABORT("CORD_put failed");
+    if (fclose(f) == EOF) ABORT("fclose failed");
+    w = CORD_from_file(f1a = fopen(FNAME1, "rb"));
+    if (CORD_len(w) != CORD_len(z)) ABORT("file length wrong");
+    if (CORD_cmp(w,z) != 0) ABORT("file comparison wrong");
+    if (CORD_cmp(CORD_substr(w, 50*36+2, 36), y) != 0)
+    	ABORT("file substr wrong");
+    z = CORD_from_file_lazy(f1b = fopen(FNAME1, "rb"));
+    if (CORD_cmp(w,z) != 0) ABORT("File conversions differ");
+    if (CORD_chr(w, 0, '9') != 37) ABORT("CORD_chr failed 1");
+    if (CORD_chr(w, 3, 'a') != 38) ABORT("CORD_chr failed 2");
+    if (CORD_rchr(w, CORD_len(w) - 1, '}') != 1) ABORT("CORD_rchr failed");
+    x = y;
+    for (i = 1; i < 14; i++) {
+        x = CORD_cat(x,x);
+    }
+    if ((f = fopen(FNAME2, "w")) == 0) ABORT("2nd open failed");
+    if (CORD_put(x,f) == EOF) ABORT("CORD_put failed");
+    if (fclose(f) == EOF) ABORT("fclose failed");
+    w = CORD_from_file(f2 = fopen(FNAME2, "rb"));
+    if (CORD_len(w) != CORD_len(x)) ABORT("file length wrong");
+    if (CORD_cmp(w,x) != 0) ABORT("file comparison wrong");
+    if (CORD_cmp(CORD_substr(w, 1000*36, 36), y) != 0)
+    	ABORT("file substr wrong");
+    if (strcmp(CORD_to_char_star(CORD_substr(w, 1000*36, 36)), y) != 0)
+    	ABORT("char * file substr wrong");
+    if (strcmp(CORD_substr(w, 1000*36, 2), "ab") != 0)
+    	ABORT("short file substr wrong");
+    if (CORD_str(x,1,"9a") != 35) ABORT("CORD_str failed 1");
+    if (CORD_str(x,0,"9abcdefghijk") != 35) ABORT("CORD_str failed 2");
+    if (CORD_str(x,0,"9abcdefghijx") != CORD_NOT_FOUND)
+    	ABORT("CORD_str failed 3");
+    if (CORD_str(x,0,"9>") != CORD_NOT_FOUND) ABORT("CORD_str failed 4");
+    if (remove(FNAME1) != 0) {
+    	/* On some systems, e.g. OS2, this may fail if f1 is still open. */
+    	if ((fclose(f1a) == EOF) & (fclose(f1b) == EOF))
+    		ABORT("fclose(f1) failed");
+    	if (remove(FNAME1) != 0) ABORT("remove 1 failed");
+    }
+    if (remove(FNAME2) != 0) {
+    	if (fclose(f2) == EOF) ABORT("fclose(f2) failed");
+    	if (remove(FNAME2) != 0) ABORT("remove 2 failed");
+    }
+}
+
+void test_printf()
+{
+    CORD result;
+    char result2[200];
+    long l;
+    short s;
+    CORD x;
+    
+    if (CORD_sprintf(&result, "%7.2f%ln", 3.14159F, &l) != 7)
+    	ABORT("CORD_sprintf failed 1");
+    if (CORD_cmp(result, "   3.14") != 0)ABORT("CORD_sprintf goofed 1");
+    if (l != 7) ABORT("CORD_sprintf goofed 2");
+    if (CORD_sprintf(&result, "%-7.2s%hn%c%s", "abcd", &s, 'x', "yz") != 10)
+    	ABORT("CORD_sprintf failed 2");
+    if (CORD_cmp(result, "ab     xyz") != 0)ABORT("CORD_sprintf goofed 3");
+    if (s != 7) ABORT("CORD_sprintf goofed 4");
+    x = "abcdefghij";
+    x = CORD_cat(x,x);
+    x = CORD_cat(x,x);
+    x = CORD_cat(x,x);
+    if (CORD_sprintf(&result, "->%-120.78r!\n", x) != 124)
+    	ABORT("CORD_sprintf failed 3");
+    (void) sprintf(result2, "->%-120.78s!\n", CORD_to_char_star(x));
+    if (CORD_cmp(result, result2) != 0)ABORT("CORD_sprintf goofed 5");
+}
+
+main()
+{
+#   ifdef THINK_C
+        printf("cordtest:\n");
+#   endif
+    test_basics();
+    test_extras();
+    test_printf();
+    CORD_fprintf(stderr, "SUCCEEDED\n");
+    return(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/cord/cordxtra.c	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,621 @@
+/*
+ * Copyright (c) 1993-1994 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ * Author: Hans-J. Boehm (boehm@parc.xerox.com)
+ */
+/*
+ * These are functions on cords that do not need to understand their
+ * implementation.  They serve also serve as example client code for
+ * cord_basics.
+ */
+/* Boehm, December 8, 1995 1:53 pm PST */
+# include <stdio.h>
+# include <string.h>
+# include <stdlib.h>
+# include <stdarg.h>
+# include "cord.h"
+# include "ec.h"
+# define I_HIDE_POINTERS	/* So we get access to allocation lock.	*/
+				/* We use this for lazy file reading, 	*/
+				/* so that we remain independent 	*/
+				/* of the threads primitives.		*/
+# include "gc.h"
+
+/* For now we assume that pointer reads and writes are atomic, 	*/
+/* i.e. another thread always sees the state before or after	*/
+/* a write.  This might be false on a Motorola M68K with	*/
+/* pointers that are not 32-bit aligned.  But there probably	*/
+/* aren't too many threads packages running on those.		*/
+# define ATOMIC_WRITE(x,y) (x) = (y)
+# define ATOMIC_READ(x) (*(x))
+
+/* The standard says these are in stdio.h, but they aren't always: */
+# ifndef SEEK_SET
+#   define SEEK_SET 0
+# endif
+# ifndef SEEK_END
+#   define SEEK_END 2
+# endif
+
+# define BUFSZ 2048	/* Size of stack allocated buffers when		*/
+			/* we want large buffers.			*/
+
+typedef void (* oom_fn)(void);
+
+# define OUT_OF_MEMORY {  if (CORD_oom_fn != (oom_fn) 0) (*CORD_oom_fn)(); \
+			  ABORT("Out of memory\n"); }
+# define ABORT(msg) { fprintf(stderr, "%s\n", msg); abort(); }
+
+CORD CORD_cat_char(CORD x, char c)
+{
+    register char * string;
+    
+    if (c == '\0') return(CORD_cat(x, CORD_nul(1)));
+    string = GC_MALLOC_ATOMIC(2);
+    if (string == 0) OUT_OF_MEMORY;
+    string[0] = c;
+    string[1] = '\0';
+    return(CORD_cat_char_star(x, string, 1));
+}
+
+CORD CORD_catn(int nargs, ...)
+{
+    register CORD result = CORD_EMPTY;
+    va_list args;
+    register int i;
+
+    va_start(args, nargs);
+    for (i = 0; i < nargs; i++) {
+        register CORD next = va_arg(args, CORD);
+        result = CORD_cat(result, next);
+    }
+    va_end(args);
+    return(result);
+}
+
+typedef struct {
+	size_t len;
+	size_t count;
+	char * buf;
+} CORD_fill_data;
+
+int CORD_fill_proc(char c, void * client_data)
+{
+    register CORD_fill_data * d = (CORD_fill_data *)client_data;
+    register size_t count = d -> count;
+    
+    (d -> buf)[count] = c;
+    d -> count = ++count;
+    if (count >= d -> len) {
+    	return(1);
+    } else {
+    	return(0);
+    }
+}
+
+int CORD_batched_fill_proc(const char * s, void * client_data)
+{
+    register CORD_fill_data * d = (CORD_fill_data *)client_data;
+    register size_t count = d -> count;
+    register size_t max = d -> len;
+    register char * buf = d -> buf;
+    register const char * t = s;
+    
+    while((buf[count] = *t++) != '\0') {
+        count++;
+        if (count >= max) {
+            d -> count = count;
+            return(1);
+        }
+    }
+    d -> count = count;
+    return(0);
+}
+
+/* Fill buf with len characters starting at i.  			*/
+/* Assumes len characters are available.				*/ 
+void CORD_fill_buf(CORD x, size_t i, size_t len, char * buf)
+{
+    CORD_fill_data fd;
+    
+    fd.len = len;
+    fd.buf = buf;
+    fd.count = 0;
+    (void)CORD_iter5(x, i, CORD_fill_proc, CORD_batched_fill_proc, &fd);
+}
+
+int CORD_cmp(CORD x, CORD y)
+{
+    CORD_pos xpos;
+    CORD_pos ypos;
+    register size_t avail, yavail;
+    
+    if (y == CORD_EMPTY) return(x != CORD_EMPTY);
+    if (x == CORD_EMPTY) return(-1);
+    if (CORD_IS_STRING(y) && CORD_IS_STRING(x)) return(strcmp(x,y));
+    CORD_set_pos(xpos, x, 0);
+    CORD_set_pos(ypos, y, 0);
+    for(;;) {
+        if (!CORD_pos_valid(xpos)) {
+            if (CORD_pos_valid(ypos)) {
+            	return(-1);
+            } else {
+                return(0);
+            }
+        }
+        if (!CORD_pos_valid(ypos)) {
+            return(1);
+        }
+        if ((avail = CORD_pos_chars_left(xpos)) <= 0
+            || (yavail = CORD_pos_chars_left(ypos)) <= 0) {
+            register char xcurrent = CORD_pos_fetch(xpos);
+            register char ycurrent = CORD_pos_fetch(ypos);
+            if (xcurrent != ycurrent) return(xcurrent - ycurrent);
+            CORD_next(xpos);
+            CORD_next(ypos);
+        } else {
+            /* process as many characters as we can	*/
+            register int result;
+            
+            if (avail > yavail) avail = yavail;
+            result = strncmp(CORD_pos_cur_char_addr(xpos),
+            		     CORD_pos_cur_char_addr(ypos), avail);
+            if (result != 0) return(result);
+            CORD_pos_advance(xpos, avail);
+            CORD_pos_advance(ypos, avail);
+        }
+    }
+}
+
+int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start, size_t len)
+{
+    CORD_pos xpos;
+    CORD_pos ypos;
+    register size_t count;
+    register long avail, yavail;
+    
+    CORD_set_pos(xpos, x, x_start);
+    CORD_set_pos(ypos, y, y_start);
+    for(count = 0; count < len;) {
+        if (!CORD_pos_valid(xpos)) {
+            if (CORD_pos_valid(ypos)) {
+            	return(-1);
+            } else {
+                return(0);
+            }
+        }
+        if (!CORD_pos_valid(ypos)) {
+            return(1);
+        }
+        if ((avail = CORD_pos_chars_left(xpos)) <= 0
+            || (yavail = CORD_pos_chars_left(ypos)) <= 0) {
+            register char xcurrent = CORD_pos_fetch(xpos);
+            register char ycurrent = CORD_pos_fetch(ypos);
+            if (xcurrent != ycurrent) return(xcurrent - ycurrent);
+            CORD_next(xpos);
+            CORD_next(ypos);
+            count++;
+        } else {
+            /* process as many characters as we can	*/
+            register int result;
+            
+            if (avail > yavail) avail = yavail;
+            count += avail;
+            if (count > len) avail -= (count - len);
+            result = strncmp(CORD_pos_cur_char_addr(xpos),
+            		     CORD_pos_cur_char_addr(ypos), (size_t)avail);
+            if (result != 0) return(result);
+            CORD_pos_advance(xpos, (size_t)avail);
+            CORD_pos_advance(ypos, (size_t)avail);
+        }
+    }
+    return(0);
+}
+
+char * CORD_to_char_star(CORD x)
+{
+    register size_t len = CORD_len(x);
+    char * result = GC_MALLOC_ATOMIC(len + 1);
+    
+    if (result == 0) OUT_OF_MEMORY;
+    CORD_fill_buf(x, 0, len, result);
+    result[len] = '\0';
+    return(result);
+}
+
+CORD CORD_from_char_star(const char *s)
+{
+    char * result;
+    size_t len = strlen(s);
+
+    if (0 == len) return(CORD_EMPTY);
+    result = GC_MALLOC_ATOMIC(len + 1);
+    if (result == 0) OUT_OF_MEMORY;
+    memcpy(result, s, len+1);
+    return(result);
+}
+
+const char * CORD_to_const_char_star(CORD x)
+{
+    if (x == 0) return("");
+    if (CORD_IS_STRING(x)) return((const char *)x);
+    return(CORD_to_char_star(x));
+}
+
+char CORD_fetch(CORD x, size_t i)
+{
+    CORD_pos xpos;
+    
+    CORD_set_pos(xpos, x, i);
+    if (!CORD_pos_valid(xpos)) ABORT("bad index?");
+    return(CORD_pos_fetch(xpos));
+}
+
+
+int CORD_put_proc(char c, void * client_data)
+{
+    register FILE * f = (FILE *)client_data;
+    
+    return(putc(c, f) == EOF);
+}
+
+int CORD_batched_put_proc(const char * s, void * client_data)
+{
+    register FILE * f = (FILE *)client_data;
+    
+    return(fputs(s, f) == EOF);
+}
+    
+
+int CORD_put(CORD x, FILE * f)
+{
+    if (CORD_iter5(x, 0, CORD_put_proc, CORD_batched_put_proc, f)) {
+        return(EOF);
+    } else {
+    	return(1);
+    }
+}
+
+typedef struct {
+    size_t pos;		/* Current position in the cord */
+    char target;	/* Character we're looking for	*/
+} chr_data;
+
+int CORD_chr_proc(char c, void * client_data)
+{
+    register chr_data * d = (chr_data *)client_data;
+    
+    if (c == d -> target) return(1);
+    (d -> pos) ++;
+    return(0);
+}
+
+int CORD_rchr_proc(char c, void * client_data)
+{
+    register chr_data * d = (chr_data *)client_data;
+    
+    if (c == d -> target) return(1);
+    (d -> pos) --;
+    return(0);
+}
+
+int CORD_batched_chr_proc(const char *s, void * client_data)
+{
+    register chr_data * d = (chr_data *)client_data;
+    register char * occ = strchr(s, d -> target);
+    
+    if (occ == 0) {
+      	d -> pos += strlen(s);
+      	return(0);
+    } else {
+    	d -> pos += occ - s;
+    	return(1);
+    }
+}
+
+size_t CORD_chr(CORD x, size_t i, int c)
+{
+    chr_data d;
+    
+    d.pos = i;
+    d.target = c;
+    if (CORD_iter5(x, i, CORD_chr_proc, CORD_batched_chr_proc, &d)) {
+        return(d.pos);
+    } else {
+    	return(CORD_NOT_FOUND);
+    }
+}
+
+size_t CORD_rchr(CORD x, size_t i, int c)
+{
+    chr_data d;
+    
+    d.pos = i;
+    d.target = c;
+    if (CORD_riter4(x, i, CORD_rchr_proc, &d)) {
+        return(d.pos);
+    } else {
+    	return(CORD_NOT_FOUND);
+    }
+}
+
+/* Find the first occurrence of s in x at position start or later.	*/
+/* This uses an asymptotically poor algorithm, which should typically 	*/
+/* perform acceptably.  We compare the first few characters directly,	*/
+/* and call CORD_ncmp whenever there is a partial match.		*/
+/* This has the advantage that we allocate very little, or not at all.	*/
+/* It's very fast if there are few close misses.			*/
+size_t CORD_str(CORD x, size_t start, CORD s)
+{
+    CORD_pos xpos;
+    size_t xlen = CORD_len(x);
+    size_t slen;
+    register size_t start_len;
+    const char * s_start;
+    unsigned long s_buf = 0;	/* The first few characters of s	*/
+    unsigned long x_buf = 0;	/* Start of candidate substring.	*/
+    				/* Initialized only to make compilers	*/
+    				/* happy.				*/
+    unsigned long mask = 0;
+    register size_t i;
+    register size_t match_pos;
+    
+    if (s == CORD_EMPTY) return(start);
+    if (CORD_IS_STRING(s)) {
+        s_start = s;
+        slen = strlen(s);
+    } else {
+        s_start = CORD_to_char_star(CORD_substr(s, 0, sizeof(unsigned long)));
+        slen = CORD_len(s);
+    }
+    if (xlen < start || xlen - start < slen) return(CORD_NOT_FOUND);
+    start_len = slen;
+    if (start_len > sizeof(unsigned long)) start_len = sizeof(unsigned long);
+    CORD_set_pos(xpos, x, start);
+    for (i = 0; i < start_len; i++) {
+        mask <<= 8;
+        mask |= 0xff;
+        s_buf <<= 8;
+        s_buf |= s_start[i];
+        x_buf <<= 8;
+        x_buf |= CORD_pos_fetch(xpos);
+        CORD_next(xpos);
+    }
+    for (match_pos = start; ; match_pos++) {
+    	if ((x_buf & mask) == s_buf) {
+    	    if (slen == start_len ||
+    	     	CORD_ncmp(x, match_pos + start_len,
+    	     	 	  s, start_len, slen - start_len) == 0) {
+    	        return(match_pos);
+    	    }
+    	}
+	if ( match_pos == xlen - slen ) {
+	    return(CORD_NOT_FOUND);
+	}
+    	x_buf <<= 8;
+        x_buf |= CORD_pos_fetch(xpos);
+        CORD_next(xpos);
+    }
+}
+
+void CORD_ec_flush_buf(CORD_ec x)
+{
+    register size_t len = x[0].ec_bufptr - x[0].ec_buf;
+    char * s;
+
+    if (len == 0) return;
+    s = GC_MALLOC_ATOMIC(len+1);
+    memcpy(s, x[0].ec_buf, len);
+    s[len] = '\0';
+    x[0].ec_cord = CORD_cat_char_star(x[0].ec_cord, s, len);
+    x[0].ec_bufptr = x[0].ec_buf;
+}
+
+void CORD_ec_append_cord(CORD_ec x, CORD s)
+{
+    CORD_ec_flush_buf(x);
+    x[0].ec_cord = CORD_cat(x[0].ec_cord, s);
+}
+
+/*ARGSUSED*/
+char CORD_nul_func(size_t i, void * client_data)
+{
+    return((char)(unsigned long)client_data);
+}
+
+
+CORD CORD_chars(char c, size_t i)
+{
+    return(CORD_from_fn(CORD_nul_func, (void *)(unsigned long)c, i));
+}
+
+CORD CORD_from_file_eager(FILE * f)
+{
+    register int c;
+    CORD_ec ecord;
+    
+    CORD_ec_init(ecord);
+    for(;;) {
+        c = getc(f);
+        if (c == 0) {
+          /* Append the right number of NULs	*/
+          /* Note that any string of NULs is rpresented in 4 words,	*/
+          /* independent of its length.					*/
+            register size_t count = 1;
+            
+            CORD_ec_flush_buf(ecord);
+            while ((c = getc(f)) == 0) count++;
+            ecord[0].ec_cord = CORD_cat(ecord[0].ec_cord, CORD_nul(count));
+        }
+        if (c == EOF) break;
+        CORD_ec_append(ecord, c);
+    }
+    (void) fclose(f);
+    return(CORD_balance(CORD_ec_to_cord(ecord)));
+}
+
+/* The state maintained for a lazily read file consists primarily	*/
+/* of a large direct-mapped cache of previously read values.		*/
+/* We could rely more on stdio buffering.  That would have 2		*/
+/* disadvantages:							*/
+/*  	1) Empirically, not all fseek implementations preserve the	*/
+/*	   buffer whenever they could.					*/
+/*	2) It would fail if 2 different sections of a long cord		*/
+/*	   were being read alternately.					*/
+/* We do use the stdio buffer for read ahead.				*/
+/* To guarantee thread safety in the presence of atomic pointer		*/
+/* writes, cache lines are always replaced, and never modified in	*/
+/* place.								*/
+
+# define LOG_CACHE_SZ 14
+# define CACHE_SZ (1 << LOG_CACHE_SZ)
+# define LOG_LINE_SZ 9
+# define LINE_SZ (1 << LOG_LINE_SZ)
+
+typedef struct {
+    size_t tag;
+    char data[LINE_SZ];
+    	/* data[i%LINE_SZ] = ith char in file if tag = i/LINE_SZ	*/
+} cache_line;
+
+typedef struct {
+    FILE * lf_file;
+    size_t lf_current;	/* Current file pointer value */
+    cache_line * volatile lf_cache[CACHE_SZ/LINE_SZ];
+} lf_state;
+
+# define MOD_CACHE_SZ(n) ((n) & (CACHE_SZ - 1))
+# define DIV_CACHE_SZ(n) ((n) >> LOG_CACHE_SZ)
+# define MOD_LINE_SZ(n) ((n) & (LINE_SZ - 1))
+# define DIV_LINE_SZ(n) ((n) >> LOG_LINE_SZ)
+# define LINE_START(n) ((n) & ~(LINE_SZ - 1))
+
+typedef struct {
+    lf_state * state;
+    size_t file_pos;	/* Position of needed character. */
+    cache_line * new_cache;
+} refill_data;
+
+/* Executed with allocation lock. */
+static char refill_cache(client_data)
+refill_data * client_data;
+{
+    register lf_state * state = client_data -> state;
+    register size_t file_pos = client_data -> file_pos;
+    FILE *f = state -> lf_file;
+    size_t line_start = LINE_START(file_pos);
+    size_t line_no = DIV_LINE_SZ(MOD_CACHE_SZ(file_pos));
+    cache_line * new_cache = client_data -> new_cache;
+    
+    if (line_start != state -> lf_current
+        && fseek(f, line_start, SEEK_SET) != 0) {
+    	    ABORT("fseek failed");
+    }
+    if (fread(new_cache -> data, sizeof(char), LINE_SZ, f)
+    	<= file_pos - line_start) {
+    	ABORT("fread failed");
+    }
+    new_cache -> tag = DIV_LINE_SZ(file_pos);
+    /* Store barrier goes here. */
+    ATOMIC_WRITE(state -> lf_cache[line_no], new_cache);
+    state -> lf_current = line_start + LINE_SZ;
+    return(new_cache->data[MOD_LINE_SZ(file_pos)]);
+}
+
+char CORD_lf_func(size_t i, void * client_data)
+{
+    register lf_state * state = (lf_state *)client_data;
+    register cache_line * volatile * cl_addr =
+		&(state -> lf_cache[DIV_LINE_SZ(MOD_CACHE_SZ(i))]);
+    register cache_line * cl = (cache_line *)ATOMIC_READ(cl_addr);
+    
+    if (cl == 0 || cl -> tag != DIV_LINE_SZ(i)) {
+    	/* Cache miss */
+    	refill_data rd;
+    	
+        rd.state = state;
+        rd.file_pos =  i;
+        rd.new_cache = GC_NEW_ATOMIC(cache_line);
+        if (rd.new_cache == 0) OUT_OF_MEMORY;
+        return((char)(GC_word)
+        	  GC_call_with_alloc_lock((GC_fn_type) refill_cache, &rd));
+    }
+    return(cl -> data[MOD_LINE_SZ(i)]);
+}    
+
+/*ARGSUSED*/
+void CORD_lf_close_proc(void * obj, void * client_data)  
+{
+    if (fclose(((lf_state *)obj) -> lf_file) != 0) {
+    	ABORT("CORD_lf_close_proc: fclose failed");
+    }
+}			
+
+CORD CORD_from_file_lazy_inner(FILE * f, size_t len)
+{
+    register lf_state * state = GC_NEW(lf_state);
+    register int i;
+    
+    if (state == 0) OUT_OF_MEMORY;
+    if (len != 0) {
+	/* Dummy read to force buffer allocation.  	*/
+	/* This greatly increases the probability	*/
+	/* of avoiding deadlock if buffer allocation	*/
+	/* is redirected to GC_malloc and the		*/
+	/* world is multithreaded.			*/
+	char buf[1];
+
+	(void) fread(buf, 1, 1, f); 
+	rewind(f);
+    }
+    state -> lf_file = f;
+    for (i = 0; i < CACHE_SZ/LINE_SZ; i++) {
+        state -> lf_cache[i] = 0;
+    }
+    state -> lf_current = 0;
+    GC_REGISTER_FINALIZER(state, CORD_lf_close_proc, 0, 0, 0);
+    return(CORD_from_fn(CORD_lf_func, state, len));
+}
+
+CORD CORD_from_file_lazy(FILE * f)
+{
+    register long len;
+    
+    if (fseek(f, 0l, SEEK_END) != 0) {
+        ABORT("Bad fd argument - fseek failed");
+    }
+    if ((len = ftell(f)) < 0) {
+        ABORT("Bad fd argument - ftell failed");
+    }
+    rewind(f);
+    return(CORD_from_file_lazy_inner(f, (size_t)len));
+}
+
+# define LAZY_THRESHOLD (128*1024 + 1)
+
+CORD CORD_from_file(FILE * f)
+{
+    register long len;
+    
+    if (fseek(f, 0l, SEEK_END) != 0) {
+        ABORT("Bad fd argument - fseek failed");
+    }
+    if ((len = ftell(f)) < 0) {
+        ABORT("Bad fd argument - ftell failed");
+    }
+    rewind(f);
+    if (len < LAZY_THRESHOLD) {
+        return(CORD_from_file_eager(f));
+    } else {
+        return(CORD_from_file_lazy_inner(f, (size_t)len));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/cord/de.c	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,603 @@
+/*
+ * Copyright (c) 1993-1994 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ * Author: Hans-J. Boehm (boehm@parc.xerox.com)
+ */
+/*
+ * A really simple-minded text editor based on cords.
+ * Things it does right:
+ * 	No size bounds.
+ *	Inbounded undo.
+ *	Shouldn't crash no matter what file you invoke it on (e.g. /vmunix)
+ *		(Make sure /vmunix is not writable before you try this.)
+ *	Scrolls horizontally.
+ * Things it does wrong:
+ *	It doesn't handle tabs reasonably (use "expand" first).
+ *	The command set is MUCH too small.
+ *	The redisplay algorithm doesn't let curses do the scrolling.
+ *	The rule for moving the window over the file is suboptimal.
+ */
+/* Boehm, February 6, 1995 12:27 pm PST */
+
+/* Boehm, May 19, 1994 2:20 pm PDT */
+#include <stdio.h>
+#include "gc.h"
+#include "cord.h"
+
+#ifdef THINK_C
+#define MACINTOSH
+#include <ctype.h>
+#endif
+
+#if defined(__BORLANDC__) && !defined(WIN32)
+    /* If this is DOS or win16, we'll fail anyway.	*/
+    /* Might as well assume win32.			*/
+#   define WIN32
+#endif
+
+#if defined(WIN32)
+#  include <windows.h>
+#  include "de_win.h"
+#elif defined(MACINTOSH)
+#	include <console.h>
+/* curses emulation. */
+#	define initscr()
+#	define endwin()
+#	define nonl()
+#	define noecho() csetmode(C_NOECHO, stdout)
+#	define cbreak() csetmode(C_CBREAK, stdout)
+#	define refresh()
+#	define addch(c) putchar(c)
+#	define standout() cinverse(1, stdout)
+#	define standend() cinverse(0, stdout)
+#	define move(line,col) cgotoxy(col + 1, line + 1, stdout)
+#	define clrtoeol() ccleol(stdout)
+#	define de_error(s) { fprintf(stderr, s); getchar(); }
+#	define LINES 25
+#	define COLS 80
+#else
+#  include <curses.h>
+#  define de_error(s) { fprintf(stderr, s); sleep(2); }
+#endif
+#include "de_cmds.h"
+
+/* List of line number to position mappings, in descending order. */
+/* There may be holes.						  */
+typedef struct LineMapRep {
+    int line;
+    size_t pos;
+    struct LineMapRep * previous;
+} * line_map;
+
+/* List of file versions, one per edit operation */
+typedef struct HistoryRep {
+    CORD file_contents;
+    struct HistoryRep * previous;
+    line_map map;	/* Invalid for first record "now" */
+} * history;
+
+history now = 0;
+CORD current;		/* == now -> file_contents.	*/
+size_t current_len;	/* Current file length.		*/
+line_map current_map = 0;	/* Current line no. to pos. map	 */
+size_t current_map_size = 0;	/* Number of current_map entries.	*/
+				/* Not always accurate, but reset	*/
+				/* by prune_map.			*/
+# define MAX_MAP_SIZE 3000
+
+/* Current display position */
+int dis_line = 0;
+int dis_col = 0;
+
+# define ALL -1
+# define NONE - 2
+int need_redisplay = 0;	/* Line that needs to be redisplayed.	*/
+
+
+/* Current cursor position. Always within file. */
+int line = 0; 
+int col = 0;
+size_t file_pos = 0;	/* Character position corresponding to cursor.	*/
+
+/* Invalidate line map for lines > i */
+void invalidate_map(int i)
+{
+    while(current_map -> line > i) {
+        current_map = current_map -> previous;
+        current_map_size--;
+    }
+}
+
+/* Reduce the number of map entries to save space for huge files. */
+/* This also affects maps in histories.				  */
+void prune_map()
+{
+    line_map map = current_map;
+    int start_line = map -> line;
+    
+    current_map_size = 0;
+    for(; map != 0; map = map -> previous) {
+    	current_map_size++;
+    	if (map -> line < start_line - LINES && map -> previous != 0) {
+    	    map -> previous = map -> previous -> previous;
+    	}
+    }
+}
+/* Add mapping entry */
+void add_map(int line, size_t pos)
+{
+    line_map new_map = GC_NEW(struct LineMapRep);
+    
+    if (current_map_size >= MAX_MAP_SIZE) prune_map();
+    new_map -> line = line;
+    new_map -> pos = pos;
+    new_map -> previous = current_map;
+    current_map = new_map;
+    current_map_size++;
+}
+
+
+
+/* Return position of column *c of ith line in   */
+/* current file. Adjust *c to be within the line.*/
+/* A 0 pointer is taken as 0 column.		 */
+/* Returns CORD_NOT_FOUND if i is too big.	 */
+/* Assumes i > dis_line.			 */
+size_t line_pos(int i, int *c)
+{
+    int j;
+    size_t cur;
+    size_t next;
+    line_map map = current_map;
+    
+    while (map -> line > i) map = map -> previous;
+    if (map -> line < i - 2) /* rebuild */ invalidate_map(i);
+    for (j = map -> line, cur = map -> pos; j < i;) {
+	cur = CORD_chr(current, cur, '\n');
+        if (cur == current_len-1) return(CORD_NOT_FOUND);
+        cur++;
+        if (++j > current_map -> line) add_map(j, cur);
+    }
+    if (c != 0) {
+        next = CORD_chr(current, cur, '\n');
+        if (next == CORD_NOT_FOUND) next = current_len - 1;
+        if (next < cur + *c) {
+            *c = next - cur;
+        }
+        cur += *c;
+    }
+    return(cur);
+}
+
+void add_hist(CORD s)
+{
+    history new_file = GC_NEW(struct HistoryRep);
+    
+    new_file -> file_contents = current = s;
+    current_len = CORD_len(s);
+    new_file -> previous = now;
+    if (now != 0) now -> map = current_map;
+    now = new_file;
+}
+
+void del_hist(void)
+{
+    now = now -> previous;
+    current = now -> file_contents;
+    current_map = now -> map;
+    current_len = CORD_len(current);
+}
+
+/* Current screen_contents; a dynamically allocated array of CORDs	*/
+CORD * screen = 0;
+int screen_size = 0;
+
+# ifndef WIN32
+/* Replace a line in the curses stdscr.	All control characters are	*/
+/* displayed as upper case characters in standout mode.  This isn't	*/
+/* terribly appropriate for tabs.									*/
+void replace_line(int i, CORD s)
+{
+    register int c;
+    CORD_pos p;
+    size_t len = CORD_len(s);
+    
+    if (screen == 0 || LINES > screen_size) {
+        screen_size = LINES;
+    	screen = (CORD *)GC_MALLOC(screen_size * sizeof(CORD));
+    }
+#   if !defined(MACINTOSH)
+        /* A gross workaround for an apparent curses bug: */
+        if (i == LINES-1 && len == COLS) {
+            s = CORD_substr(s, 0, CORD_len(s) - 1);
+        }
+#   endif
+    if (CORD_cmp(screen[i], s) != 0) {
+        move(i, 0); clrtoeol(); move(i,0);
+
+        CORD_FOR (p, s) {
+            c = CORD_pos_fetch(p) & 0x7f;
+            if (iscntrl(c)) {
+            	standout(); addch(c + 0x40); standend();
+            } else {
+    	        addch(c);
+    	    }
+    	}
+    	screen[i] = s;
+    }
+}
+#else
+# define replace_line(i,s) invalidate_line(i)
+#endif
+
+/* Return up to COLS characters of the line of s starting at pos,	*/
+/* returning only characters after the given column.			*/
+CORD retrieve_line(CORD s, size_t pos, unsigned column)
+{
+    CORD candidate = CORD_substr(s, pos, column + COLS);
+    			/* avoids scanning very long lines	*/
+    int eol = CORD_chr(candidate, 0, '\n');
+    int len;
+    
+    if (eol == CORD_NOT_FOUND) eol = CORD_len(candidate);
+    len = (int)eol - (int)column;
+    if (len < 0) len = 0;
+    return(CORD_substr(s, pos + column, len));
+}
+
+# ifdef WIN32
+#   define refresh();
+
+    CORD retrieve_screen_line(int i)
+    {
+    	register size_t pos;
+    	
+    	invalidate_map(dis_line + LINES);	/* Prune search */
+    	pos = line_pos(dis_line + i, 0);
+    	if (pos == CORD_NOT_FOUND) return(CORD_EMPTY);
+    	return(retrieve_line(current, pos, dis_col));
+    }
+# endif
+
+/* Display the visible section of the current file	 */
+void redisplay(void)
+{
+    register int i;
+    
+    invalidate_map(dis_line + LINES);	/* Prune search */
+    for (i = 0; i < LINES; i++) {
+        if (need_redisplay == ALL || need_redisplay == i) {
+            register size_t pos = line_pos(dis_line + i, 0);
+            
+            if (pos == CORD_NOT_FOUND) break;
+            replace_line(i, retrieve_line(current, pos, dis_col));
+            if (need_redisplay == i) goto done;
+        }
+    }
+    for (; i < LINES; i++) replace_line(i, CORD_EMPTY);
+done:
+    refresh();
+    need_redisplay = NONE;
+}
+
+int dis_granularity;
+
+/* Update dis_line, dis_col, and dis_pos to make cursor visible.	*/
+/* Assumes line, col, dis_line, dis_pos are in bounds.			*/
+void normalize_display()
+{
+    int old_line = dis_line;
+    int old_col = dis_col;
+    
+    dis_granularity = 1;
+    if (LINES > 15 && COLS > 15) dis_granularity = 2;
+    while (dis_line > line) dis_line -= dis_granularity;
+    while (dis_col > col) dis_col -= dis_granularity;
+    while (line >= dis_line + LINES) dis_line += dis_granularity;
+    while (col >= dis_col + COLS) dis_col += dis_granularity;
+    if (old_line != dis_line || old_col != dis_col) {
+        need_redisplay = ALL;
+    }
+}
+
+# if defined(WIN32)
+# elif defined(MACINTOSH)
+#		define move_cursor(x,y) cgotoxy(x + 1, y + 1, stdout)
+# else
+#		define move_cursor(x,y) move(y,x)
+# endif
+
+/* Adjust display so that cursor is visible; move cursor into position	*/
+/* Update screen if necessary.						*/
+void fix_cursor(void)
+{
+    normalize_display();
+    if (need_redisplay != NONE) redisplay();
+    move_cursor(col - dis_col, line - dis_line);
+    refresh();
+#   ifndef WIN32
+      fflush(stdout);
+#   endif
+}
+
+/* Make sure line, col, and dis_pos are somewhere inside file.	*/
+/* Recompute file_pos.	Assumes dis_pos is accurate or past eof	*/
+void fix_pos()
+{
+    int my_col = col;
+    
+    if ((size_t)line > current_len) line = current_len;
+    file_pos = line_pos(line, &my_col);
+    if (file_pos == CORD_NOT_FOUND) {
+        for (line = current_map -> line, file_pos = current_map -> pos;
+             file_pos < current_len;
+             line++, file_pos = CORD_chr(current, file_pos, '\n') + 1);
+    	line--;
+        file_pos = line_pos(line, &col);
+    } else {
+    	col = my_col;
+    }
+}
+
+#if defined(WIN32)
+#  define beep() Beep(1000 /* Hz */, 300 /* msecs */) 
+#elif defined(MACINTOSH)
+#	define beep() SysBeep(1)
+#else
+/*
+ * beep() is part of some curses packages and not others.
+ * We try to match the type of the builtin one, if any.
+ */
+#ifdef __STDC__
+    int beep(void)
+#else
+    int beep()
+#endif
+{
+    putc('\007', stderr);
+    return(0);
+}
+#endif
+
+#   define NO_PREFIX -1
+#   define BARE_PREFIX -2
+int repeat_count = NO_PREFIX;	/* Current command prefix. */
+
+int locate_mode = 0;			/* Currently between 2 ^Ls	*/
+CORD locate_string = CORD_EMPTY;	/* Current search string.	*/
+
+char * arg_file_name;
+
+#ifdef WIN32
+/* Change the current position to whatever is currently displayed at	*/
+/* the given SCREEN coordinates.					*/
+void set_position(int c, int l)
+{
+    line = l + dis_line;
+    col = c + dis_col;
+    fix_pos();
+    move_cursor(col - dis_col, line - dis_line);
+}
+#endif /* WIN32 */
+
+/* Perform the command associated with character c.  C may be an	*/
+/* integer > 256 denoting a windows command, one of the above control	*/
+/* characters, or another ASCII character to be used as either a 	*/
+/* character to be inserted, a repeat count, or a search string, 	*/
+/* depending on the current state.					*/
+void do_command(int c)
+{
+    int i;
+    int need_fix_pos;
+    FILE * out;
+    
+    if ( c == '\r') c = '\n';
+    if (locate_mode) {
+        size_t new_pos;
+          
+        if (c == LOCATE) {
+              locate_mode = 0;
+              locate_string = CORD_EMPTY;
+              return;
+        }
+        locate_string = CORD_cat_char(locate_string, (char)c);
+        new_pos = CORD_str(current, file_pos - CORD_len(locate_string) + 1,
+          		   locate_string);
+        if (new_pos != CORD_NOT_FOUND) {
+            need_redisplay = ALL;
+            new_pos += CORD_len(locate_string);
+            for (;;) {
+              	file_pos = line_pos(line + 1, 0);
+              	if (file_pos > new_pos) break;
+              	line++;
+            }
+            col = new_pos - line_pos(line, 0);
+            file_pos = new_pos;
+            fix_cursor();
+        } else {
+            locate_string = CORD_substr(locate_string, 0,
+              				CORD_len(locate_string) - 1);
+            beep();
+        }
+        return;
+    }
+    if (c == REPEAT) {
+      	repeat_count = BARE_PREFIX; return;
+    } else if (c < 0x100 && isdigit(c)){
+        if (repeat_count == BARE_PREFIX) {
+          repeat_count = c - '0'; return;
+        } else if (repeat_count != NO_PREFIX) {
+          repeat_count = 10 * repeat_count + c - '0'; return;
+        }
+    }
+    if (repeat_count == NO_PREFIX) repeat_count = 1;
+    if (repeat_count == BARE_PREFIX && (c == UP || c == DOWN)) {
+      	repeat_count = LINES - dis_granularity;
+    }
+    if (repeat_count == BARE_PREFIX) repeat_count = 8;
+    need_fix_pos = 0;
+    for (i = 0; i < repeat_count; i++) {
+        switch(c) {
+          case LOCATE:
+            locate_mode = 1;
+            break;
+          case TOP:
+            line = col = file_pos = 0;
+            break;
+     	  case UP:
+     	    if (line != 0) {
+     	        line--;
+     	        need_fix_pos = 1;
+     	    }
+     	    break;
+     	  case DOWN:
+     	    line++;
+     	    need_fix_pos = 1;
+     	    break;
+     	  case LEFT:
+     	    if (col != 0) {
+     	        col--; file_pos--;
+     	    }
+     	    break;
+     	  case RIGHT:
+     	    if (CORD_fetch(current, file_pos) == '\n') break;
+     	    col++; file_pos++;
+     	    break;
+     	  case UNDO:
+     	    del_hist();
+     	    need_redisplay = ALL; need_fix_pos = 1;
+     	    break;
+     	  case BS:
+     	    if (col == 0) {
+     	        beep();
+     	        break;
+     	    }
+     	    col--; file_pos--;
+     	    /* fall through: */
+     	  case DEL:
+     	    if (file_pos == current_len-1) break;
+     	    	/* Can't delete trailing newline */
+     	    if (CORD_fetch(current, file_pos) == '\n') {
+     	        need_redisplay = ALL; need_fix_pos = 1;
+     	    } else {
+     	        need_redisplay = line - dis_line;
+     	    }
+     	    add_hist(CORD_cat(
+     	    		CORD_substr(current, 0, file_pos),
+     	    		CORD_substr(current, file_pos+1, current_len)));
+     	    invalidate_map(line);
+     	    break;
+     	  case WRITE:
+	    {
+  		CORD name = CORD_cat(CORD_from_char_star(arg_file_name),
+				     ".new");
+
+    	        if ((out = fopen(CORD_to_const_char_star(name), "wb")) == NULL
+  	            || CORD_put(current, out) == EOF) {
+        	    de_error("Write failed\n");
+        	    need_redisplay = ALL;
+                } else {
+                    fclose(out);
+                }
+	    }
+            break;
+     	  default:
+     	    {
+     	        CORD left_part = CORD_substr(current, 0, file_pos);
+     	        CORD right_part = CORD_substr(current, file_pos, current_len);
+     	        
+     	        add_hist(CORD_cat(CORD_cat_char(left_part, (char)c),
+     	        		  right_part));
+     	        invalidate_map(line);
+     	        if (c == '\n') {
+     	            col = 0; line++; file_pos++;
+     	            need_redisplay = ALL;
+     	        } else {
+     	            col++; file_pos++;
+     	            need_redisplay = line - dis_line;
+     	    	}
+     	        break;
+     	    }
+        }
+    }
+    if (need_fix_pos) fix_pos();
+    fix_cursor();
+    repeat_count = NO_PREFIX;
+}
+
+/* OS independent initialization */
+
+void generic_init(void)
+{
+    FILE * f;
+    CORD initial;
+    
+    if ((f = fopen(arg_file_name, "rb")) == NULL) {
+     	initial = "\n";
+    } else {
+        initial = CORD_from_file(f);
+        if (initial == CORD_EMPTY
+            || CORD_fetch(initial, CORD_len(initial)-1) != '\n') {
+            initial = CORD_cat(initial, "\n");
+        }
+    }
+    add_map(0,0);
+    add_hist(initial);
+    now -> map = current_map;
+    now -> previous = now;  /* Can't back up further: beginning of the world */
+    need_redisplay = ALL;
+    fix_cursor();
+}
+
+#ifndef WIN32
+
+main(argc, argv)
+int argc;
+char ** argv;
+{
+    int c;
+
+#if defined(MACINTOSH)
+	console_options.title = "\pDumb Editor";
+	cshow(stdout);
+	GC_init();
+	argc = ccommand(&argv);
+#endif
+    
+    if (argc != 2) goto usage;
+    arg_file_name = argv[1];
+    setvbuf(stdout, GC_MALLOC_ATOMIC(8192), _IOFBF, 8192);
+    initscr();
+    noecho(); nonl(); cbreak();
+    generic_init();
+    while ((c = getchar()) != QUIT) {
+		if (c == EOF) break;
+	    do_command(c);
+    }
+done:
+    move(LINES-1, 0);
+    clrtoeol();
+    refresh();
+    nl();
+    echo();
+    endwin();
+    exit(0);
+usage:
+    fprintf(stderr, "Usage: %s file\n", argv[0]);
+    fprintf(stderr, "Cursor keys: ^B(left) ^F(right) ^P(up) ^N(down)\n");
+    fprintf(stderr, "Undo: ^U    Write to <file>.new: ^W");
+    fprintf(stderr, "Quit:^D  Repeat count: ^R[n]\n");
+    fprintf(stderr, "Top: ^T   Locate (search, find): ^L text ^L\n");
+    exit(1);
+}
+
+#endif  /* !WIN32 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/cord/de_cmds.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 1994 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+/* Boehm, May 19, 1994 2:24 pm PDT */
+
+#ifndef DE_CMDS_H
+
+# define DE_CMDS_H
+
+# define UP     16	/* ^P */
+# define DOWN   14	/* ^N */
+# define LEFT   2	/* ^B */
+# define RIGHT  6	/* ^F */
+# define DEL	127	/* ^? */
+# define BS     8	/* ^H */
+# define UNDO   21	/* ^U */
+# define WRITE  23	/* ^W */
+# define QUIT   4	/* ^D */
+# define REPEAT 18	/* ^R */
+# define LOCATE 12	/* ^L */
+# define TOP    20	/* ^T */
+
+#endif
+
Binary file libgc/cord/de_win.ICO has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/cord/de_win.RC	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to copy this garbage collector for any purpose,
+ * provided the above notices are retained on all copies.
+ */
+/* Boehm, May 13, 1994 9:50 am PDT */
+
+#include "windows.h"
+#include "de_cmds.h"
+#include "de_win.h"
+
+
+
+ABOUTBOX DIALOG 19, 21, 163, 47
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "About Demonstration Text Editor"
+BEGIN
+	ICON "DE", -1, 8, 8, 13, 13, WS_CHILD | WS_VISIBLE
+	LTEXT "Demonstration Text Editor", -1, 44, 8, 118, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
+	LTEXT "Version 4.1", -1, 44, 16, 60, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
+	PUSHBUTTON "OK", IDOK, 118, 27, 24, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+END
+
+
+DE MENU 
+BEGIN
+	POPUP "&File"
+	BEGIN
+		MENUITEM "&Save\t^W", IDM_FILESAVE
+		MENUITEM "E&xit\t^D", IDM_FILEEXIT
+	END
+
+	POPUP "&Edit"
+	BEGIN
+	    MENUITEM "Page &Down\t^R^N", IDM_EDITPDOWN
+	    MENUITEM "Page &Up\t^R^P", IDM_EDITPUP
+		MENUITEM "U&ndo\t^U", IDM_EDITUNDO
+		MENUITEM "&Locate\t^L ... ^L", IDM_EDITLOCATE
+		MENUITEM "D&own\t^N", IDM_EDITDOWN
+	    MENUITEM "U&p\t^P", IDM_EDITUP
+	    MENUITEM "Le&ft\t^B", IDM_EDITLEFT
+	    MENUITEM "&Right\t^F", IDM_EDITRIGHT
+	    MENUITEM "Delete &Backward\tBS", IDM_EDITBS
+	    MENUITEM "Delete F&orward\tDEL", IDM_EDITDEL
+	    MENUITEM "&Top\t^T", IDM_EDITTOP
+	END
+	
+	POPUP "&Help"
+	BEGIN
+		MENUITEM "&Contents", IDM_HELPCONTENTS
+		MENUITEM "&About...", IDM_HELPABOUT
+	END
+	
+	MENUITEM "Page_&Down", IDM_EDITPDOWN
+	MENUITEM "Page_&Up", IDM_EDITPUP
+END
+
+
+DE ACCELERATORS 
+BEGIN
+    "^R", IDM_EDITREPEAT
+    "^N", IDM_EDITDOWN
+    "^P", IDM_EDITUP
+    "^L", IDM_EDITLOCATE
+    "^B", IDM_EDITLEFT
+    "^F", IDM_EDITRIGHT
+    "^T", IDM_EDITTOP
+	VK_DELETE, IDM_EDITDEL, VIRTKEY
+	VK_BACK, IDM_EDITBS, VIRTKEY
+END
+
+
+DE ICON cord\de_win.ICO
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/cord/de_win.c	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 1994 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+/* Boehm, February 6, 1995 12:29 pm PST */
+
+/*
+ * The MS Windows specific part of de.  
+ * This started as the generic Windows application template
+ * made available by Rob Haack (rhaack@polaris.unm.edu), but
+ * significant parts didn't survive to the final version.
+ *
+ * This was written by a nonexpert windows programmer.
+ */
+
+
+#include "windows.h"
+#include "gc.h"
+#include "cord.h"
+#include "de_cmds.h"
+#include "de_win.h"
+
+int LINES = 0;
+int COLS = 0;
+
+char       szAppName[]     = "DE";
+char       FullAppName[]   = "Demonstration Editor";
+
+HWND        hwnd;
+
+void de_error(char *s)
+{
+    MessageBox( hwnd, (LPSTR) s,
+                (LPSTR) FullAppName,
+                MB_ICONINFORMATION | MB_OK );
+    InvalidateRect(hwnd, NULL, TRUE);
+}
+
+int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
+                      LPSTR command_line, int nCmdShow)
+{
+   MSG         msg;
+   WNDCLASS    wndclass;
+   HANDLE      hAccel;
+
+   if (!hPrevInstance)
+   {
+      wndclass.style          = CS_HREDRAW | CS_VREDRAW;
+      wndclass.lpfnWndProc    = WndProc;
+      wndclass.cbClsExtra     = 0;
+      wndclass.cbWndExtra     = DLGWINDOWEXTRA;
+      wndclass.hInstance      = hInstance;
+      wndclass.hIcon          = LoadIcon (hInstance, szAppName);
+      wndclass.hCursor        = LoadCursor (NULL, IDC_ARROW);
+      wndclass.hbrBackground  = GetStockObject(WHITE_BRUSH);
+      wndclass.lpszMenuName   = "DE";
+      wndclass.lpszClassName  = szAppName;
+
+      if (RegisterClass (&wndclass) == 0) {
+          char buf[50];
+   	
+   	  sprintf(buf, "RegisterClass: error code: 0x%X", GetLastError());
+   	  de_error(buf);
+   	  return(0);
+      }
+   }
+   
+   /* Empirically, the command line does not include the command name ...
+   if (command_line != 0) {
+       while (isspace(*command_line)) command_line++;
+       while (*command_line != 0 && !isspace(*command_line)) command_line++;
+       while (isspace(*command_line)) command_line++;
+   } */
+   
+   if (command_line == 0 || *command_line == 0) {
+        de_error("File name argument required");
+        return( 0 );
+   } else {
+        char *p = command_line;
+        
+        while (*p != 0 && !isspace(*p)) p++;
+   	arg_file_name = CORD_to_char_star(
+   			    CORD_substr(command_line, 0, p - command_line));
+   }
+
+   hwnd = CreateWindow (szAppName,
+   			FullAppName,
+   			WS_OVERLAPPEDWINDOW | WS_CAPTION, /* Window style */
+   			CW_USEDEFAULT, 0, /* default pos. */
+   			CW_USEDEFAULT, 0, /* default width, height */
+   			NULL,	/* No parent */
+   			NULL, 	/* Window class menu */
+   			hInstance, NULL);
+   if (hwnd == NULL) {
+   	char buf[50];
+   	
+   	sprintf(buf, "CreateWindow: error code: 0x%X", GetLastError());
+   	de_error(buf);
+   	return(0);
+   }
+
+   ShowWindow (hwnd, nCmdShow);
+
+   hAccel = LoadAccelerators( hInstance, szAppName );
+   
+   while (GetMessage (&msg, NULL, 0, 0))
+   {
+      if( !TranslateAccelerator( hwnd, hAccel, &msg ) )
+      {
+         TranslateMessage (&msg);
+         DispatchMessage (&msg);
+      }
+   }
+   return msg.wParam;
+}
+
+/* Return the argument with all control characters replaced by blanks.	*/
+char * plain_chars(char * text, size_t len)
+{
+    char * result = GC_MALLOC_ATOMIC(len + 1);
+    register size_t i;
+    
+    for (i = 0; i < len; i++) {
+       if (iscntrl(text[i])) {
+           result[i] = ' ';
+       } else {
+           result[i] = text[i];
+       }
+    }
+    result[len] = '\0';
+    return(result);
+}
+
+/* Return the argument with all non-control-characters replaced by 	*/
+/* blank, and all control characters c replaced by c + 32.		*/
+char * control_chars(char * text, size_t len)
+{
+    char * result = GC_MALLOC_ATOMIC(len + 1);
+    register size_t i;
+    
+    for (i = 0; i < len; i++) {
+       if (iscntrl(text[i])) {
+           result[i] = text[i] + 0x40;
+       } else {
+           result[i] = ' ';
+       }
+    }
+    result[len] = '\0';
+    return(result);
+}
+
+int char_width;
+int char_height;
+
+void get_line_rect(int line, int win_width, RECT * rectp)
+{
+    rectp -> top = line * char_height;
+    rectp -> bottom = rectp->top + char_height;
+    rectp -> left = 0;
+    rectp -> right = win_width;
+}
+
+int caret_visible = 0;	/* Caret is currently visible.	*/
+
+int screen_was_painted = 0;/* Screen has been painted at least once.	*/
+
+void update_cursor(void);
+
+LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
+                          WPARAM wParam, LPARAM lParam)
+{
+   static FARPROC lpfnAboutBox;
+   static HANDLE  hInstance;
+   HDC dc;
+   PAINTSTRUCT ps;
+   RECT client_area;
+   RECT this_line;
+   RECT dummy;
+   TEXTMETRIC tm;
+   register int i;
+   int id;
+
+   switch (message)
+   {
+      case WM_CREATE:
+           hInstance = ( (LPCREATESTRUCT) lParam)->hInstance;
+           lpfnAboutBox = MakeProcInstance( (FARPROC) AboutBox, hInstance );
+           dc = GetDC(hwnd);
+           SelectObject(dc, GetStockObject(SYSTEM_FIXED_FONT));
+           GetTextMetrics(dc, &tm);
+           ReleaseDC(hwnd, dc);
+           char_width = tm.tmAveCharWidth;
+           char_height = tm.tmHeight + tm.tmExternalLeading;
+           GetClientRect(hwnd, &client_area);
+      	   COLS = (client_area.right - client_area.left)/char_width;
+      	   LINES = (client_area.bottom - client_area.top)/char_height;
+      	   generic_init();
+           return(0);
+
+      case WM_CHAR:
+      	   if (wParam == QUIT) {
+      	       SendMessage( hwnd, WM_CLOSE, 0, 0L );
+      	   } else {
+      	       do_command(wParam);
+      	   }
+      	   return(0);
+      
+      case WM_SETFOCUS:
+      	   CreateCaret(hwnd, NULL, char_width, char_height);
+      	   ShowCaret(hwnd);
+      	   caret_visible = 1;
+      	   update_cursor();
+      	   return(0);
+      	   
+      case WM_KILLFOCUS:
+      	   HideCaret(hwnd);
+      	   DestroyCaret();
+      	   caret_visible = 0;
+      	   return(0);
+      	   
+      case WM_LBUTTONUP:
+      	   {
+      	       unsigned xpos = LOWORD(lParam);	/* From left	*/
+      	       unsigned ypos = HIWORD(lParam);	/* from top */
+      	       
+      	       set_position( xpos/char_width, ypos/char_height );
+      	       return(0);
+      	   }
+      	   
+      case WM_COMMAND:
+      	   id = LOWORD(wParam);
+      	   if (id & EDIT_CMD_FLAG) {
+               if (id & REPEAT_FLAG) do_command(REPEAT);
+               do_command(CHAR_CMD(id));
+               return( 0 );
+           } else {
+             switch(id) {
+               case IDM_FILEEXIT:
+                  SendMessage( hwnd, WM_CLOSE, 0, 0L );
+                  return( 0 );
+
+               case IDM_HELPABOUT:
+                  if( DialogBox( hInstance, "ABOUTBOX",
+                                 hwnd, lpfnAboutBox ) );
+                     InvalidateRect( hwnd, NULL, TRUE );
+                  return( 0 );
+	       case IDM_HELPCONTENTS:
+	     	  de_error(
+	     	       "Cursor keys: ^B(left) ^F(right) ^P(up) ^N(down)\n"
+	     	       "Undo: ^U    Write: ^W   Quit:^D  Repeat count: ^R[n]\n"
+	     	       "Top: ^T   Locate (search, find): ^L text ^L\n");
+	     	  return( 0 );
+	     }
+	   }
+           break;
+
+      case WM_CLOSE:
+           DestroyWindow( hwnd );
+           return 0;
+
+      case WM_DESTROY:
+           PostQuitMessage (0);
+	   GC_win32_free_heap();
+           return 0;
+      
+      case WM_PAINT:
+      	   dc = BeginPaint(hwnd, &ps);
+      	   GetClientRect(hwnd, &client_area);
+      	   COLS = (client_area.right - client_area.left)/char_width;
+      	   LINES = (client_area.bottom - client_area.top)/char_height;
+      	   SelectObject(dc, GetStockObject(SYSTEM_FIXED_FONT));
+      	   for (i = 0; i < LINES; i++) {
+      	       get_line_rect(i, client_area.right, &this_line);
+      	       if (IntersectRect(&dummy, &this_line, &ps.rcPaint)) {
+      	           CORD raw_line = retrieve_screen_line(i);
+      	           size_t len = CORD_len(raw_line);
+      	           char * text = CORD_to_char_star(raw_line);
+      	           		/* May contain embedded NULLs	*/
+      	           char * plain = plain_chars(text, len);
+      	           char * blanks = CORD_to_char_star(CORD_chars(' ',
+      	           				                COLS - len));
+      	           char * control = control_chars(text, len);
+#		   define RED RGB(255,0,0)
+      	           
+      	           SetBkMode(dc, OPAQUE);
+      	           SetTextColor(dc, GetSysColor(COLOR_WINDOWTEXT));
+      	           
+      	           TextOut(dc, this_line.left, this_line.top,
+      	           	   plain, len);
+      	           TextOut(dc, this_line.left + len * char_width, this_line.top,
+      	           	   blanks, COLS - len);
+      	           SetBkMode(dc, TRANSPARENT);
+      	           SetTextColor(dc, RED);
+      	           TextOut(dc, this_line.left, this_line.top,
+      	           	   control, strlen(control));
+      	       }
+      	   }
+      	   EndPaint(hwnd, &ps);
+      	   screen_was_painted = 1;
+      	   return 0;
+   }
+   return DefWindowProc (hwnd, message, wParam, lParam);
+}
+
+int last_col;
+int last_line;
+
+void move_cursor(int c, int l)
+{
+    last_col = c;
+    last_line = l;
+    
+    if (caret_visible) update_cursor();
+}
+
+void update_cursor(void)
+{
+    SetCaretPos(last_col * char_width, last_line * char_height);
+    ShowCaret(hwnd);
+}
+
+void invalidate_line(int i)
+{
+    RECT line;
+    
+    if (!screen_was_painted) return;
+    	/* Invalidating a rectangle before painting seems result in a	*/
+    	/* major performance problem.					*/
+    get_line_rect(i, COLS*char_width, &line);
+    InvalidateRect(hwnd, &line, FALSE);
+}
+
+LRESULT CALLBACK AboutBox( HWND hDlg, UINT message,
+                           WPARAM wParam, LPARAM lParam )
+{
+   switch( message )
+   {
+      case WM_INITDIALOG:
+           SetFocus( GetDlgItem( hDlg, IDOK ) );
+           break;
+
+      case WM_COMMAND:
+           switch( wParam )
+           {
+              case IDOK:
+                   EndDialog( hDlg, TRUE );
+                   break;
+           }
+           break;
+
+      case WM_CLOSE:
+           EndDialog( hDlg, TRUE );
+           return TRUE;
+
+   }
+   return FALSE;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/cord/de_win.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 1994 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+/* Boehm, May 19, 1994 2:25 pm PDT */
+
+/* cord.h, de_cmds.h, and windows.h should be included before this. */
+
+
+# define OTHER_FLAG	0x100
+# define EDIT_CMD_FLAG	0x200
+# define REPEAT_FLAG	0x400
+
+# define CHAR_CMD(i) ((i) & 0xff)
+
+/* MENU: DE */
+#define IDM_FILESAVE		(EDIT_CMD_FLAG + WRITE)
+#define IDM_FILEEXIT		(OTHER_FLAG + 1)
+#define IDM_HELPABOUT		(OTHER_FLAG + 2)
+#define IDM_HELPCONTENTS	(OTHER_FLAG + 3)
+
+#define IDM_EDITPDOWN		(REPEAT_FLAG + EDIT_CMD_FLAG + DOWN)
+#define IDM_EDITPUP		(REPEAT_FLAG + EDIT_CMD_FLAG + UP)
+#define IDM_EDITUNDO		(EDIT_CMD_FLAG + UNDO)
+#define IDM_EDITLOCATE		(EDIT_CMD_FLAG + LOCATE)
+#define IDM_EDITDOWN		(EDIT_CMD_FLAG + DOWN)
+#define IDM_EDITUP		(EDIT_CMD_FLAG + UP)
+#define IDM_EDITLEFT		(EDIT_CMD_FLAG + LEFT)
+#define IDM_EDITRIGHT		(EDIT_CMD_FLAG + RIGHT)
+#define IDM_EDITBS		(EDIT_CMD_FLAG + BS)
+#define IDM_EDITDEL		(EDIT_CMD_FLAG + DEL)
+#define IDM_EDITREPEAT		(EDIT_CMD_FLAG + REPEAT)
+#define IDM_EDITTOP		(EDIT_CMD_FLAG + TOP)
+
+
+
+
+/* Windows UI stuff	*/
+
+LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
+			  UINT wParam, LONG lParam);
+
+LRESULT CALLBACK AboutBox( HWND hDlg, UINT message,
+			   UINT wParam, LONG lParam );
+
+
+/* Screen dimensions.  Maintained by de_win.c.	*/
+extern int LINES;
+extern int COLS;
+
+/* File being edited.	*/
+extern char * arg_file_name;
+
+/* Current display position in file.  Maintained by de.c	*/
+extern int dis_line;
+extern int dis_col;
+
+/* Current cursor position in file.				*/
+extern int line;
+extern int col;
+
+/*
+ *  Calls from de_win.c to de.c
+ */
+  
+CORD retrieve_screen_line(int i);
+			/* Get the contents of i'th screen line.	*/
+			/* Relies on COLS.				*/
+
+void set_position(int x, int y);
+			/* Set column, row.  Upper left of window = (0,0). */
+
+void do_command(int);
+			/* Execute an editor command.			*/
+			/* Agument is a command character or one	*/
+			/* of the IDM_ commands.			*/
+
+void generic_init(void);
+			/* OS independent initialization */
+
+
+/*
+ * Calls from de.c to de_win.c
+ */
+ 
+void move_cursor(int column, int line);
+			/* Physically move the cursor on the display,	*/
+			/* so that it appears at			*/
+			/* (column, line).				*/
+
+void invalidate_line(int line);
+			/* Invalidate line i on the screen.	*/
+
+void de_error(char *s);
+			/* Display error message.	*/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/cord/ec.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,70 @@
+# ifndef EC_H
+# define EC_H
+
+# ifndef CORD_H
+#  include "cord.h"
+# endif
+
+/* Extensible cords are strings that may be destructively appended to.	*/
+/* They allow fast construction of cords from characters that are	*/
+/* being read from a stream.						*/
+/*
+ * A client might look like:
+ *
+ *	{
+ *	    CORD_ec x;
+ *	    CORD result;
+ *	    char c;
+ *	    FILE *f;
+ *
+ *	    ...
+ *	    CORD_ec_init(x);
+ *	    while(...) {
+ *		c = getc(f);
+ *		...
+ *		CORD_ec_append(x, c);
+ *	    }
+ *	    result = CORD_balance(CORD_ec_to_cord(x));
+ *
+ * If a C string is desired as the final result, the call to CORD_balance
+ * may be replaced by a call to CORD_to_char_star.
+ */
+
+# ifndef CORD_BUFSZ
+#   define CORD_BUFSZ 128
+# endif
+
+typedef struct CORD_ec_struct {
+    CORD ec_cord;
+    char * ec_bufptr;
+    char ec_buf[CORD_BUFSZ+1];
+} CORD_ec[1];
+
+/* This structure represents the concatenation of ec_cord with		*/
+/* ec_buf[0 ... (ec_bufptr-ec_buf-1)]					*/
+
+/* Flush the buffer part of the extended chord into ec_cord.	*/
+/* Note that this is almost the only real function, and it is	*/
+/* implemented in 6 lines in cordxtra.c				*/
+void CORD_ec_flush_buf(CORD_ec x);
+      
+/* Convert an extensible cord to a cord. */
+# define CORD_ec_to_cord(x) (CORD_ec_flush_buf(x), (x)[0].ec_cord)
+
+/* Initialize an extensible cord. */
+# define CORD_ec_init(x) ((x)[0].ec_cord = 0, (x)[0].ec_bufptr = (x)[0].ec_buf)
+
+/* Append a character to an extensible cord.	*/
+# define CORD_ec_append(x, c) \
+    {  \
+	if ((x)[0].ec_bufptr == (x)[0].ec_buf + CORD_BUFSZ) { \
+	  	CORD_ec_flush_buf(x); \
+	} \
+	*((x)[0].ec_bufptr)++ = (c); \
+    }
+
+/* Append a cord to an extensible cord.  Structure remains shared with 	*/
+/* original.								*/
+void CORD_ec_append_cord(CORD_ec x, CORD s);
+
+# endif /* EC_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/cord/gc.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,804 @@
+/* 
+ * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
+ * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.
+ * Copyright 1996-1999 by Silicon Graphics.  All rights reserved.
+ * Copyright 1999 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+/*
+ * Note that this defines a large number of tuning hooks, which can
+ * safely be ignored in nearly all cases.  For normal use it suffices
+ * to call only GC_MALLOC and perhaps GC_REALLOC.
+ * For better performance, also look at GC_MALLOC_ATOMIC, and
+ * GC_enable_incremental.  If you need an action to be performed
+ * immediately before an object is collected, look at GC_register_finalizer.
+ * If you are using Solaris threads, look at the end of this file.
+ * Everything else is best ignored unless you encounter performance
+ * problems.
+ */
+ 
+#ifndef _GC_H
+
+# define _GC_H
+# define __GC
+# include <stddef.h>
+
+#if defined(__CYGWIN32__) && defined(GC_USE_DLL)
+#include "libgc_globals.h"
+#endif
+
+#if defined(__MINGW32__) && defined(WIN32_THREADS)
+# ifdef GC_BUILD
+#   define GC_API __declspec(dllexport)
+# else
+#   define GC_API __declspec(dllimport)
+# endif
+#endif
+
+#if defined(_MSC_VER) && defined(_DLL)
+# ifdef GC_BUILD
+#   define GC_API __declspec(dllexport)
+# else
+#   define GC_API __declspec(dllimport)
+# endif
+#endif
+
+#if defined(__WATCOMC__) && defined(GC_DLL)
+# ifdef GC_BUILD
+#   define GC_API extern __declspec(dllexport)
+# else
+#   define GC_API extern __declspec(dllimport)
+# endif
+#endif
+
+#ifndef GC_API
+#define GC_API extern
+#endif
+
+# if defined(__STDC__) || defined(__cplusplus)
+#   define GC_PROTO(args) args
+    typedef void * GC_PTR;
+#   define GC_CONST const
+# else
+#   define GC_PROTO(args) ()
+    typedef char * GC_PTR;
+#   define GC_CONST
+#  endif
+
+# ifdef __cplusplus
+    extern "C" {
+# endif
+
+
+/* Define word and signed_word to be unsigned and signed types of the 	*/
+/* size as char * or void *.  There seems to be no way to do this	*/
+/* even semi-portably.  The following is probably no better/worse 	*/
+/* than almost anything else.						*/
+/* The ANSI standard suggests that size_t and ptr_diff_t might be 	*/
+/* better choices.  But those appear to have incorrect definitions	*/
+/* on may systems.  Notably "typedef int size_t" seems to be both	*/
+/* frequent and WRONG.							*/
+typedef unsigned long GC_word;
+typedef long GC_signed_word;
+
+/* Public read-only variables */
+
+GC_API GC_word GC_gc_no;/* Counter incremented per collection.  	*/
+			/* Includes empty GCs at startup.		*/
+			
+
+/* Public R/W variables */
+
+GC_API GC_PTR (*GC_oom_fn) GC_PROTO((size_t bytes_requested));
+			/* When there is insufficient memory to satisfy */
+			/* an allocation request, we return		*/
+			/* (*GC_oom_fn)().  By default this just	*/
+			/* returns 0.					*/
+			/* If it returns, it must return 0 or a valid	*/
+			/* pointer to a previously allocated heap 	*/
+			/* object.					*/
+
+GC_API int GC_find_leak;
+			/* Do not actually garbage collect, but simply	*/
+			/* report inaccessible memory that was not	*/
+			/* deallocated with GC_free.  Initial value	*/
+			/* is determined by FIND_LEAK macro.		*/
+
+GC_API int GC_quiet;	/* Disable statistics output.  Only matters if	*/
+			/* collector has been compiled with statistics	*/
+			/* enabled.  This involves a performance cost,	*/
+			/* and is thus not the default.			*/
+
+GC_API int GC_finalize_on_demand;
+			/* If nonzero, finalizers will only be run in 	*/
+			/* response to an eplit GC_invoke_finalizers	*/
+			/* call.  The default is determined by whether	*/
+			/* the FINALIZE_ON_DEMAND macro is defined	*/
+			/* when the collector is built.			*/
+
+GC_API int GC_java_finalization;
+			/* Mark objects reachable from finalizable 	*/
+			/* objects in a separate postpass.  This makes	*/
+			/* it a bit safer to use non-topologically-	*/
+			/* ordered finalization.  Default value is	*/
+			/* determined by JAVA_FINALIZATION macro.	*/
+
+GC_API int GC_dont_gc;	/* Dont collect unless explicitly requested, e.g. */
+			/* because it's not safe.			  */
+
+GC_API int GC_dont_expand;
+			/* Dont expand heap unless explicitly requested */
+			/* or forced to.				*/
+
+GC_API int GC_use_entire_heap;
+		/* Causes the nonincremental collector to use the	*/
+		/* entire heap before collecting.  This was the only 	*/
+		/* option for GC versions < 5.0.  This sometimes	*/
+		/* results in more large block fragmentation, since	*/
+		/* very larg blocks will tend to get broken up		*/
+		/* during each GC cycle.  It is likely to result in a	*/
+		/* larger working set, but lower collection		*/
+		/* frequencies, and hence fewer instructions executed	*/
+		/* in the collector.					*/
+
+GC_API int GC_full_freq;    /* Number of partial collections between	*/
+			    /* full collections.  Matters only if	*/
+			    /* GC_incremental is set.			*/
+			    /* Full collections are also triggered if	*/
+			    /* the collector detects a substantial	*/
+			    /* increase in the number of in-use heap	*/
+			    /* blocks.  Values in the tens are now	*/
+			    /* perfectly reasonable, unlike for		*/
+			    /* earlier GC versions.			*/
+			
+GC_API GC_word GC_non_gc_bytes;
+			/* Bytes not considered candidates for collection. */
+			/* Used only to control scheduling of collections. */
+
+GC_API GC_word GC_free_space_divisor;
+			/* We try to make sure that we allocate at 	*/
+			/* least N/GC_free_space_divisor bytes between	*/
+			/* collections, where N is the heap size plus	*/
+			/* a rough estimate of the root set size.	*/
+			/* Initially, GC_free_space_divisor = 4.	*/
+			/* Increasing its value will use less space	*/
+			/* but more collection time.  Decreasing it	*/
+			/* will appreciably decrease collection time	*/
+			/* at the expense of space.			*/
+			/* GC_free_space_divisor = 1 will effectively	*/
+			/* disable collections.				*/
+
+GC_API GC_word GC_max_retries;
+			/* The maximum number of GCs attempted before	*/
+			/* reporting out of memory after heap		*/
+			/* expansion fails.  Initially 0.		*/
+			
+
+GC_API char *GC_stackbottom;	/* Cool end of user stack.		*/
+				/* May be set in the client prior to	*/
+				/* calling any GC_ routines.  This	*/
+				/* avoids some overhead, and 		*/
+				/* potentially some signals that can 	*/
+				/* confuse debuggers.  Otherwise the	*/
+				/* collector attempts to set it 	*/
+				/* automatically.			*/
+				/* For multithreaded code, this is the	*/
+				/* cold end of the stack for the	*/
+				/* primordial thread.			*/
+				
+/* Public procedures */
+/*
+ * general purpose allocation routines, with roughly malloc calling conv.
+ * The atomic versions promise that no relevant pointers are contained
+ * in the object.  The nonatomic versions guarantee that the new object
+ * is cleared.  GC_malloc_stubborn promises that no changes to the object
+ * will occur after GC_end_stubborn_change has been called on the
+ * result of GC_malloc_stubborn. GC_malloc_uncollectable allocates an object
+ * that is scanned for pointers to collectable objects, but is not itself
+ * collectable.  GC_malloc_uncollectable and GC_free called on the resulting
+ * object implicitly update GC_non_gc_bytes appropriately.
+ */
+GC_API GC_PTR GC_malloc GC_PROTO((size_t size_in_bytes));
+GC_API GC_PTR GC_malloc_atomic GC_PROTO((size_t size_in_bytes));
+GC_API GC_PTR GC_malloc_uncollectable GC_PROTO((size_t size_in_bytes));
+GC_API GC_PTR GC_malloc_stubborn GC_PROTO((size_t size_in_bytes));
+
+/* The following is only defined if the library has been suitably	*/
+/* compiled:								*/
+GC_API GC_PTR GC_malloc_atomic_uncollectable GC_PROTO((size_t size_in_bytes));
+
+/* Explicitly deallocate an object.  Dangerous if used incorrectly.     */
+/* Requires a pointer to the base of an object.				*/
+/* If the argument is stubborn, it should not be changeable when freed. */
+/* An object should not be enable for finalization when it is 		*/
+/* explicitly deallocated.						*/
+/* GC_free(0) is a no-op, as required by ANSI C for free.		*/
+GC_API void GC_free GC_PROTO((GC_PTR object_addr));
+
+/*
+ * Stubborn objects may be changed only if the collector is explicitly informed.
+ * The collector is implicitly informed of coming change when such
+ * an object is first allocated.  The following routines inform the
+ * collector that an object will no longer be changed, or that it will
+ * once again be changed.  Only nonNIL pointer stores into the object
+ * are considered to be changes.  The argument to GC_end_stubborn_change
+ * must be exacly the value returned by GC_malloc_stubborn or passed to
+ * GC_change_stubborn.  (In the second case it may be an interior pointer
+ * within 512 bytes of the beginning of the objects.)
+ * There is a performance penalty for allowing more than
+ * one stubborn object to be changed at once, but it is acceptable to
+ * do so.  The same applies to dropping stubborn objects that are still
+ * changeable.
+ */
+GC_API void GC_change_stubborn GC_PROTO((GC_PTR));
+GC_API void GC_end_stubborn_change GC_PROTO((GC_PTR));
+
+/* Return a pointer to the base (lowest address) of an object given	*/
+/* a pointer to a location within the object.				*/
+/* Return 0 if displaced_pointer doesn't point to within a valid	*/
+/* object.								*/
+GC_API GC_PTR GC_base GC_PROTO((GC_PTR displaced_pointer));
+
+/* Given a pointer to the base of an object, return its size in bytes.	*/
+/* The returned size may be slightly larger than what was originally	*/
+/* requested.								*/
+GC_API size_t GC_size GC_PROTO((GC_PTR object_addr));
+
+/* For compatibility with C library.  This is occasionally faster than	*/
+/* a malloc followed by a bcopy.  But if you rely on that, either here	*/
+/* or with the standard C library, your code is broken.  In my		*/
+/* opinion, it shouldn't have been invented, but now we're stuck. -HB	*/
+/* The resulting object has the same kind as the original.		*/
+/* If the argument is stubborn, the result will have changes enabled.	*/
+/* It is an error to have changes enabled for the original object.	*/
+/* Follows ANSI comventions for NULL old_object.			*/
+GC_API GC_PTR GC_realloc
+	GC_PROTO((GC_PTR old_object, size_t new_size_in_bytes));
+				   
+/* Explicitly increase the heap size.	*/
+/* Returns 0 on failure, 1 on success.  */
+GC_API int GC_expand_hp GC_PROTO((size_t number_of_bytes));
+
+/* Limit the heap size to n bytes.  Useful when you're debugging, 	*/
+/* especially on systems that don't handle running out of memory well.	*/
+/* n == 0 ==> unbounded.  This is the default.				*/
+GC_API void GC_set_max_heap_size GC_PROTO((GC_word n));
+
+/* Inform the collector that a certain section of statically allocated	*/
+/* memory contains no pointers to garbage collected memory.  Thus it 	*/
+/* need not be scanned.  This is sometimes important if the application */
+/* maps large read/write files into the address space, which could be	*/
+/* mistaken for dynamic library data segments on some systems.		*/
+GC_API void GC_exclude_static_roots GC_PROTO((GC_PTR start, GC_PTR finish));
+
+/* Clear the set of root segments.  Wizards only. */
+GC_API void GC_clear_roots GC_PROTO((void));
+
+/* Add a root segment.  Wizards only. */
+GC_API void GC_add_roots GC_PROTO((char * low_address,
+				   char * high_address_plus_1));
+
+/* Add a displacement to the set of those considered valid by the	*/
+/* collector.  GC_register_displacement(n) means that if p was returned */
+/* by GC_malloc, then (char *)p + n will be considered to be a valid	*/
+/* pointer to n.  N must be small and less than the size of p.		*/
+/* (All pointers to the interior of objects from the stack are		*/
+/* considered valid in any case.  This applies to heap objects and	*/
+/* static data.)							*/
+/* Preferably, this should be called before any other GC procedures.	*/
+/* Calling it later adds to the probability of excess memory		*/
+/* retention.								*/
+/* This is a no-op if the collector was compiled with recognition of	*/
+/* arbitrary interior pointers enabled, which is now the default.	*/
+GC_API void GC_register_displacement GC_PROTO((GC_word n));
+
+/* The following version should be used if any debugging allocation is	*/
+/* being done.								*/
+GC_API void GC_debug_register_displacement GC_PROTO((GC_word n));
+
+/* Explicitly trigger a full, world-stop collection. 	*/
+GC_API void GC_gcollect GC_PROTO((void));
+
+/* Trigger a full world-stopped collection.  Abort the collection if 	*/
+/* and when stop_func returns a nonzero value.  Stop_func will be 	*/
+/* called frequently, and should be reasonably fast.  This works even	*/
+/* if virtual dirty bits, and hence incremental collection is not 	*/
+/* available for this architecture.  Collections can be aborted faster	*/
+/* than normal pause times for incremental collection.  However,	*/
+/* aborted collections do no useful work; the next collection needs	*/
+/* to start from the beginning.						*/
+/* Return 0 if the collection was aborted, 1 if it succeeded.		*/
+typedef int (* GC_stop_func) GC_PROTO((void));
+GC_API int GC_try_to_collect GC_PROTO((GC_stop_func stop_func));
+
+/* Return the number of bytes in the heap.  Excludes collector private	*/
+/* data structures.  Includes empty blocks and fragmentation loss.	*/
+/* Includes some pages that were allocated but never written.		*/
+GC_API size_t GC_get_heap_size GC_PROTO((void));
+
+/* Return a lower bound on the number of free bytes in the heap.	*/
+GC_API size_t GC_get_free_bytes GC_PROTO((void));
+
+/* Return the number of bytes allocated since the last collection.	*/
+GC_API size_t GC_get_bytes_since_gc GC_PROTO((void));
+
+/* Enable incremental/generational collection.	*/
+/* Not advisable unless dirty bits are 		*/
+/* available or most heap objects are		*/
+/* pointerfree(atomic) or immutable.		*/
+/* Don't use in leak finding mode.		*/
+/* Ignored if GC_dont_gc is true.		*/
+GC_API void GC_enable_incremental GC_PROTO((void));
+
+/* Perform some garbage collection work, if appropriate.	*/
+/* Return 0 if there is no more work to be done.		*/
+/* Typically performs an amount of work corresponding roughly	*/
+/* to marking from one page.  May do more work if further	*/
+/* progress requires it, e.g. if incremental collection is	*/
+/* disabled.  It is reasonable to call this in a wait loop	*/
+/* until it returns 0.						*/
+GC_API int GC_collect_a_little GC_PROTO((void));
+
+/* Allocate an object of size lb bytes.  The client guarantees that	*/
+/* as long as the object is live, it will be referenced by a pointer	*/
+/* that points to somewhere within the first 256 bytes of the object.	*/
+/* (This should normally be declared volatile to prevent the compiler	*/
+/* from invalidating this assertion.)  This routine is only useful	*/
+/* if a large array is being allocated.  It reduces the chance of 	*/
+/* accidentally retaining such an array as a result of scanning an	*/
+/* integer that happens to be an address inside the array.  (Actually,	*/
+/* it reduces the chance of the allocator not finding space for such	*/
+/* an array, since it will try hard to avoid introducing such a false	*/
+/* reference.)  On a SunOS 4.X or MS Windows system this is recommended */
+/* for arrays likely to be larger than 100K or so.  For other systems,	*/
+/* or if the collector is not configured to recognize all interior	*/
+/* pointers, the threshold is normally much higher.			*/
+GC_API GC_PTR GC_malloc_ignore_off_page GC_PROTO((size_t lb));
+GC_API GC_PTR GC_malloc_atomic_ignore_off_page GC_PROTO((size_t lb));
+
+#if defined(__sgi) && !defined(__GNUC__) && _COMPILER_VERSION >= 720
+#   define GC_ADD_CALLER
+#   define GC_RETURN_ADDR (GC_word)__return_address
+#endif
+
+#ifdef GC_ADD_CALLER
+#  define GC_EXTRAS GC_RETURN_ADDR, __FILE__, __LINE__
+#  define GC_EXTRA_PARAMS GC_word ra, GC_CONST char * s, int i
+#else
+#  define GC_EXTRAS __FILE__, __LINE__
+#  define GC_EXTRA_PARAMS GC_CONST char * s, int i
+#endif
+
+/* Debugging (annotated) allocation.  GC_gcollect will check 		*/
+/* objects allocated in this way for overwrites, etc.			*/
+GC_API GC_PTR GC_debug_malloc
+	GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
+GC_API GC_PTR GC_debug_malloc_atomic
+	GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
+GC_API GC_PTR GC_debug_malloc_uncollectable
+	GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
+GC_API GC_PTR GC_debug_malloc_stubborn
+	GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
+GC_API void GC_debug_free GC_PROTO((GC_PTR object_addr));
+GC_API GC_PTR GC_debug_realloc
+	GC_PROTO((GC_PTR old_object, size_t new_size_in_bytes,
+  		  GC_EXTRA_PARAMS));
+  			 	 
+GC_API void GC_debug_change_stubborn GC_PROTO((GC_PTR));
+GC_API void GC_debug_end_stubborn_change GC_PROTO((GC_PTR));
+# ifdef GC_DEBUG
+#   define GC_MALLOC(sz) GC_debug_malloc(sz, GC_EXTRAS)
+#   define GC_MALLOC_ATOMIC(sz) GC_debug_malloc_atomic(sz, GC_EXTRAS)
+#   define GC_MALLOC_UNCOLLECTABLE(sz) GC_debug_malloc_uncollectable(sz, \
+							GC_EXTRAS)
+#   define GC_REALLOC(old, sz) GC_debug_realloc(old, sz, GC_EXTRAS)
+#   define GC_FREE(p) GC_debug_free(p)
+#   define GC_REGISTER_FINALIZER(p, f, d, of, od) \
+	GC_debug_register_finalizer(p, f, d, of, od)
+#   define GC_REGISTER_FINALIZER_IGNORE_SELF(p, f, d, of, od) \
+	GC_debug_register_finalizer_ignore_self(p, f, d, of, od)
+#   define GC_REGISTER_FINALIZER_NO_ORDER(p, f, d, of, od) \
+	GC_debug_register_finalizer_no_order(p, f, d, of, od)
+#   define GC_MALLOC_STUBBORN(sz) GC_debug_malloc_stubborn(sz, GC_EXTRAS);
+#   define GC_CHANGE_STUBBORN(p) GC_debug_change_stubborn(p)
+#   define GC_END_STUBBORN_CHANGE(p) GC_debug_end_stubborn_change(p)
+#   define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \
+	GC_general_register_disappearing_link(link, GC_base(obj))
+#   define GC_REGISTER_DISPLACEMENT(n) GC_debug_register_displacement(n)
+# else
+#   define GC_MALLOC(sz) GC_malloc(sz)
+#   define GC_MALLOC_ATOMIC(sz) GC_malloc_atomic(sz)
+#   define GC_MALLOC_UNCOLLECTABLE(sz) GC_malloc_uncollectable(sz)
+#   define GC_REALLOC(old, sz) GC_realloc(old, sz)
+#   define GC_FREE(p) GC_free(p)
+#   define GC_REGISTER_FINALIZER(p, f, d, of, od) \
+	GC_register_finalizer(p, f, d, of, od)
+#   define GC_REGISTER_FINALIZER_IGNORE_SELF(p, f, d, of, od) \
+	GC_register_finalizer_ignore_self(p, f, d, of, od)
+#   define GC_REGISTER_FINALIZER_NO_ORDER(p, f, d, of, od) \
+	GC_register_finalizer_no_order(p, f, d, of, od)
+#   define GC_MALLOC_STUBBORN(sz) GC_malloc_stubborn(sz)
+#   define GC_CHANGE_STUBBORN(p) GC_change_stubborn(p)
+#   define GC_END_STUBBORN_CHANGE(p) GC_end_stubborn_change(p)
+#   define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \
+	GC_general_register_disappearing_link(link, obj)
+#   define GC_REGISTER_DISPLACEMENT(n) GC_register_displacement(n)
+# endif
+/* The following are included because they are often convenient, and	*/
+/* reduce the chance for a misspecifed size argument.  But calls may	*/
+/* expand to something syntactically incorrect if t is a complicated	*/
+/* type expression.  							*/
+# define GC_NEW(t) (t *)GC_MALLOC(sizeof (t))
+# define GC_NEW_ATOMIC(t) (t *)GC_MALLOC_ATOMIC(sizeof (t))
+# define GC_NEW_STUBBORN(t) (t *)GC_MALLOC_STUBBORN(sizeof (t))
+# define GC_NEW_UNCOLLECTABLE(t) (t *)GC_MALLOC_UNCOLLECTABLE(sizeof (t))
+
+/* Finalization.  Some of these primitives are grossly unsafe.		*/
+/* The idea is to make them both cheap, and sufficient to build		*/
+/* a safer layer, closer to PCedar finalization.			*/
+/* The interface represents my conclusions from a long discussion	*/
+/* with Alan Demers, Dan Greene, Carl Hauser, Barry Hayes, 		*/
+/* Christian Jacobi, and Russ Atkinson.  It's not perfect, and		*/
+/* probably nobody else agrees with it.	    Hans-J. Boehm  3/13/92	*/
+typedef void (*GC_finalization_proc)
+  	GC_PROTO((GC_PTR obj, GC_PTR client_data));
+
+GC_API void GC_register_finalizer
+    	GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
+		  GC_finalization_proc *ofn, GC_PTR *ocd));
+GC_API void GC_debug_register_finalizer
+    	GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
+		  GC_finalization_proc *ofn, GC_PTR *ocd));
+	/* When obj is no longer accessible, invoke		*/
+	/* (*fn)(obj, cd).  If a and b are inaccessible, and	*/
+	/* a points to b (after disappearing links have been	*/
+	/* made to disappear), then only a will be		*/
+	/* finalized.  (If this does not create any new		*/
+	/* pointers to b, then b will be finalized after the	*/
+	/* next collection.)  Any finalizable object that	*/
+	/* is reachable from itself by following one or more	*/
+	/* pointers will not be finalized (or collected).	*/
+	/* Thus cycles involving finalizable objects should	*/
+	/* be avoided, or broken by disappearing links.		*/
+	/* All but the last finalizer registered for an object  */
+	/* is ignored.						*/
+	/* Finalization may be removed by passing 0 as fn.	*/
+	/* Finalizers are implicitly unregistered just before   */
+	/* they are invoked.					*/
+	/* The old finalizer and client data are stored in	*/
+	/* *ofn and *ocd.					*/ 
+	/* Fn is never invoked on an accessible object,		*/
+	/* provided hidden pointers are converted to real 	*/
+	/* pointers only if the allocation lock is held, and	*/
+	/* such conversions are not performed by finalization	*/
+	/* routines.						*/
+	/* If GC_register_finalizer is aborted as a result of	*/
+	/* a signal, the object may be left with no		*/
+	/* finalization, even if neither the old nor new	*/
+	/* finalizer were NULL.					*/
+	/* Obj should be the nonNULL starting address of an 	*/
+	/* object allocated by GC_malloc or friends.		*/
+	/* Note that any garbage collectable object referenced	*/
+	/* by cd will be considered accessible until the	*/
+	/* finalizer is invoked.				*/
+
+/* Another versions of the above follow.  It ignores		*/
+/* self-cycles, i.e. pointers from a finalizable object to	*/
+/* itself.  There is a stylistic argument that this is wrong,	*/
+/* but it's unavoidable for C++, since the compiler may		*/
+/* silently introduce these.  It's also benign in that specific	*/
+/* case.							*/
+GC_API void GC_register_finalizer_ignore_self
+	GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
+		  GC_finalization_proc *ofn, GC_PTR *ocd));
+GC_API void GC_debug_register_finalizer_ignore_self
+	GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
+		  GC_finalization_proc *ofn, GC_PTR *ocd));
+
+/* Another version of the above.  It ignores all cycles.        */
+/* It should probably only be used by Java implementations.      */
+GC_API void GC_register_finalizer_no_order
+	GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
+		  GC_finalization_proc *ofn, GC_PTR *ocd));
+GC_API void GC_debug_register_finalizer_no_order
+	GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
+		  GC_finalization_proc *ofn, GC_PTR *ocd));
+
+
+/* The following routine may be used to break cycles between	*/
+/* finalizable objects, thus causing cyclic finalizable		*/
+/* objects to be finalized in the correct order.  Standard	*/
+/* use involves calling GC_register_disappearing_link(&p),	*/
+/* where p is a pointer that is not followed by finalization	*/
+/* code, and should not be considered in determining 		*/
+/* finalization order.						*/
+GC_API int GC_register_disappearing_link GC_PROTO((GC_PTR * /* link */));
+	/* Link should point to a field of a heap allocated 	*/
+	/* object obj.  *link will be cleared when obj is	*/
+	/* found to be inaccessible.  This happens BEFORE any	*/
+	/* finalization code is invoked, and BEFORE any		*/
+	/* decisions about finalization order are made.		*/
+	/* This is useful in telling the finalizer that 	*/
+	/* some pointers are not essential for proper		*/
+	/* finalization.  This may avoid finalization cycles.	*/
+	/* Note that obj may be resurrected by another		*/
+	/* finalizer, and thus the clearing of *link may	*/
+	/* be visible to non-finalization code.  		*/
+	/* There's an argument that an arbitrary action should  */
+	/* be allowed here, instead of just clearing a pointer. */
+	/* But this causes problems if that action alters, or 	*/
+	/* examines connectivity.				*/
+	/* Returns 1 if link was already registered, 0		*/
+	/* otherwise.						*/
+	/* Only exists for backward compatibility.  See below:	*/
+	
+GC_API int GC_general_register_disappearing_link
+	GC_PROTO((GC_PTR * /* link */, GC_PTR obj));
+	/* A slight generalization of the above. *link is	*/
+	/* cleared when obj first becomes inaccessible.  This	*/
+	/* can be used to implement weak pointers easily and	*/
+	/* safely. Typically link will point to a location	*/
+	/* holding a disguised pointer to obj.  (A pointer 	*/
+	/* inside an "atomic" object is effectively  		*/
+	/* disguised.)   In this way soft			*/
+	/* pointers are broken before any object		*/
+	/* reachable from them are finalized.  Each link	*/
+	/* May be registered only once, i.e. with one obj	*/
+	/* value.  This was added after a long email discussion */
+	/* with John Ellis.					*/
+	/* Obj must be a pointer to the first word of an object */
+	/* we allocated.  It is unsafe to explicitly deallocate */
+	/* the object containing link.  Explicitly deallocating */
+	/* obj may or may not cause link to eventually be	*/
+	/* cleared.						*/
+GC_API int GC_unregister_disappearing_link GC_PROTO((GC_PTR * /* link */));
+	/* Returns 0 if link was not actually registered.	*/
+	/* Undoes a registration by either of the above two	*/
+	/* routines.						*/
+
+/* Auxiliary fns to make finalization work correctly with displaced	*/
+/* pointers introduced by the debugging allocators.			*/
+GC_API GC_PTR GC_make_closure GC_PROTO((GC_finalization_proc fn, GC_PTR data));
+GC_API void GC_debug_invoke_finalizer GC_PROTO((GC_PTR obj, GC_PTR data));
+
+/* Returns !=0  if GC_invoke_finalizers has something to do. 		*/
+GC_API int GC_should_invoke_finalizers GC_PROTO((void));
+
+GC_API int GC_invoke_finalizers GC_PROTO((void));
+	/* Run finalizers for all objects that are ready to	*/
+	/* be finalized.  Return the number of finalizers	*/
+	/* that were run.  Normally this is also called		*/
+	/* implicitly during some allocations.	If		*/
+	/* GC-finalize_on_demand is nonzero, it must be called	*/
+	/* explicitly.						*/
+
+/* GC_set_warn_proc can be used to redirect or filter warning messages.	*/
+/* p may not be a NULL pointer.						*/
+typedef void (*GC_warn_proc) GC_PROTO((char *msg, GC_word arg));
+GC_API GC_warn_proc GC_set_warn_proc GC_PROTO((GC_warn_proc p));
+    /* Returns old warning procedure.	*/
+	
+/* The following is intended to be used by a higher level	*/
+/* (e.g. cedar-like) finalization facility.  It is expected	*/
+/* that finalization code will arrange for hidden pointers to	*/
+/* disappear.  Otherwise objects can be accessed after they	*/
+/* have been collected.						*/
+/* Note that putting pointers in atomic objects or in 		*/
+/* nonpointer slots of "typed" objects is equivalent to 	*/
+/* disguising them in this way, and may have other advantages.	*/
+# if defined(I_HIDE_POINTERS) || defined(GC_I_HIDE_POINTERS)
+    typedef GC_word GC_hidden_pointer;
+#   define HIDE_POINTER(p) (~(GC_hidden_pointer)(p))
+#   define REVEAL_POINTER(p) ((GC_PTR)(HIDE_POINTER(p)))
+    /* Converting a hidden pointer to a real pointer requires verifying	*/
+    /* that the object still exists.  This involves acquiring the  	*/
+    /* allocator lock to avoid a race with the collector.		*/
+# endif /* I_HIDE_POINTERS */
+
+typedef GC_PTR (*GC_fn_type) GC_PROTO((GC_PTR client_data));
+GC_API GC_PTR GC_call_with_alloc_lock
+        	GC_PROTO((GC_fn_type fn, GC_PTR client_data));
+
+/* Check that p and q point to the same object.  		*/
+/* Fail conspicuously if they don't.				*/
+/* Returns the first argument.  				*/
+/* Succeeds if neither p nor q points to the heap.		*/
+/* May succeed if both p and q point to between heap objects.	*/
+GC_API GC_PTR GC_same_obj GC_PROTO((GC_PTR p, GC_PTR q));
+
+/* Checked pointer pre- and post- increment operations.  Note that	*/
+/* the second argument is in units of bytes, not multiples of the	*/
+/* object size.  This should either be invoked from a macro, or the	*/
+/* call should be automatically generated.				*/
+GC_API GC_PTR GC_pre_incr GC_PROTO((GC_PTR *p, size_t how_much));
+GC_API GC_PTR GC_post_incr GC_PROTO((GC_PTR *p, size_t how_much));
+
+/* Check that p is visible						*/
+/* to the collector as a possibly pointer containing location.		*/
+/* If it isn't fail conspicuously.					*/
+/* Returns the argument in all cases.  May erroneously succeed		*/
+/* in hard cases.  (This is intended for debugging use with		*/
+/* untyped allocations.  The idea is that it should be possible, though	*/
+/* slow, to add such a call to all indirect pointer stores.)		*/
+/* Currently useless for multithreaded worlds.				*/
+GC_API GC_PTR GC_is_visible GC_PROTO((GC_PTR p));
+
+/* Check that if p is a pointer to a heap page, then it points to	*/
+/* a valid displacement within a heap object.				*/
+/* Fail conspicuously if this property does not hold.			*/
+/* Uninteresting with ALL_INTERIOR_POINTERS.				*/
+/* Always returns its argument.						*/
+GC_API GC_PTR GC_is_valid_displacement GC_PROTO((GC_PTR	p));
+
+/* Safer, but slow, pointer addition.  Probably useful mainly with 	*/
+/* a preprocessor.  Useful only for heap pointers.			*/
+#ifdef GC_DEBUG
+#   define GC_PTR_ADD3(x, n, type_of_result) \
+	((type_of_result)GC_same_obj((x)+(n), (x)))
+#   define GC_PRE_INCR3(x, n, type_of_result) \
+	((type_of_result)GC_pre_incr(&(x), (n)*sizeof(*x))
+#   define GC_POST_INCR2(x, type_of_result) \
+	((type_of_result)GC_post_incr(&(x), sizeof(*x))
+#   ifdef __GNUC__
+#       define GC_PTR_ADD(x, n) \
+	    GC_PTR_ADD3(x, n, typeof(x))
+#   define GC_PRE_INCR(x, n) \
+	    GC_PRE_INCR3(x, n, typeof(x))
+#   define GC_POST_INCR(x, n) \
+	    GC_POST_INCR3(x, typeof(x))
+#   else
+	/* We can't do this right without typeof, which ANSI	*/
+	/* decided was not sufficiently useful.  Repeatedly	*/
+	/* mentioning the arguments seems too dangerous to be	*/
+	/* useful.  So does not casting the result.		*/
+#   	define GC_PTR_ADD(x, n) ((x)+(n))
+#   endif
+#else	/* !GC_DEBUG */
+#   define GC_PTR_ADD3(x, n, type_of_result) ((x)+(n))
+#   define GC_PTR_ADD(x, n) ((x)+(n))
+#   define GC_PRE_INCR3(x, n, type_of_result) ((x) += (n))
+#   define GC_PRE_INCR(x, n) ((x) += (n))
+#   define GC_POST_INCR2(x, n, type_of_result) ((x)++)
+#   define GC_POST_INCR(x, n) ((x)++)
+#endif
+
+/* Safer assignment of a pointer to a nonstack location.	*/
+#ifdef GC_DEBUG
+# ifdef __STDC__
+#   define GC_PTR_STORE(p, q) \
+	(*(void **)GC_is_visible(p) = GC_is_valid_displacement(q))
+# else
+#   define GC_PTR_STORE(p, q) \
+	(*(char **)GC_is_visible(p) = GC_is_valid_displacement(q))
+# endif
+#else /* !GC_DEBUG */
+#   define GC_PTR_STORE(p, q) *((p) = (q))
+#endif
+
+/* Fynctions called to report pointer checking errors */
+GC_API void (*GC_same_obj_print_proc) GC_PROTO((GC_PTR p, GC_PTR q));
+
+GC_API void (*GC_is_valid_displacement_print_proc)
+	GC_PROTO((GC_PTR p));
+
+GC_API void (*GC_is_visible_print_proc)
+	GC_PROTO((GC_PTR p));
+
+#if defined(_SOLARIS_PTHREADS) && !defined(SOLARIS_THREADS)
+#   define SOLARIS_THREADS
+#endif
+
+#ifdef SOLARIS_THREADS
+/* We need to intercept calls to many of the threads primitives, so 	*/
+/* that we can locate thread stacks and stop the world.			*/
+/* Note also that the collector cannot see thread specific data.	*/
+/* Thread specific data should generally consist of pointers to		*/
+/* uncollectable objects, which are deallocated using the destructor	*/
+/* facility in thr_keycreate.						*/
+# include <thread.h>
+# include <signal.h>
+  int GC_thr_create(void *stack_base, size_t stack_size,
+                    void *(*start_routine)(void *), void *arg, long flags,
+                    thread_t *new_thread);
+  int GC_thr_join(thread_t wait_for, thread_t *departed, void **status);
+  int GC_thr_suspend(thread_t target_thread);
+  int GC_thr_continue(thread_t target_thread);
+  void * GC_dlopen(const char *path, int mode);
+
+# ifdef _SOLARIS_PTHREADS
+#   include <pthread.h>
+    extern int GC_pthread_create(pthread_t *new_thread,
+    			         const pthread_attr_t *attr,
+          			 void * (*thread_execp)(void *), void *arg);
+    extern int GC_pthread_join(pthread_t wait_for, void **status);
+
+#   undef thread_t
+
+#   define pthread_join GC_pthread_join
+#   define pthread_create GC_pthread_create
+#endif
+
+# define thr_create GC_thr_create
+# define thr_join GC_thr_join
+# define thr_suspend GC_thr_suspend
+# define thr_continue GC_thr_continue
+# define dlopen GC_dlopen
+
+# endif /* SOLARIS_THREADS */
+
+
+#if !defined(USE_LD_WRAP) && \
+    (defined(IRIX_THREADS) || defined(LINUX_THREADS) || defined(HPUX_THREADS))
+/* We treat these similarly. */
+# include <pthread.h>
+# include <signal.h>
+
+  int GC_pthread_create(pthread_t *new_thread,
+                        const pthread_attr_t *attr,
+		        void *(*start_routine)(void *), void *arg);
+  int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset);
+  int GC_pthread_join(pthread_t thread, void **retval);
+
+# define pthread_create GC_pthread_create
+# define pthread_sigmask GC_pthread_sigmask
+# define pthread_join GC_pthread_join
+# define dlopen GC_dlopen
+
+#endif /* xxxxx_THREADS */
+
+# if defined(PCR) || defined(SOLARIS_THREADS) || defined(WIN32_THREADS) || \
+	defined(IRIX_THREADS) || defined(LINUX_THREADS) || \
+	defined(IRIX_JDK_THREADS) || defined(HPUX_THREADS)
+   	/* Any flavor of threads except SRC_M3.	*/
+/* This returns a list of objects, linked through their first		*/
+/* word.  Its use can greatly reduce lock contention problems, since	*/
+/* the allocation lock can be acquired and released many fewer times.	*/
+/* lb must be large enough to hold the pointer field.			*/
+GC_PTR GC_malloc_many(size_t lb);
+#define GC_NEXT(p) (*(GC_PTR *)(p)) 	/* Retrieve the next element	*/
+					/* in returned list.		*/
+extern void GC_thr_init();	/* Needed for Solaris/X86	*/
+
+#endif /* THREADS && !SRC_M3 */
+
+/*
+ * If you are planning on putting
+ * the collector in a SunOS 5 dynamic library, you need to call GC_INIT()
+ * from the statically loaded program section.
+ * This circumvents a Solaris 2.X (X<=4) linker bug.
+ */
+#if defined(sparc) || defined(__sparc)
+#   define GC_INIT() { extern end, etext; \
+		       GC_noop(&end, &etext); }
+#else
+# if defined(__CYGWIN32__) && defined(GC_USE_DLL)
+    /*
+     * Similarly gnu-win32 DLLs need explicit initialization
+     */
+#   define GC_INIT() { GC_add_roots(DATASTART, DATAEND); }
+# else
+#   define GC_INIT()
+# endif
+#endif
+
+#if (defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300) \
+     || defined(_WIN32)
+  /* win32S may not free all resources on process exit.  */
+  /* This explicitly deallocates the heap.		 */
+    GC_API void GC_win32_free_heap ();
+#endif
+
+#ifdef __cplusplus
+    }  /* end of extern "C" */
+#endif
+
+#endif /* _GC_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/cord/private/cord_pos.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,118 @@
+/* 
+ * Copyright (c) 1993-1994 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+/* Boehm, May 19, 1994 2:23 pm PDT */
+# ifndef CORD_POSITION_H
+
+/* The representation of CORD_position.  This is private to the	*/
+/* implementation, but the size is known to clients.  Also	*/
+/* the implementation of some exported macros relies on it.	*/
+/* Don't use anything defined here and not in cord.h.		*/
+
+# define MAX_DEPTH 48
+	/* The maximum depth of a balanced cord + 1.		*/
+	/* We don't let cords get deeper than MAX_DEPTH.	*/
+
+struct CORD_pe {
+    CORD pe_cord;
+    size_t pe_start_pos;
+};
+
+/* A structure describing an entry on the path from the root 	*/
+/* to current position.						*/
+typedef struct CORD_Pos {
+    size_t cur_pos;
+    int path_len;
+#	define CORD_POS_INVALID (0x55555555)
+		/* path_len == INVALID <==> position invalid */
+    const char *cur_leaf;	/* Current leaf, if it is a string.	*/
+    				/* If the current leaf is a function,	*/
+    				/* then this may point to function_buf	*/
+    				/* containing the next few characters.	*/
+    				/* Always points to a valid string	*/
+    				/* containing the current character 	*/
+    				/* unless cur_end is 0.			*/
+    size_t cur_start;	/* Start position of cur_leaf	*/
+    size_t cur_end;	/* Ending position of cur_leaf	*/
+    			/* 0 if cur_leaf is invalid.	*/
+    struct CORD_pe path[MAX_DEPTH + 1];
+    	/* path[path_len] is the leaf corresponding to cur_pos	*/
+    	/* path[0].pe_cord is the cord we point to.		*/
+#   define FUNCTION_BUF_SZ 8
+    char function_buf[FUNCTION_BUF_SZ];	/* Space for next few chars	*/
+    					/* from function node.		*/
+} CORD_pos[1];
+
+/* Extract the cord from a position:	*/
+CORD CORD_pos_to_cord(CORD_pos p);
+	
+/* Extract the current index from a position:	*/
+size_t CORD_pos_to_index(CORD_pos p);
+	
+/* Fetch the character located at the given position:	*/
+char CORD_pos_fetch(CORD_pos p);
+	
+/* Initialize the position to refer to the give cord and index.	*/
+/* Note that this is the most expensive function on positions:	*/
+void CORD_set_pos(CORD_pos p, CORD x, size_t i);
+	
+/* Advance the position to the next character.	*/
+/* P must be initialized and valid.		*/
+/* Invalidates p if past end:			*/
+void CORD_next(CORD_pos p);
+
+/* Move the position to the preceding character.	*/
+/* P must be initialized and valid.			*/
+/* Invalidates p if past beginning:			*/
+void CORD_prev(CORD_pos p);
+	
+/* Is the position valid, i.e. inside the cord?		*/
+int CORD_pos_valid(CORD_pos p);
+
+char CORD__pos_fetch(CORD_pos);
+void CORD__next(CORD_pos);
+void CORD__prev(CORD_pos);
+
+#define CORD_pos_fetch(p)	\
+    (((p)[0].cur_end != 0)? \
+     	(p)[0].cur_leaf[(p)[0].cur_pos - (p)[0].cur_start] \
+     	: CORD__pos_fetch(p))
+
+#define CORD_next(p)	\
+    (((p)[0].cur_pos + 1 < (p)[0].cur_end)? \
+    	(p)[0].cur_pos++ \
+    	: (CORD__next(p), 0))
+
+#define CORD_prev(p)	\
+    (((p)[0].cur_end != 0 && (p)[0].cur_pos > (p)[0].cur_start)? \
+    	(p)[0].cur_pos-- \
+    	: (CORD__prev(p), 0))
+
+#define CORD_pos_to_index(p) ((p)[0].cur_pos)
+
+#define CORD_pos_to_cord(p) ((p)[0].path[0].pe_cord)
+
+#define CORD_pos_valid(p) ((p)[0].path_len != CORD_POS_INVALID)
+
+/* Some grubby stuff for performance-critical friends:	*/
+#define CORD_pos_chars_left(p) ((long)((p)[0].cur_end) - (long)((p)[0].cur_pos))
+	/* Number of characters in cache.  <= 0 ==> none	*/
+
+#define CORD_pos_advance(p,n) ((p)[0].cur_pos += (n) - 1, CORD_next(p))
+	/* Advance position by n characters	*/
+	/* 0 < n < CORD_pos_chars_left(p)	*/
+
+#define CORD_pos_cur_char_addr(p) \
+	(p)[0].cur_leaf + ((p)[0].cur_pos - (p)[0].cur_start)
+	/* address of current character in cache.	*/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/include/backptr.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,63 @@
+/*
+ * This is a simple API to implement pointer back tracing, i.e.
+ * to answer questions such as "who is pointing to this" or
+ * "why is this object being retained by the collector"
+ *
+ * This API assumes that we have an ANSI C compiler.
+ *
+ * Most of these calls yield useful information on only after
+ * a garbage collection.  Usually the client will first force
+ * a full collection and then gather information, preferably
+ * before much intervening allocation.
+ *
+ * The implementation of the interface is only about 99.9999%
+ * correct.  It is intended to be good enough for profiling,
+ * but is not intended to be used with production code.
+ *
+ * Results are likely to be much more useful if all allocation is
+ * accomplished through the debugging allocators.
+ *
+ * The implementation idea is due to A. Demers.
+ */
+
+/* Store information about the object referencing dest in *base_p     */
+/* and *offset_p.                                                     */
+/* If multiple objects or roots point to dest, the one reported	      */
+/* will be the last on used by the garbage collector to trace the     */
+/* object.							      */
+/*   source is root ==> *base_p = address, *offset_p = 0	      */
+/*   source is heap object ==> *base_p != 0, *offset_p = offset       */
+/*   Returns 1 on success, 0 if source couldn't be determined.        */
+/* Dest can be any address within a heap object.                      */
+typedef enum {  GC_UNREFERENCED, /* No reference info available.	*/
+		GC_NO_SPACE,	/* Dest not allocated with debug alloc  */
+		GC_REFD_FROM_ROOT, /* Referenced directly by root *base_p */
+		GC_REFD_FROM_REG,  /* Referenced from a register, i.e.	*/
+				   /* a root without an address.	*/
+		GC_REFD_FROM_HEAP, /* Referenced from another heap obj. */
+		GC_FINALIZER_REFD /* Finalizable and hence accessible.  */
+} GC_ref_kind;
+
+GC_ref_kind GC_get_back_ptr_info(void *dest, void **base_p, size_t *offset_p);
+
+/* Generate a random heap address.            */
+/* The resulting address is in the heap, but  */
+/* not necessarily inside a valid object.     */
+void * GC_generate_random_heap_address(void);
+
+/* Generate a random address inside a valid marked heap object. */
+void * GC_generate_random_valid_address(void);
+
+/* Force a garbage collection and generate a backtrace from a */
+/* random heap address.                                       */
+/* This uses the GC logging mechanism (GC_printf) to produce  */
+/* output.  It can often be called from a debugger.  The      */
+/* source in dbg_mlc.c also serves as a sample client.	      */
+void GC_generate_random_backtrace(void);
+
+/* Print a backtrace from a specific address.  Used by the 	*/
+/* above.  The client should call GC_gcollect() immediately	*/
+/* before invocation.						*/
+void GC_print_backtrace(void *);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/include/cord.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,327 @@
+/* 
+ * Copyright (c) 1993-1994 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ * Author: Hans-J. Boehm (boehm@parc.xerox.com)
+ */
+/* Boehm, October 5, 1995 4:20 pm PDT */
+ 
+/*
+ * Cords are immutable character strings.  A number of operations
+ * on long cords are much more efficient than their strings.h counterpart.
+ * In particular, concatenation takes constant time independent of the length
+ * of the arguments.  (Cords are represented as trees, with internal
+ * nodes representing concatenation and leaves consisting of either C
+ * strings or a functional description of the string.)
+ *
+ * The following are reasonable applications of cords.  They would perform
+ * unacceptably if C strings were used:
+ * - A compiler that produces assembly language output by repeatedly
+ *   concatenating instructions onto a cord representing the output file.
+ * - A text editor that converts the input file to a cord, and then
+ *   performs editing operations by producing a new cord representing
+ *   the file after echa character change (and keeping the old ones in an
+ *   edit history)
+ *
+ * For optimal performance, cords should be built by
+ * concatenating short sections.
+ * This interface is designed for maximum compatibility with C strings.
+ * ASCII NUL characters may be embedded in cords using CORD_from_fn.
+ * This is handled correctly, but CORD_to_char_star will produce a string
+ * with embedded NULs when given such a cord. 
+ *
+ * This interface is fairly big, largely for performance reasons.
+ * The most basic constants and functions:
+ *
+ * CORD - the type of a cord;
+ * CORD_EMPTY - empty cord;
+ * CORD_len(cord) - length of a cord;
+ * CORD_cat(cord1,cord2) - concatenation of two cords;
+ * CORD_substr(cord, start, len) - substring (or subcord);
+ * CORD_pos i;  CORD_FOR(i, cord) {  ... CORD_pos_fetch(i) ... } -
+ *    examine each character in a cord.  CORD_pos_fetch(i) is the char.
+ * CORD_fetch(int i) - Retrieve i'th character (slowly).
+ * CORD_cmp(cord1, cord2) - compare two cords.
+ * CORD_from_file(FILE * f) - turn a read-only file into a cord.
+ * CORD_to_char_star(cord) - convert to C string.
+ *   (Non-NULL C constant strings are cords.)
+ * CORD_printf (etc.) - cord version of printf. Use %r for cords.
+ */
+# ifndef CORD_H
+
+# define CORD_H
+# include <stddef.h>
+# include <stdio.h>
+/* Cords have type const char *.  This is cheating quite a bit, and not	*/
+/* 100% portable.  But it means that nonempty character string		*/
+/* constants may be used as cords directly, provided the string is	*/
+/* never modified in place.  The empty cord is represented by, and	*/
+/* can be written as, 0.						*/
+
+typedef const char * CORD;
+
+/* An empty cord is always represented as nil 	*/
+# define CORD_EMPTY 0
+
+/* Is a nonempty cord represented as a C string? */
+#define CORD_IS_STRING(s) (*(s) != '\0')
+
+/* Concatenate two cords.  If the arguments are C strings, they may 	*/
+/* not be subsequently altered.						*/
+CORD CORD_cat(CORD x, CORD y);
+
+/* Concatenate a cord and a C string with known length.  Except for the	*/
+/* empty string case, this is a special case of CORD_cat.  Since the	*/
+/* length is known, it can be faster.					*/
+/* The string y is shared with the resulting CORD.  Hence it should	*/
+/* not be altered by the caller.					*/
+CORD CORD_cat_char_star(CORD x, const char * y, size_t leny);
+
+/* Compute the length of a cord */
+size_t CORD_len(CORD x);
+
+/* Cords may be represented by functions defining the ith character */
+typedef char (* CORD_fn)(size_t i, void * client_data);
+
+/* Turn a functional description into a cord. 	*/
+CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len);
+
+/* Return the substring (subcord really) of x with length at most n,	*/
+/* starting at position i.  (The initial character has position 0.)	*/
+CORD CORD_substr(CORD x, size_t i, size_t n);
+
+/* Return the argument, but rebalanced to allow more efficient   	*/
+/* character retrieval, substring operations, and comparisons.		*/
+/* This is useful only for cords that were built using repeated 	*/
+/* concatenation.  Guarantees log time access to the result, unless	*/
+/* x was obtained through a large number of repeated substring ops	*/
+/* or the embedded functional descriptions take longer to evaluate.	*/
+/* May reallocate significant parts of the cord.  The argument is not	*/
+/* modified; only the result is balanced.				*/
+CORD CORD_balance(CORD x);
+
+/* The following traverse a cord by applying a function to each 	*/
+/* character.  This is occasionally appropriate, especially where	*/
+/* speed is crucial.  But, since C doesn't have nested functions,	*/
+/* clients of this sort of traversal are clumsy to write.  Consider	*/
+/* the functions that operate on cord positions instead.		*/
+
+/* Function to iteratively apply to individual characters in cord.	*/
+typedef int (* CORD_iter_fn)(char c, void * client_data);
+
+/* Function to apply to substrings of a cord.  Each substring is a 	*/
+/* a C character string, not a general cord.				*/
+typedef int (* CORD_batched_iter_fn)(const char * s, void * client_data);
+# define CORD_NO_FN ((CORD_batched_iter_fn)0)
+
+/* Apply f1 to each character in the cord, in ascending order,		*/
+/* starting at position i. If						*/
+/* f2 is not CORD_NO_FN, then multiple calls to f1 may be replaced by	*/
+/* a single call to f2.  The parameter f2 is provided only to allow	*/
+/* some optimization by the client.  This terminates when the right	*/
+/* end of this string is reached, or when f1 or f2 return != 0.  In the	*/
+/* latter case CORD_iter returns != 0.  Otherwise it returns 0.		*/
+/* The specified value of i must be < CORD_len(x).			*/
+int CORD_iter5(CORD x, size_t i, CORD_iter_fn f1,
+	       CORD_batched_iter_fn f2, void * client_data);
+
+/* A simpler version that starts at 0, and without f2:	*/
+int CORD_iter(CORD x, CORD_iter_fn f1, void * client_data);
+# define CORD_iter(x, f1, cd) CORD_iter5(x, 0, f1, CORD_NO_FN, cd)
+
+/* Similar to CORD_iter5, but end-to-beginning.	No provisions for	*/
+/* CORD_batched_iter_fn.						*/
+int CORD_riter4(CORD x, size_t i, CORD_iter_fn f1, void * client_data);
+
+/* A simpler version that starts at the end:	*/
+int CORD_riter(CORD x, CORD_iter_fn f1, void * client_data);
+
+/* Functions that operate on cord positions.  The easy way to traverse	*/
+/* cords.  A cord position is logically a pair consisting of a cord	*/
+/* and an index into that cord.  But it is much faster to retrieve a	*/
+/* charcter based on a position than on an index.  Unfortunately,	*/
+/* positions are big (order of a few 100 bytes), so allocate them with	*/
+/* caution.								*/
+/* Things in cord_pos.h should be treated as opaque, except as		*/
+/* described below.  Also note that					*/
+/* CORD_pos_fetch, CORD_next and CORD_prev have both macro and function	*/
+/* definitions.  The former may evaluate their argument more than once. */
+# include "private/cord_pos.h"
+
+/*
+	Visible definitions from above:
+	
+	typedef <OPAQUE but fairly big> CORD_pos[1];
+	
+	* Extract the cord from a position:
+	CORD CORD_pos_to_cord(CORD_pos p);
+	
+	* Extract the current index from a position:
+	size_t CORD_pos_to_index(CORD_pos p);
+	
+	* Fetch the character located at the given position:
+	char CORD_pos_fetch(CORD_pos p);
+	
+	* Initialize the position to refer to the given cord and index.
+	* Note that this is the most expensive function on positions:
+	void CORD_set_pos(CORD_pos p, CORD x, size_t i);
+	
+	* Advance the position to the next character.
+	* P must be initialized and valid.
+	* Invalidates p if past end:
+	void CORD_next(CORD_pos p);
+	
+	* Move the position to the preceding character.
+	* P must be initialized and valid.
+	* Invalidates p if past beginning:
+	void CORD_prev(CORD_pos p);
+	
+	* Is the position valid, i.e. inside the cord?
+	int CORD_pos_valid(CORD_pos p);
+*/
+# define CORD_FOR(pos, cord) \
+    for (CORD_set_pos(pos, cord, 0); CORD_pos_valid(pos); CORD_next(pos))
+
+			
+/* An out of memory handler to call.  May be supplied by client.	*/
+/* Must not return.							*/
+extern void (* CORD_oom_fn)(void);
+
+/* Dump the representation of x to stdout in an implementation defined	*/
+/* manner.  Intended for debugging only.				*/
+void CORD_dump(CORD x);
+
+/* The following could easily be implemented by the client.  They are	*/
+/* provided in cordxtra.c for convenience.				*/
+
+/* Concatenate a character to the end of a cord.	*/
+CORD CORD_cat_char(CORD x, char c);
+
+/* Concatenate n cords.	*/
+CORD CORD_catn(int n, /* CORD */ ...);
+
+/* Return the character in CORD_substr(x, i, 1)  	*/
+char CORD_fetch(CORD x, size_t i);
+
+/* Return < 0, 0, or > 0, depending on whether x < y, x = y, x > y	*/
+int CORD_cmp(CORD x, CORD y);
+
+/* A generalization that takes both starting positions for the 		*/
+/* comparison, and a limit on the number of characters to be compared.	*/
+int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start, size_t len);
+
+/* Find the first occurrence of s in x at position start or later.	*/
+/* Return the position of the first character of s in x, or		*/
+/* CORD_NOT_FOUND if there is none.					*/
+size_t CORD_str(CORD x, size_t start, CORD s);
+
+/* Return a cord consisting of i copies of (possibly NUL) c.  Dangerous	*/
+/* in conjunction with CORD_to_char_star.				*/
+/* The resulting representation takes constant space, independent of i.	*/
+CORD CORD_chars(char c, size_t i);
+# define CORD_nul(i) CORD_chars('\0', (i))
+
+/* Turn a file into cord.  The file must be seekable.  Its contents	*/
+/* must remain constant.  The file may be accessed as an immediate	*/
+/* result of this call and/or as a result of subsequent accesses to 	*/
+/* the cord.  Short files are likely to be immediately read, but	*/
+/* long files are likely to be read on demand, possibly relying on 	*/
+/* stdio for buffering.							*/
+/* We must have exclusive access to the descriptor f, i.e. we may	*/
+/* read it at any time, and expect the file pointer to be		*/
+/* where we left it.  Normally this should be invoked as		*/
+/* CORD_from_file(fopen(...))						*/
+/* CORD_from_file arranges to close the file descriptor when it is no	*/
+/* longer needed (e.g. when the result becomes inaccessible).		*/ 
+/* The file f must be such that ftell reflects the actual character	*/
+/* position in the file, i.e. the number of characters that can be 	*/
+/* or were read with fread.  On UNIX systems this is always true.  On	*/
+/* MS Windows systems, f must be opened in binary mode.			*/
+CORD CORD_from_file(FILE * f);
+
+/* Equivalent to the above, except that the entire file will be read	*/
+/* and the file pointer will be closed immediately.			*/
+/* The binary mode restriction from above does not apply.		*/
+CORD CORD_from_file_eager(FILE * f);
+
+/* Equivalent to the above, except that the file will be read on demand.*/
+/* The binary mode restriction applies.					*/
+CORD CORD_from_file_lazy(FILE * f);
+
+/* Turn a cord into a C string.	The result shares no structure with	*/
+/* x, and is thus modifiable.						*/
+char * CORD_to_char_star(CORD x);
+
+/* Turn a C string into a CORD.  The C string is copied, and so may	*/
+/* subsequently be modified.						*/
+CORD CORD_from_char_star(const char *s);
+
+/* Identical to the above, but the result may share structure with	*/
+/* the argument and is thus not modifiable.				*/
+const char * CORD_to_const_char_star(CORD x); 
+
+/* Write a cord to a file, starting at the current position.  No	*/
+/* trailing NULs are newlines are added.				*/
+/* Returns EOF if a write error occurs, 1 otherwise.			*/
+int CORD_put(CORD x, FILE * f);
+
+/* "Not found" result for the following two functions.			*/
+# define CORD_NOT_FOUND ((size_t)(-1))
+
+/* A vague analog of strchr.  Returns the position (an integer, not	*/
+/* a pointer) of the first occurrence of (char) c inside x at position 	*/
+/* i or later. The value i must be < CORD_len(x).			*/
+size_t CORD_chr(CORD x, size_t i, int c);
+
+/* A vague analog of strrchr.  Returns index of the last occurrence	*/
+/* of (char) c inside x at position i or earlier. The value i		*/
+/* must be < CORD_len(x).						*/
+size_t CORD_rchr(CORD x, size_t i, int c);
+
+
+/* The following are also not primitive, but are implemented in 	*/
+/* cordprnt.c.  They provide functionality similar to the ANSI C	*/
+/* functions with corresponding names, but with the following		*/
+/* additions and changes:						*/
+/* 1. A %r conversion specification specifies a CORD argument.  Field	*/
+/*    width, precision, etc. have the same semantics as for %s.		*/
+/*    (Note that %c,%C, and %S were already taken.)			*/
+/* 2. The format string is represented as a CORD.		        */
+/* 3. CORD_sprintf and CORD_vsprintf assign the result through the 1st	*/ 	/*    argument.	Unlike their ANSI C versions, there is no need to guess	*/
+/*    the correct buffer size.						*/
+/* 4. Most of the conversions are implement through the native 		*/
+/*    vsprintf.  Hence they are usually no faster, and 			*/
+/*    idiosyncracies of the native printf are preserved.  However,	*/
+/*    CORD arguments to CORD_sprintf and CORD_vsprintf are NOT copied;	*/
+/*    the result shares the original structure.  This may make them	*/
+/*    very efficient in some unusual applications.			*/
+/*    The format string is copied.					*/
+/* All functions return the number of characters generated or -1 on	*/
+/* error.  This complies with the ANSI standard, but is inconsistent	*/
+/* with some older implementations of sprintf.				*/
+
+/* The implementation of these is probably less portable than the rest	*/
+/* of this package.							*/
+
+#ifndef CORD_NO_IO
+
+#include <stdarg.h>
+
+int CORD_sprintf(CORD * out, CORD format, ...);
+int CORD_vsprintf(CORD * out, CORD format, va_list args);
+int CORD_fprintf(FILE * f, CORD format, ...);
+int CORD_vfprintf(FILE * f, CORD format, va_list args);
+int CORD_printf(CORD format, ...);
+int CORD_vprintf(CORD format, va_list args);
+
+#endif /* CORD_NO_IO */
+
+# endif /* CORD_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/include/ec.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,70 @@
+# ifndef EC_H
+# define EC_H
+
+# ifndef CORD_H
+#  include "cord.h"
+# endif
+
+/* Extensible cords are strings that may be destructively appended to.	*/
+/* They allow fast construction of cords from characters that are	*/
+/* being read from a stream.						*/
+/*
+ * A client might look like:
+ *
+ *	{
+ *	    CORD_ec x;
+ *	    CORD result;
+ *	    char c;
+ *	    FILE *f;
+ *
+ *	    ...
+ *	    CORD_ec_init(x);
+ *	    while(...) {
+ *		c = getc(f);
+ *		...
+ *		CORD_ec_append(x, c);
+ *	    }
+ *	    result = CORD_balance(CORD_ec_to_cord(x));
+ *
+ * If a C string is desired as the final result, the call to CORD_balance
+ * may be replaced by a call to CORD_to_char_star.
+ */
+
+# ifndef CORD_BUFSZ
+#   define CORD_BUFSZ 128
+# endif
+
+typedef struct CORD_ec_struct {
+    CORD ec_cord;
+    char * ec_bufptr;
+    char ec_buf[CORD_BUFSZ+1];
+} CORD_ec[1];
+
+/* This structure represents the concatenation of ec_cord with		*/
+/* ec_buf[0 ... (ec_bufptr-ec_buf-1)]					*/
+
+/* Flush the buffer part of the extended chord into ec_cord.	*/
+/* Note that this is almost the only real function, and it is	*/
+/* implemented in 6 lines in cordxtra.c				*/
+void CORD_ec_flush_buf(CORD_ec x);
+      
+/* Convert an extensible cord to a cord. */
+# define CORD_ec_to_cord(x) (CORD_ec_flush_buf(x), (x)[0].ec_cord)
+
+/* Initialize an extensible cord. */
+# define CORD_ec_init(x) ((x)[0].ec_cord = 0, (x)[0].ec_bufptr = (x)[0].ec_buf)
+
+/* Append a character to an extensible cord.	*/
+# define CORD_ec_append(x, c) \
+    {  \
+	if ((x)[0].ec_bufptr == (x)[0].ec_buf + CORD_BUFSZ) { \
+	  	CORD_ec_flush_buf(x); \
+	} \
+	*((x)[0].ec_bufptr)++ = (c); \
+    }
+
+/* Append a cord to an extensible cord.  Structure remains shared with 	*/
+/* original.								*/
+void CORD_ec_append_cord(CORD_ec x, CORD s);
+
+# endif /* EC_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/include/gc.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,804 @@
+/* 
+ * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
+ * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.
+ * Copyright 1996-1999 by Silicon Graphics.  All rights reserved.
+ * Copyright 1999 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+/*
+ * Note that this defines a large number of tuning hooks, which can
+ * safely be ignored in nearly all cases.  For normal use it suffices
+ * to call only GC_MALLOC and perhaps GC_REALLOC.
+ * For better performance, also look at GC_MALLOC_ATOMIC, and
+ * GC_enable_incremental.  If you need an action to be performed
+ * immediately before an object is collected, look at GC_register_finalizer.
+ * If you are using Solaris threads, look at the end of this file.
+ * Everything else is best ignored unless you encounter performance
+ * problems.
+ */
+ 
+#ifndef _GC_H
+
+# define _GC_H
+# define __GC
+# include <stddef.h>
+
+#if defined(__CYGWIN32__) && defined(GC_USE_DLL)
+#include "libgc_globals.h"
+#endif
+
+#if defined(__MINGW32__) && defined(WIN32_THREADS)
+# ifdef GC_BUILD
+#   define GC_API __declspec(dllexport)
+# else
+#   define GC_API __declspec(dllimport)
+# endif
+#endif
+
+#if defined(_MSC_VER) && defined(_DLL)
+# ifdef GC_BUILD
+#   define GC_API __declspec(dllexport)
+# else
+#   define GC_API __declspec(dllimport)
+# endif
+#endif
+
+#if defined(__WATCOMC__) && defined(GC_DLL)
+# ifdef GC_BUILD
+#   define GC_API extern __declspec(dllexport)
+# else
+#   define GC_API extern __declspec(dllimport)
+# endif
+#endif
+
+#ifndef GC_API
+#define GC_API extern
+#endif
+
+# if defined(__STDC__) || defined(__cplusplus)
+#   define GC_PROTO(args) args
+    typedef void * GC_PTR;
+#   define GC_CONST const
+# else
+#   define GC_PROTO(args) ()
+    typedef char * GC_PTR;
+#   define GC_CONST
+#  endif
+
+# ifdef __cplusplus
+    extern "C" {
+# endif
+
+
+/* Define word and signed_word to be unsigned and signed types of the 	*/
+/* size as char * or void *.  There seems to be no way to do this	*/
+/* even semi-portably.  The following is probably no better/worse 	*/
+/* than almost anything else.						*/
+/* The ANSI standard suggests that size_t and ptr_diff_t might be 	*/
+/* better choices.  But those appear to have incorrect definitions	*/
+/* on may systems.  Notably "typedef int size_t" seems to be both	*/
+/* frequent and WRONG.							*/
+typedef unsigned long GC_word;
+typedef long GC_signed_word;
+
+/* Public read-only variables */
+
+GC_API GC_word GC_gc_no;/* Counter incremented per collection.  	*/
+			/* Includes empty GCs at startup.		*/
+			
+
+/* Public R/W variables */
+
+GC_API GC_PTR (*GC_oom_fn) GC_PROTO((size_t bytes_requested));
+			/* When there is insufficient memory to satisfy */
+			/* an allocation request, we return		*/
+			/* (*GC_oom_fn)().  By default this just	*/
+			/* returns 0.					*/
+			/* If it returns, it must return 0 or a valid	*/
+			/* pointer to a previously allocated heap 	*/
+			/* object.					*/
+
+GC_API int GC_find_leak;
+			/* Do not actually garbage collect, but simply	*/
+			/* report inaccessible memory that was not	*/
+			/* deallocated with GC_free.  Initial value	*/
+			/* is determined by FIND_LEAK macro.		*/
+
+GC_API int GC_quiet;	/* Disable statistics output.  Only matters if	*/
+			/* collector has been compiled with statistics	*/
+			/* enabled.  This involves a performance cost,	*/
+			/* and is thus not the default.			*/
+
+GC_API int GC_finalize_on_demand;
+			/* If nonzero, finalizers will only be run in 	*/
+			/* response to an eplit GC_invoke_finalizers	*/
+			/* call.  The default is determined by whether	*/
+			/* the FINALIZE_ON_DEMAND macro is defined	*/
+			/* when the collector is built.			*/
+
+GC_API int GC_java_finalization;
+			/* Mark objects reachable from finalizable 	*/
+			/* objects in a separate postpass.  This makes	*/
+			/* it a bit safer to use non-topologically-	*/
+			/* ordered finalization.  Default value is	*/
+			/* determined by JAVA_FINALIZATION macro.	*/
+
+GC_API int GC_dont_gc;	/* Dont collect unless explicitly requested, e.g. */
+			/* because it's not safe.			  */
+
+GC_API int GC_dont_expand;
+			/* Dont expand heap unless explicitly requested */
+			/* or forced to.				*/
+
+GC_API int GC_use_entire_heap;
+		/* Causes the nonincremental collector to use the	*/
+		/* entire heap before collecting.  This was the only 	*/
+		/* option for GC versions < 5.0.  This sometimes	*/
+		/* results in more large block fragmentation, since	*/
+		/* very larg blocks will tend to get broken up		*/
+		/* during each GC cycle.  It is likely to result in a	*/
+		/* larger working set, but lower collection		*/
+		/* frequencies, and hence fewer instructions executed	*/
+		/* in the collector.					*/
+
+GC_API int GC_full_freq;    /* Number of partial collections between	*/
+			    /* full collections.  Matters only if	*/
+			    /* GC_incremental is set.			*/
+			    /* Full collections are also triggered if	*/
+			    /* the collector detects a substantial	*/
+			    /* increase in the number of in-use heap	*/
+			    /* blocks.  Values in the tens are now	*/
+			    /* perfectly reasonable, unlike for		*/
+			    /* earlier GC versions.			*/
+			
+GC_API GC_word GC_non_gc_bytes;
+			/* Bytes not considered candidates for collection. */
+			/* Used only to control scheduling of collections. */
+
+GC_API GC_word GC_free_space_divisor;
+			/* We try to make sure that we allocate at 	*/
+			/* least N/GC_free_space_divisor bytes between	*/
+			/* collections, where N is the heap size plus	*/
+			/* a rough estimate of the root set size.	*/
+			/* Initially, GC_free_space_divisor = 4.	*/
+			/* Increasing its value will use less space	*/
+			/* but more collection time.  Decreasing it	*/
+			/* will appreciably decrease collection time	*/
+			/* at the expense of space.			*/
+			/* GC_free_space_divisor = 1 will effectively	*/
+			/* disable collections.				*/
+
+GC_API GC_word GC_max_retries;
+			/* The maximum number of GCs attempted before	*/
+			/* reporting out of memory after heap		*/
+			/* expansion fails.  Initially 0.		*/
+			
+
+GC_API char *GC_stackbottom;	/* Cool end of user stack.		*/
+				/* May be set in the client prior to	*/
+				/* calling any GC_ routines.  This	*/
+				/* avoids some overhead, and 		*/
+				/* potentially some signals that can 	*/
+				/* confuse debuggers.  Otherwise the	*/
+				/* collector attempts to set it 	*/
+				/* automatically.			*/
+				/* For multithreaded code, this is the	*/
+				/* cold end of the stack for the	*/
+				/* primordial thread.			*/
+				
+/* Public procedures */
+/*
+ * general purpose allocation routines, with roughly malloc calling conv.
+ * The atomic versions promise that no relevant pointers are contained
+ * in the object.  The nonatomic versions guarantee that the new object
+ * is cleared.  GC_malloc_stubborn promises that no changes to the object
+ * will occur after GC_end_stubborn_change has been called on the
+ * result of GC_malloc_stubborn. GC_malloc_uncollectable allocates an object
+ * that is scanned for pointers to collectable objects, but is not itself
+ * collectable.  GC_malloc_uncollectable and GC_free called on the resulting
+ * object implicitly update GC_non_gc_bytes appropriately.
+ */
+GC_API GC_PTR GC_malloc GC_PROTO((size_t size_in_bytes));
+GC_API GC_PTR GC_malloc_atomic GC_PROTO((size_t size_in_bytes));
+GC_API GC_PTR GC_malloc_uncollectable GC_PROTO((size_t size_in_bytes));
+GC_API GC_PTR GC_malloc_stubborn GC_PROTO((size_t size_in_bytes));
+
+/* The following is only defined if the library has been suitably	*/
+/* compiled:								*/
+GC_API GC_PTR GC_malloc_atomic_uncollectable GC_PROTO((size_t size_in_bytes));
+
+/* Explicitly deallocate an object.  Dangerous if used incorrectly.     */
+/* Requires a pointer to the base of an object.				*/
+/* If the argument is stubborn, it should not be changeable when freed. */
+/* An object should not be enable for finalization when it is 		*/
+/* explicitly deallocated.						*/
+/* GC_free(0) is a no-op, as required by ANSI C for free.		*/
+GC_API void GC_free GC_PROTO((GC_PTR object_addr));
+
+/*
+ * Stubborn objects may be changed only if the collector is explicitly informed.
+ * The collector is implicitly informed of coming change when such
+ * an object is first allocated.  The following routines inform the
+ * collector that an object will no longer be changed, or that it will
+ * once again be changed.  Only nonNIL pointer stores into the object
+ * are considered to be changes.  The argument to GC_end_stubborn_change
+ * must be exacly the value returned by GC_malloc_stubborn or passed to
+ * GC_change_stubborn.  (In the second case it may be an interior pointer
+ * within 512 bytes of the beginning of the objects.)
+ * There is a performance penalty for allowing more than
+ * one stubborn object to be changed at once, but it is acceptable to
+ * do so.  The same applies to dropping stubborn objects that are still
+ * changeable.
+ */
+GC_API void GC_change_stubborn GC_PROTO((GC_PTR));
+GC_API void GC_end_stubborn_change GC_PROTO((GC_PTR));
+
+/* Return a pointer to the base (lowest address) of an object given	*/
+/* a pointer to a location within the object.				*/
+/* Return 0 if displaced_pointer doesn't point to within a valid	*/
+/* object.								*/
+GC_API GC_PTR GC_base GC_PROTO((GC_PTR displaced_pointer));
+
+/* Given a pointer to the base of an object, return its size in bytes.	*/
+/* The returned size may be slightly larger than what was originally	*/
+/* requested.								*/
+GC_API size_t GC_size GC_PROTO((GC_PTR object_addr));
+
+/* For compatibility with C library.  This is occasionally faster than	*/
+/* a malloc followed by a bcopy.  But if you rely on that, either here	*/
+/* or with the standard C library, your code is broken.  In my		*/
+/* opinion, it shouldn't have been invented, but now we're stuck. -HB	*/
+/* The resulting object has the same kind as the original.		*/
+/* If the argument is stubborn, the result will have changes enabled.	*/
+/* It is an error to have changes enabled for the original object.	*/
+/* Follows ANSI comventions for NULL old_object.			*/
+GC_API GC_PTR GC_realloc
+	GC_PROTO((GC_PTR old_object, size_t new_size_in_bytes));
+				   
+/* Explicitly increase the heap size.	*/
+/* Returns 0 on failure, 1 on success.  */
+GC_API int GC_expand_hp GC_PROTO((size_t number_of_bytes));
+
+/* Limit the heap size to n bytes.  Useful when you're debugging, 	*/
+/* especially on systems that don't handle running out of memory well.	*/
+/* n == 0 ==> unbounded.  This is the default.				*/
+GC_API void GC_set_max_heap_size GC_PROTO((GC_word n));
+
+/* Inform the collector that a certain section of statically allocated	*/
+/* memory contains no pointers to garbage collected memory.  Thus it 	*/
+/* need not be scanned.  This is sometimes important if the application */
+/* maps large read/write files into the address space, which could be	*/
+/* mistaken for dynamic library data segments on some systems.		*/
+GC_API void GC_exclude_static_roots GC_PROTO((GC_PTR start, GC_PTR finish));
+
+/* Clear the set of root segments.  Wizards only. */
+GC_API void GC_clear_roots GC_PROTO((void));
+
+/* Add a root segment.  Wizards only. */
+GC_API void GC_add_roots GC_PROTO((char * low_address,
+				   char * high_address_plus_1));
+
+/* Add a displacement to the set of those considered valid by the	*/
+/* collector.  GC_register_displacement(n) means that if p was returned */
+/* by GC_malloc, then (char *)p + n will be considered to be a valid	*/
+/* pointer to n.  N must be small and less than the size of p.		*/
+/* (All pointers to the interior of objects from the stack are		*/
+/* considered valid in any case.  This applies to heap objects and	*/
+/* static data.)							*/
+/* Preferably, this should be called before any other GC procedures.	*/
+/* Calling it later adds to the probability of excess memory		*/
+/* retention.								*/
+/* This is a no-op if the collector was compiled with recognition of	*/
+/* arbitrary interior pointers enabled, which is now the default.	*/
+GC_API void GC_register_displacement GC_PROTO((GC_word n));
+
+/* The following version should be used if any debugging allocation is	*/
+/* being done.								*/
+GC_API void GC_debug_register_displacement GC_PROTO((GC_word n));
+
+/* Explicitly trigger a full, world-stop collection. 	*/
+GC_API void GC_gcollect GC_PROTO((void));
+
+/* Trigger a full world-stopped collection.  Abort the collection if 	*/
+/* and when stop_func returns a nonzero value.  Stop_func will be 	*/
+/* called frequently, and should be reasonably fast.  This works even	*/
+/* if virtual dirty bits, and hence incremental collection is not 	*/
+/* available for this architecture.  Collections can be aborted faster	*/
+/* than normal pause times for incremental collection.  However,	*/
+/* aborted collections do no useful work; the next collection needs	*/
+/* to start from the beginning.						*/
+/* Return 0 if the collection was aborted, 1 if it succeeded.		*/
+typedef int (* GC_stop_func) GC_PROTO((void));
+GC_API int GC_try_to_collect GC_PROTO((GC_stop_func stop_func));
+
+/* Return the number of bytes in the heap.  Excludes collector private	*/
+/* data structures.  Includes empty blocks and fragmentation loss.	*/
+/* Includes some pages that were allocated but never written.		*/
+GC_API size_t GC_get_heap_size GC_PROTO((void));
+
+/* Return a lower bound on the number of free bytes in the heap.	*/
+GC_API size_t GC_get_free_bytes GC_PROTO((void));
+
+/* Return the number of bytes allocated since the last collection.	*/
+GC_API size_t GC_get_bytes_since_gc GC_PROTO((void));
+
+/* Enable incremental/generational collection.	*/
+/* Not advisable unless dirty bits are 		*/
+/* available or most heap objects are		*/
+/* pointerfree(atomic) or immutable.		*/
+/* Don't use in leak finding mode.		*/
+/* Ignored if GC_dont_gc is true.		*/
+GC_API void GC_enable_incremental GC_PROTO((void));
+
+/* Perform some garbage collection work, if appropriate.	*/
+/* Return 0 if there is no more work to be done.		*/
+/* Typically performs an amount of work corresponding roughly	*/
+/* to marking from one page.  May do more work if further	*/
+/* progress requires it, e.g. if incremental collection is	*/
+/* disabled.  It is reasonable to call this in a wait loop	*/
+/* until it returns 0.						*/
+GC_API int GC_collect_a_little GC_PROTO((void));
+
+/* Allocate an object of size lb bytes.  The client guarantees that	*/
+/* as long as the object is live, it will be referenced by a pointer	*/
+/* that points to somewhere within the first 256 bytes of the object.	*/
+/* (This should normally be declared volatile to prevent the compiler	*/
+/* from invalidating this assertion.)  This routine is only useful	*/
+/* if a large array is being allocated.  It reduces the chance of 	*/
+/* accidentally retaining such an array as a result of scanning an	*/
+/* integer that happens to be an address inside the array.  (Actually,	*/
+/* it reduces the chance of the allocator not finding space for such	*/
+/* an array, since it will try hard to avoid introducing such a false	*/
+/* reference.)  On a SunOS 4.X or MS Windows system this is recommended */
+/* for arrays likely to be larger than 100K or so.  For other systems,	*/
+/* or if the collector is not configured to recognize all interior	*/
+/* pointers, the threshold is normally much higher.			*/
+GC_API GC_PTR GC_malloc_ignore_off_page GC_PROTO((size_t lb));
+GC_API GC_PTR GC_malloc_atomic_ignore_off_page GC_PROTO((size_t lb));
+
+#if defined(__sgi) && !defined(__GNUC__) && _COMPILER_VERSION >= 720
+#   define GC_ADD_CALLER
+#   define GC_RETURN_ADDR (GC_word)__return_address
+#endif
+
+#ifdef GC_ADD_CALLER
+#  define GC_EXTRAS GC_RETURN_ADDR, __FILE__, __LINE__
+#  define GC_EXTRA_PARAMS GC_word ra, GC_CONST char * s, int i
+#else
+#  define GC_EXTRAS __FILE__, __LINE__
+#  define GC_EXTRA_PARAMS GC_CONST char * s, int i
+#endif
+
+/* Debugging (annotated) allocation.  GC_gcollect will check 		*/
+/* objects allocated in this way for overwrites, etc.			*/
+GC_API GC_PTR GC_debug_malloc
+	GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
+GC_API GC_PTR GC_debug_malloc_atomic
+	GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
+GC_API GC_PTR GC_debug_malloc_uncollectable
+	GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
+GC_API GC_PTR GC_debug_malloc_stubborn
+	GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
+GC_API void GC_debug_free GC_PROTO((GC_PTR object_addr));
+GC_API GC_PTR GC_debug_realloc
+	GC_PROTO((GC_PTR old_object, size_t new_size_in_bytes,
+  		  GC_EXTRA_PARAMS));
+  			 	 
+GC_API void GC_debug_change_stubborn GC_PROTO((GC_PTR));
+GC_API void GC_debug_end_stubborn_change GC_PROTO((GC_PTR));
+# ifdef GC_DEBUG
+#   define GC_MALLOC(sz) GC_debug_malloc(sz, GC_EXTRAS)
+#   define GC_MALLOC_ATOMIC(sz) GC_debug_malloc_atomic(sz, GC_EXTRAS)
+#   define GC_MALLOC_UNCOLLECTABLE(sz) GC_debug_malloc_uncollectable(sz, \
+							GC_EXTRAS)
+#   define GC_REALLOC(old, sz) GC_debug_realloc(old, sz, GC_EXTRAS)
+#   define GC_FREE(p) GC_debug_free(p)
+#   define GC_REGISTER_FINALIZER(p, f, d, of, od) \
+	GC_debug_register_finalizer(p, f, d, of, od)
+#   define GC_REGISTER_FINALIZER_IGNORE_SELF(p, f, d, of, od) \
+	GC_debug_register_finalizer_ignore_self(p, f, d, of, od)
+#   define GC_REGISTER_FINALIZER_NO_ORDER(p, f, d, of, od) \
+	GC_debug_register_finalizer_no_order(p, f, d, of, od)
+#   define GC_MALLOC_STUBBORN(sz) GC_debug_malloc_stubborn(sz, GC_EXTRAS);
+#   define GC_CHANGE_STUBBORN(p) GC_debug_change_stubborn(p)
+#   define GC_END_STUBBORN_CHANGE(p) GC_debug_end_stubborn_change(p)
+#   define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \
+	GC_general_register_disappearing_link(link, GC_base(obj))
+#   define GC_REGISTER_DISPLACEMENT(n) GC_debug_register_displacement(n)
+# else
+#   define GC_MALLOC(sz) GC_malloc(sz)
+#   define GC_MALLOC_ATOMIC(sz) GC_malloc_atomic(sz)
+#   define GC_MALLOC_UNCOLLECTABLE(sz) GC_malloc_uncollectable(sz)
+#   define GC_REALLOC(old, sz) GC_realloc(old, sz)
+#   define GC_FREE(p) GC_free(p)
+#   define GC_REGISTER_FINALIZER(p, f, d, of, od) \
+	GC_register_finalizer(p, f, d, of, od)
+#   define GC_REGISTER_FINALIZER_IGNORE_SELF(p, f, d, of, od) \
+	GC_register_finalizer_ignore_self(p, f, d, of, od)
+#   define GC_REGISTER_FINALIZER_NO_ORDER(p, f, d, of, od) \
+	GC_register_finalizer_no_order(p, f, d, of, od)
+#   define GC_MALLOC_STUBBORN(sz) GC_malloc_stubborn(sz)
+#   define GC_CHANGE_STUBBORN(p) GC_change_stubborn(p)
+#   define GC_END_STUBBORN_CHANGE(p) GC_end_stubborn_change(p)
+#   define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \
+	GC_general_register_disappearing_link(link, obj)
+#   define GC_REGISTER_DISPLACEMENT(n) GC_register_displacement(n)
+# endif
+/* The following are included because they are often convenient, and	*/
+/* reduce the chance for a misspecifed size argument.  But calls may	*/
+/* expand to something syntactically incorrect if t is a complicated	*/
+/* type expression.  							*/
+# define GC_NEW(t) (t *)GC_MALLOC(sizeof (t))
+# define GC_NEW_ATOMIC(t) (t *)GC_MALLOC_ATOMIC(sizeof (t))
+# define GC_NEW_STUBBORN(t) (t *)GC_MALLOC_STUBBORN(sizeof (t))
+# define GC_NEW_UNCOLLECTABLE(t) (t *)GC_MALLOC_UNCOLLECTABLE(sizeof (t))
+
+/* Finalization.  Some of these primitives are grossly unsafe.		*/
+/* The idea is to make them both cheap, and sufficient to build		*/
+/* a safer layer, closer to PCedar finalization.			*/
+/* The interface represents my conclusions from a long discussion	*/
+/* with Alan Demers, Dan Greene, Carl Hauser, Barry Hayes, 		*/
+/* Christian Jacobi, and Russ Atkinson.  It's not perfect, and		*/
+/* probably nobody else agrees with it.	    Hans-J. Boehm  3/13/92	*/
+typedef void (*GC_finalization_proc)
+  	GC_PROTO((GC_PTR obj, GC_PTR client_data));
+
+GC_API void GC_register_finalizer
+    	GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
+		  GC_finalization_proc *ofn, GC_PTR *ocd));
+GC_API void GC_debug_register_finalizer
+    	GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
+		  GC_finalization_proc *ofn, GC_PTR *ocd));
+	/* When obj is no longer accessible, invoke		*/
+	/* (*fn)(obj, cd).  If a and b are inaccessible, and	*/
+	/* a points to b (after disappearing links have been	*/
+	/* made to disappear), then only a will be		*/
+	/* finalized.  (If this does not create any new		*/
+	/* pointers to b, then b will be finalized after the	*/
+	/* next collection.)  Any finalizable object that	*/
+	/* is reachable from itself by following one or more	*/
+	/* pointers will not be finalized (or collected).	*/
+	/* Thus cycles involving finalizable objects should	*/
+	/* be avoided, or broken by disappearing links.		*/
+	/* All but the last finalizer registered for an object  */
+	/* is ignored.						*/
+	/* Finalization may be removed by passing 0 as fn.	*/
+	/* Finalizers are implicitly unregistered just before   */
+	/* they are invoked.					*/
+	/* The old finalizer and client data are stored in	*/
+	/* *ofn and *ocd.					*/ 
+	/* Fn is never invoked on an accessible object,		*/
+	/* provided hidden pointers are converted to real 	*/
+	/* pointers only if the allocation lock is held, and	*/
+	/* such conversions are not performed by finalization	*/
+	/* routines.						*/
+	/* If GC_register_finalizer is aborted as a result of	*/
+	/* a signal, the object may be left with no		*/
+	/* finalization, even if neither the old nor new	*/
+	/* finalizer were NULL.					*/
+	/* Obj should be the nonNULL starting address of an 	*/
+	/* object allocated by GC_malloc or friends.		*/
+	/* Note that any garbage collectable object referenced	*/
+	/* by cd will be considered accessible until the	*/
+	/* finalizer is invoked.				*/
+
+/* Another versions of the above follow.  It ignores		*/
+/* self-cycles, i.e. pointers from a finalizable object to	*/
+/* itself.  There is a stylistic argument that this is wrong,	*/
+/* but it's unavoidable for C++, since the compiler may		*/
+/* silently introduce these.  It's also benign in that specific	*/
+/* case.							*/
+GC_API void GC_register_finalizer_ignore_self
+	GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
+		  GC_finalization_proc *ofn, GC_PTR *ocd));
+GC_API void GC_debug_register_finalizer_ignore_self
+	GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
+		  GC_finalization_proc *ofn, GC_PTR *ocd));
+
+/* Another version of the above.  It ignores all cycles.        */
+/* It should probably only be used by Java implementations.      */
+GC_API void GC_register_finalizer_no_order
+	GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
+		  GC_finalization_proc *ofn, GC_PTR *ocd));
+GC_API void GC_debug_register_finalizer_no_order
+	GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
+		  GC_finalization_proc *ofn, GC_PTR *ocd));
+
+
+/* The following routine may be used to break cycles between	*/
+/* finalizable objects, thus causing cyclic finalizable		*/
+/* objects to be finalized in the correct order.  Standard	*/
+/* use involves calling GC_register_disappearing_link(&p),	*/
+/* where p is a pointer that is not followed by finalization	*/
+/* code, and should not be considered in determining 		*/
+/* finalization order.						*/
+GC_API int GC_register_disappearing_link GC_PROTO((GC_PTR * /* link */));
+	/* Link should point to a field of a heap allocated 	*/
+	/* object obj.  *link will be cleared when obj is	*/
+	/* found to be inaccessible.  This happens BEFORE any	*/
+	/* finalization code is invoked, and BEFORE any		*/
+	/* decisions about finalization order are made.		*/
+	/* This is useful in telling the finalizer that 	*/
+	/* some pointers are not essential for proper		*/
+	/* finalization.  This may avoid finalization cycles.	*/
+	/* Note that obj may be resurrected by another		*/
+	/* finalizer, and thus the clearing of *link may	*/
+	/* be visible to non-finalization code.  		*/
+	/* There's an argument that an arbitrary action should  */
+	/* be allowed here, instead of just clearing a pointer. */
+	/* But this causes problems if that action alters, or 	*/
+	/* examines connectivity.				*/
+	/* Returns 1 if link was already registered, 0		*/
+	/* otherwise.						*/
+	/* Only exists for backward compatibility.  See below:	*/
+	
+GC_API int GC_general_register_disappearing_link
+	GC_PROTO((GC_PTR * /* link */, GC_PTR obj));
+	/* A slight generalization of the above. *link is	*/
+	/* cleared when obj first becomes inaccessible.  This	*/
+	/* can be used to implement weak pointers easily and	*/
+	/* safely. Typically link will point to a location	*/
+	/* holding a disguised pointer to obj.  (A pointer 	*/
+	/* inside an "atomic" object is effectively  		*/
+	/* disguised.)   In this way soft			*/
+	/* pointers are broken before any object		*/
+	/* reachable from them are finalized.  Each link	*/
+	/* May be registered only once, i.e. with one obj	*/
+	/* value.  This was added after a long email discussion */
+	/* with John Ellis.					*/
+	/* Obj must be a pointer to the first word of an object */
+	/* we allocated.  It is unsafe to explicitly deallocate */
+	/* the object containing link.  Explicitly deallocating */
+	/* obj may or may not cause link to eventually be	*/
+	/* cleared.						*/
+GC_API int GC_unregister_disappearing_link GC_PROTO((GC_PTR * /* link */));
+	/* Returns 0 if link was not actually registered.	*/
+	/* Undoes a registration by either of the above two	*/
+	/* routines.						*/
+
+/* Auxiliary fns to make finalization work correctly with displaced	*/
+/* pointers introduced by the debugging allocators.			*/
+GC_API GC_PTR GC_make_closure GC_PROTO((GC_finalization_proc fn, GC_PTR data));
+GC_API void GC_debug_invoke_finalizer GC_PROTO((GC_PTR obj, GC_PTR data));
+
+/* Returns !=0  if GC_invoke_finalizers has something to do. 		*/
+GC_API int GC_should_invoke_finalizers GC_PROTO((void));
+
+GC_API int GC_invoke_finalizers GC_PROTO((void));
+	/* Run finalizers for all objects that are ready to	*/
+	/* be finalized.  Return the number of finalizers	*/
+	/* that were run.  Normally this is also called		*/
+	/* implicitly during some allocations.	If		*/
+	/* GC-finalize_on_demand is nonzero, it must be called	*/
+	/* explicitly.						*/
+
+/* GC_set_warn_proc can be used to redirect or filter warning messages.	*/
+/* p may not be a NULL pointer.						*/
+typedef void (*GC_warn_proc) GC_PROTO((char *msg, GC_word arg));
+GC_API GC_warn_proc GC_set_warn_proc GC_PROTO((GC_warn_proc p));
+    /* Returns old warning procedure.	*/
+	
+/* The following is intended to be used by a higher level	*/
+/* (e.g. cedar-like) finalization facility.  It is expected	*/
+/* that finalization code will arrange for hidden pointers to	*/
+/* disappear.  Otherwise objects can be accessed after they	*/
+/* have been collected.						*/
+/* Note that putting pointers in atomic objects or in 		*/
+/* nonpointer slots of "typed" objects is equivalent to 	*/
+/* disguising them in this way, and may have other advantages.	*/
+# if defined(I_HIDE_POINTERS) || defined(GC_I_HIDE_POINTERS)
+    typedef GC_word GC_hidden_pointer;
+#   define HIDE_POINTER(p) (~(GC_hidden_pointer)(p))
+#   define REVEAL_POINTER(p) ((GC_PTR)(HIDE_POINTER(p)))
+    /* Converting a hidden pointer to a real pointer requires verifying	*/
+    /* that the object still exists.  This involves acquiring the  	*/
+    /* allocator lock to avoid a race with the collector.		*/
+# endif /* I_HIDE_POINTERS */
+
+typedef GC_PTR (*GC_fn_type) GC_PROTO((GC_PTR client_data));
+GC_API GC_PTR GC_call_with_alloc_lock
+        	GC_PROTO((GC_fn_type fn, GC_PTR client_data));
+
+/* Check that p and q point to the same object.  		*/
+/* Fail conspicuously if they don't.				*/
+/* Returns the first argument.  				*/
+/* Succeeds if neither p nor q points to the heap.		*/
+/* May succeed if both p and q point to between heap objects.	*/
+GC_API GC_PTR GC_same_obj GC_PROTO((GC_PTR p, GC_PTR q));
+
+/* Checked pointer pre- and post- increment operations.  Note that	*/
+/* the second argument is in units of bytes, not multiples of the	*/
+/* object size.  This should either be invoked from a macro, or the	*/
+/* call should be automatically generated.				*/
+GC_API GC_PTR GC_pre_incr GC_PROTO((GC_PTR *p, size_t how_much));
+GC_API GC_PTR GC_post_incr GC_PROTO((GC_PTR *p, size_t how_much));
+
+/* Check that p is visible						*/
+/* to the collector as a possibly pointer containing location.		*/
+/* If it isn't fail conspicuously.					*/
+/* Returns the argument in all cases.  May erroneously succeed		*/
+/* in hard cases.  (This is intended for debugging use with		*/
+/* untyped allocations.  The idea is that it should be possible, though	*/
+/* slow, to add such a call to all indirect pointer stores.)		*/
+/* Currently useless for multithreaded worlds.				*/
+GC_API GC_PTR GC_is_visible GC_PROTO((GC_PTR p));
+
+/* Check that if p is a pointer to a heap page, then it points to	*/
+/* a valid displacement within a heap object.				*/
+/* Fail conspicuously if this property does not hold.			*/
+/* Uninteresting with ALL_INTERIOR_POINTERS.				*/
+/* Always returns its argument.						*/
+GC_API GC_PTR GC_is_valid_displacement GC_PROTO((GC_PTR	p));
+
+/* Safer, but slow, pointer addition.  Probably useful mainly with 	*/
+/* a preprocessor.  Useful only for heap pointers.			*/
+#ifdef GC_DEBUG
+#   define GC_PTR_ADD3(x, n, type_of_result) \
+	((type_of_result)GC_same_obj((x)+(n), (x)))
+#   define GC_PRE_INCR3(x, n, type_of_result) \
+	((type_of_result)GC_pre_incr(&(x), (n)*sizeof(*x))
+#   define GC_POST_INCR2(x, type_of_result) \
+	((type_of_result)GC_post_incr(&(x), sizeof(*x))
+#   ifdef __GNUC__
+#       define GC_PTR_ADD(x, n) \
+	    GC_PTR_ADD3(x, n, typeof(x))
+#   define GC_PRE_INCR(x, n) \
+	    GC_PRE_INCR3(x, n, typeof(x))
+#   define GC_POST_INCR(x, n) \
+	    GC_POST_INCR3(x, typeof(x))
+#   else
+	/* We can't do this right without typeof, which ANSI	*/
+	/* decided was not sufficiently useful.  Repeatedly	*/
+	/* mentioning the arguments seems too dangerous to be	*/
+	/* useful.  So does not casting the result.		*/
+#   	define GC_PTR_ADD(x, n) ((x)+(n))
+#   endif
+#else	/* !GC_DEBUG */
+#   define GC_PTR_ADD3(x, n, type_of_result) ((x)+(n))
+#   define GC_PTR_ADD(x, n) ((x)+(n))
+#   define GC_PRE_INCR3(x, n, type_of_result) ((x) += (n))
+#   define GC_PRE_INCR(x, n) ((x) += (n))
+#   define GC_POST_INCR2(x, n, type_of_result) ((x)++)
+#   define GC_POST_INCR(x, n) ((x)++)
+#endif
+
+/* Safer assignment of a pointer to a nonstack location.	*/
+#ifdef GC_DEBUG
+# ifdef __STDC__
+#   define GC_PTR_STORE(p, q) \
+	(*(void **)GC_is_visible(p) = GC_is_valid_displacement(q))
+# else
+#   define GC_PTR_STORE(p, q) \
+	(*(char **)GC_is_visible(p) = GC_is_valid_displacement(q))
+# endif
+#else /* !GC_DEBUG */
+#   define GC_PTR_STORE(p, q) *((p) = (q))
+#endif
+
+/* Fynctions called to report pointer checking errors */
+GC_API void (*GC_same_obj_print_proc) GC_PROTO((GC_PTR p, GC_PTR q));
+
+GC_API void (*GC_is_valid_displacement_print_proc)
+	GC_PROTO((GC_PTR p));
+
+GC_API void (*GC_is_visible_print_proc)
+	GC_PROTO((GC_PTR p));
+
+#if defined(_SOLARIS_PTHREADS) && !defined(SOLARIS_THREADS)
+#   define SOLARIS_THREADS
+#endif
+
+#ifdef SOLARIS_THREADS
+/* We need to intercept calls to many of the threads primitives, so 	*/
+/* that we can locate thread stacks and stop the world.			*/
+/* Note also that the collector cannot see thread specific data.	*/
+/* Thread specific data should generally consist of pointers to		*/
+/* uncollectable objects, which are deallocated using the destructor	*/
+/* facility in thr_keycreate.						*/
+# include <thread.h>
+# include <signal.h>
+  int GC_thr_create(void *stack_base, size_t stack_size,
+                    void *(*start_routine)(void *), void *arg, long flags,
+                    thread_t *new_thread);
+  int GC_thr_join(thread_t wait_for, thread_t *departed, void **status);
+  int GC_thr_suspend(thread_t target_thread);
+  int GC_thr_continue(thread_t target_thread);
+  void * GC_dlopen(const char *path, int mode);
+
+# ifdef _SOLARIS_PTHREADS
+#   include <pthread.h>
+    extern int GC_pthread_create(pthread_t *new_thread,
+    			         const pthread_attr_t *attr,
+          			 void * (*thread_execp)(void *), void *arg);
+    extern int GC_pthread_join(pthread_t wait_for, void **status);
+
+#   undef thread_t
+
+#   define pthread_join GC_pthread_join
+#   define pthread_create GC_pthread_create
+#endif
+
+# define thr_create GC_thr_create
+# define thr_join GC_thr_join
+# define thr_suspend GC_thr_suspend
+# define thr_continue GC_thr_continue
+# define dlopen GC_dlopen
+
+# endif /* SOLARIS_THREADS */
+
+
+#if !defined(USE_LD_WRAP) && \
+    (defined(IRIX_THREADS) || defined(LINUX_THREADS) || defined(HPUX_THREADS))
+/* We treat these similarly. */
+# include <pthread.h>
+# include <signal.h>
+
+  int GC_pthread_create(pthread_t *new_thread,
+                        const pthread_attr_t *attr,
+		        void *(*start_routine)(void *), void *arg);
+  int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset);
+  int GC_pthread_join(pthread_t thread, void **retval);
+
+# define pthread_create GC_pthread_create
+# define pthread_sigmask GC_pthread_sigmask
+# define pthread_join GC_pthread_join
+# define dlopen GC_dlopen
+
+#endif /* xxxxx_THREADS */
+
+# if defined(PCR) || defined(SOLARIS_THREADS) || defined(WIN32_THREADS) || \
+	defined(IRIX_THREADS) || defined(LINUX_THREADS) || \
+	defined(IRIX_JDK_THREADS) || defined(HPUX_THREADS)
+   	/* Any flavor of threads except SRC_M3.	*/
+/* This returns a list of objects, linked through their first		*/
+/* word.  Its use can greatly reduce lock contention problems, since	*/
+/* the allocation lock can be acquired and released many fewer times.	*/
+/* lb must be large enough to hold the pointer field.			*/
+GC_PTR GC_malloc_many(size_t lb);
+#define GC_NEXT(p) (*(GC_PTR *)(p)) 	/* Retrieve the next element	*/
+					/* in returned list.		*/
+extern void GC_thr_init();	/* Needed for Solaris/X86	*/
+
+#endif /* THREADS && !SRC_M3 */
+
+/*
+ * If you are planning on putting
+ * the collector in a SunOS 5 dynamic library, you need to call GC_INIT()
+ * from the statically loaded program section.
+ * This circumvents a Solaris 2.X (X<=4) linker bug.
+ */
+#if defined(sparc) || defined(__sparc)
+#   define GC_INIT() { extern end, etext; \
+		       GC_noop(&end, &etext); }
+#else
+# if defined(__CYGWIN32__) && defined(GC_USE_DLL)
+    /*
+     * Similarly gnu-win32 DLLs need explicit initialization
+     */
+#   define GC_INIT() { GC_add_roots(DATASTART, DATAEND); }
+# else
+#   define GC_INIT()
+# endif
+#endif
+
+#if (defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300) \
+     || defined(_WIN32)
+  /* win32S may not free all resources on process exit.  */
+  /* This explicitly deallocates the heap.		 */
+    GC_API void GC_win32_free_heap ();
+#endif
+
+#ifdef __cplusplus
+    }  /* end of extern "C" */
+#endif
+
+#endif /* _GC_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/include/gc_alloc.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 1996-1998 by Silicon Graphics.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+//
+// This is a C++ header file that is intended to replace the SGI STL
+// alloc.h.  This assumes SGI STL version < 3.0.
+//
+// This assumes the collector has been compiled with -DATOMIC_UNCOLLECTABLE
+// and -DALL_INTERIOR_POINTERS.  We also recommend
+// -DREDIRECT_MALLOC=GC_uncollectable_malloc.
+//
+// Some of this could be faster in the explicit deallocation case.  In particular,
+// we spend too much time clearing objects on the free lists.  That could be avoided.
+//
+// This uses template classes with static members, and hence does not work
+// with g++ 2.7.2 and earlier.
+//
+
+#include "gc.h"
+
+#ifndef GC_ALLOC_H
+
+#define GC_ALLOC_H
+#define __ALLOC_H	// Prevent inclusion of the default version.  Ugly.
+#define __SGI_STL_ALLOC_H
+#define __SGI_STL_INTERNAL_ALLOC_H
+
+#ifndef __ALLOC
+#   define __ALLOC alloc
+#endif
+
+#include <stddef.h>
+#include <string.h>
+
+// The following is just replicated from the conventional SGI alloc.h:
+
+template<class T, class alloc>
+class simple_alloc {
+
+public:
+    static T *allocate(size_t n)
+                { return 0 == n? 0 : (T*) alloc::allocate(n * sizeof (T)); }
+    static T *allocate(void)
+                { return (T*) alloc::allocate(sizeof (T)); }
+    static void deallocate(T *p, size_t n)
+                { if (0 != n) alloc::deallocate(p, n * sizeof (T)); }
+    static void deallocate(T *p)
+                { alloc::deallocate(p, sizeof (T)); }
+};
+
+#include "gc.h"
+
+// The following need to match collector data structures.
+// We can't include gc_priv.h, since that pulls in way too much stuff.
+// This should eventually be factored out into another include file.
+
+extern "C" {
+    extern void ** const GC_objfreelist_ptr;
+    extern void ** const GC_aobjfreelist_ptr;
+    extern void ** const GC_uobjfreelist_ptr;
+    extern void ** const GC_auobjfreelist_ptr;
+
+    extern void GC_incr_words_allocd(size_t words);
+    extern void GC_incr_mem_freed(size_t words);
+
+    extern char * GC_generic_malloc_words_small(size_t word, int kind);
+}
+
+// Object kinds; must match PTRFREE, NORMAL, UNCOLLECTABLE, and
+// AUNCOLLECTABLE in gc_priv.h.
+
+enum { GC_PTRFREE = 0, GC_NORMAL = 1, GC_UNCOLLECTABLE = 2,
+       GC_AUNCOLLECTABLE = 3 };
+
+enum { GC_max_fast_bytes = 255 };
+
+enum { GC_bytes_per_word = sizeof(char *) };
+
+enum { GC_byte_alignment = 8 };
+
+enum { GC_word_alignment = GC_byte_alignment/GC_bytes_per_word };
+
+inline void * &GC_obj_link(void * p)
+{   return *(void **)p;  }
+
+// Compute a number of words >= n+1 bytes.
+// The +1 allows for pointers one past the end.
+inline size_t GC_round_up(size_t n)
+{
+    return ((n + GC_byte_alignment)/GC_byte_alignment)*GC_word_alignment;
+}
+
+// The same but don't allow for extra byte.
+inline size_t GC_round_up_uncollectable(size_t n)
+{
+    return ((n + GC_byte_alignment - 1)/GC_byte_alignment)*GC_word_alignment;
+}
+
+template <int dummy>
+class GC_aux_template {
+public:
+  // File local count of allocated words.  Occasionally this is
+  // added into the global count.  A separate count is necessary since the
+  // real one must be updated with a procedure call.
+  static size_t GC_words_recently_allocd;
+
+  // Same for uncollectable mmory.  Not yet reflected in either
+  // GC_words_recently_allocd or GC_non_gc_bytes.
+  static size_t GC_uncollectable_words_recently_allocd;
+
+  // Similar counter for explicitly deallocated memory.
+  static size_t GC_mem_recently_freed;
+
+  // Again for uncollectable memory.
+  static size_t GC_uncollectable_mem_recently_freed;
+
+  static void * GC_out_of_line_malloc(size_t nwords, int kind);
+};
+
+template <int dummy>
+size_t GC_aux_template<dummy>::GC_words_recently_allocd = 0;
+
+template <int dummy>
+size_t GC_aux_template<dummy>::GC_uncollectable_words_recently_allocd = 0;
+
+template <int dummy>
+size_t GC_aux_template<dummy>::GC_mem_recently_freed = 0;
+
+template <int dummy>
+size_t GC_aux_template<dummy>::GC_uncollectable_mem_recently_freed = 0;
+
+template <int dummy>
+void * GC_aux_template<dummy>::GC_out_of_line_malloc(size_t nwords, int kind)
+{
+    GC_words_recently_allocd += GC_uncollectable_words_recently_allocd;
+    GC_non_gc_bytes +=
+                GC_bytes_per_word * GC_uncollectable_words_recently_allocd;
+    GC_uncollectable_words_recently_allocd = 0;
+
+    GC_mem_recently_freed += GC_uncollectable_mem_recently_freed;
+    GC_non_gc_bytes -= 
+                GC_bytes_per_word * GC_uncollectable_mem_recently_freed;
+    GC_uncollectable_mem_recently_freed = 0;
+
+    GC_incr_words_allocd(GC_words_recently_allocd);
+    GC_words_recently_allocd = 0;
+
+    GC_incr_mem_freed(GC_mem_recently_freed);
+    GC_mem_recently_freed = 0;
+
+    return GC_generic_malloc_words_small(nwords, kind);
+}
+
+typedef GC_aux_template<0> GC_aux;
+
+// A fast, single-threaded, garbage-collected allocator
+// We assume the first word will be immediately overwritten.
+// In this version, deallocation is not a noop, and explicit
+// deallocation is likely to help performance.
+template <int dummy>
+class single_client_gc_alloc_template {
+    public:
+     	static void * allocate(size_t n)
+        {
+	    size_t nwords = GC_round_up(n);
+	    void ** flh;
+	    void * op;
+
+  	    if (n > GC_max_fast_bytes) return GC_malloc(n);
+	    flh = GC_objfreelist_ptr + nwords;
+	    if (0 == (op = *flh)) {
+		return GC_aux::GC_out_of_line_malloc(nwords, GC_NORMAL);
+	    }
+	    *flh = GC_obj_link(op);
+	    GC_aux::GC_words_recently_allocd += nwords;
+	    return op;
+        }
+     	static void * ptr_free_allocate(size_t n)
+        {
+	    size_t nwords = GC_round_up(n);
+	    void ** flh;
+	    void * op;
+
+  	    if (n > GC_max_fast_bytes) return GC_malloc_atomic(n);
+	    flh = GC_aobjfreelist_ptr + nwords;
+	    if (0 == (op = *flh)) {
+		return GC_aux::GC_out_of_line_malloc(nwords, GC_PTRFREE);
+	    }
+	    *flh = GC_obj_link(op);
+	    GC_aux::GC_words_recently_allocd += nwords;
+	    return op;
+        }
+	static void deallocate(void *p, size_t n)
+	{
+            size_t nwords = GC_round_up(n);
+            void ** flh;
+	   
+	    if (n > GC_max_fast_bytes)  {
+		GC_free(p);
+	    } else {
+	        flh = GC_objfreelist_ptr + nwords;
+	        GC_obj_link(p) = *flh;
+		memset((char *)p + GC_bytes_per_word, 0,
+		       GC_bytes_per_word * (nwords - 1));
+	        *flh = p;
+	        GC_aux::GC_mem_recently_freed += nwords;
+	    }
+	}
+	static void ptr_free_deallocate(void *p, size_t n)
+	{
+            size_t nwords = GC_round_up(n);
+            void ** flh;
+	   
+	    if (n > GC_max_fast_bytes) {
+		GC_free(p);
+	    } else {
+	    	flh = GC_aobjfreelist_ptr + nwords;
+	    	GC_obj_link(p) = *flh;
+	    	*flh = p;
+	    	GC_aux::GC_mem_recently_freed += nwords;
+	    }
+	}
+};
+
+typedef single_client_gc_alloc_template<0> single_client_gc_alloc;
+
+// Once more, for uncollectable objects.
+template <int dummy>
+class single_client_alloc_template {
+    public:
+     	static void * allocate(size_t n)
+        {
+	    size_t nwords = GC_round_up_uncollectable(n);
+	    void ** flh;
+	    void * op;
+
+  	    if (n > GC_max_fast_bytes) return GC_malloc_uncollectable(n);
+	    flh = GC_uobjfreelist_ptr + nwords;
+	    if (0 == (op = *flh)) {
+		return GC_aux::GC_out_of_line_malloc(nwords, GC_UNCOLLECTABLE);
+	    }
+	    *flh = GC_obj_link(op);
+	    GC_aux::GC_uncollectable_words_recently_allocd += nwords;
+	    return op;
+        }
+     	static void * ptr_free_allocate(size_t n)
+        {
+	    size_t nwords = GC_round_up_uncollectable(n);
+	    void ** flh;
+	    void * op;
+
+  	    if (n > GC_max_fast_bytes) return GC_malloc_atomic_uncollectable(n);
+	    flh = GC_auobjfreelist_ptr + nwords;
+	    if (0 == (op = *flh)) {
+		return GC_aux::GC_out_of_line_malloc(nwords, GC_AUNCOLLECTABLE);
+	    }
+	    *flh = GC_obj_link(op);
+	    GC_aux::GC_uncollectable_words_recently_allocd += nwords;
+	    return op;
+        }
+	static void deallocate(void *p, size_t n)
+	{
+            size_t nwords = GC_round_up_uncollectable(n);
+            void ** flh;
+	   
+	    if (n > GC_max_fast_bytes)  {
+		GC_free(p);
+	    } else {
+	        flh = GC_uobjfreelist_ptr + nwords;
+	        GC_obj_link(p) = *flh;
+	        *flh = p;
+	        GC_aux::GC_uncollectable_mem_recently_freed += nwords;
+	    }
+	}
+	static void ptr_free_deallocate(void *p, size_t n)
+	{
+            size_t nwords = GC_round_up_uncollectable(n);
+            void ** flh;
+	   
+	    if (n > GC_max_fast_bytes) {
+		GC_free(p);
+	    } else {
+	    	flh = GC_auobjfreelist_ptr + nwords;
+	    	GC_obj_link(p) = *flh;
+	    	*flh = p;
+	    	GC_aux::GC_uncollectable_mem_recently_freed += nwords;
+	    }
+	}
+};
+
+typedef single_client_alloc_template<0> single_client_alloc;
+
+template < int dummy >
+class gc_alloc_template {
+    public:
+     	static void * allocate(size_t n) { return GC_malloc(n); }
+     	static void * ptr_free_allocate(size_t n)
+		{ return GC_malloc_atomic(n); }
+	static void deallocate(void *, size_t) { }
+	static void ptr_free_deallocate(void *, size_t) { }
+};
+
+typedef gc_alloc_template < 0 > gc_alloc;
+
+template < int dummy >
+class alloc_template {
+    public:
+     	static void * allocate(size_t n) { return GC_malloc_uncollectable(n); }
+     	static void * ptr_free_allocate(size_t n)
+		{ return GC_malloc_atomic_uncollectable(n); }
+	static void deallocate(void *p, size_t) { GC_free(p); }
+	static void ptr_free_deallocate(void *p, size_t) { GC_free(p); }
+};
+
+typedef alloc_template < 0 > alloc;
+
+#ifdef _SGI_SOURCE
+
+// We want to specialize simple_alloc so that it does the right thing
+// for all pointerfree types.  At the moment there is no portable way to
+// even approximate that.  The following approximation should work for
+// SGI compilers, and perhaps some others.
+
+# define __GC_SPECIALIZE(T,alloc) \
+class simple_alloc<T, alloc> { \
+public: \
+    static T *allocate(size_t n) \
+	{ return 0 == n? 0 : \
+			 (T*) alloc::ptr_free_allocate(n * sizeof (T)); } \
+    static T *allocate(void) \
+	{ return (T*) alloc::ptr_free_allocate(sizeof (T)); } \
+    static void deallocate(T *p, size_t n) \
+	{ if (0 != n) alloc::ptr_free_deallocate(p, n * sizeof (T)); } \
+    static void deallocate(T *p) \
+	{ alloc::ptr_free_deallocate(p, sizeof (T)); } \
+};
+
+__GC_SPECIALIZE(char, gc_alloc)
+__GC_SPECIALIZE(int, gc_alloc)
+__GC_SPECIALIZE(unsigned, gc_alloc)
+__GC_SPECIALIZE(float, gc_alloc)
+__GC_SPECIALIZE(double, gc_alloc)
+
+__GC_SPECIALIZE(char, alloc)
+__GC_SPECIALIZE(int, alloc)
+__GC_SPECIALIZE(unsigned, alloc)
+__GC_SPECIALIZE(float, alloc)
+__GC_SPECIALIZE(double, alloc)
+
+__GC_SPECIALIZE(char, single_client_gc_alloc)
+__GC_SPECIALIZE(int, single_client_gc_alloc)
+__GC_SPECIALIZE(unsigned, single_client_gc_alloc)
+__GC_SPECIALIZE(float, single_client_gc_alloc)
+__GC_SPECIALIZE(double, single_client_gc_alloc)
+
+__GC_SPECIALIZE(char, single_client_alloc)
+__GC_SPECIALIZE(int, single_client_alloc)
+__GC_SPECIALIZE(unsigned, single_client_alloc)
+__GC_SPECIALIZE(float, single_client_alloc)
+__GC_SPECIALIZE(double, single_client_alloc)
+
+#ifdef __STL_USE_STD_ALLOCATORS
+
+???copy stuff from stl_alloc.h or remove it to a different file ???
+
+#endif /* __STL_USE_STD_ALLOCATORS */
+
+#endif /* _SGI_SOURCE */
+
+#endif /* GC_ALLOC_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/include/gc_copy_descr.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,26 @@
+
+/* 
+ * Copyright (c) 1999 by Silicon Graphics.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+/* Descriptor for allocation request. May be redefined by client. */
+typedef struct {
+    GC_word bitmap;	/* Bitmap describing pointer locations.	*/
+			/* High order bit correspond to 0th	*/
+			/* word.  2 lsbs must be 0.		*/
+    size_t length;      /* In bytes, must be multiple of word	*/
+			/* size.  Must be >0, <= 512		*/
+} * GC_copy_descriptor;
+
+/* The collector accesses descriptors only through these two macros. */
+#define GC_SIZE_FROM_DESCRIPTOR(d) ((d) -> length)
+#define GC_BIT_MAP_FROM_DESCRIPTOR(d) ((d) -> bitmap)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/include/gc_cpp.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,310 @@
+#ifndef GC_CPP_H
+#define GC_CPP_H
+/****************************************************************************
+Copyright (c) 1994 by Xerox Corporation.  All rights reserved.
+ 
+THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ 
+Permission is hereby granted to use or copy this program for any
+purpose, provided the above notices are retained on all copies.
+Permission to modify the code and to distribute modified code is
+granted, provided the above notices are retained, and a notice that
+the code was modified is included with the above copyright notice.
+****************************************************************************
+
+C++ Interface to the Boehm Collector
+
+    John R. Ellis and Jesse Hull 
+
+This interface provides access to the Boehm collector.  It provides
+basic facilities similar to those described in "Safe, Efficient
+Garbage Collection for C++", by John R. Elis and David L. Detlefs
+(ftp://ftp.parc.xerox.com/pub/ellis/gc).
+
+All heap-allocated objects are either "collectable" or
+"uncollectable".  Programs must explicitly delete uncollectable
+objects, whereas the garbage collector will automatically delete
+collectable objects when it discovers them to be inaccessible.
+Collectable objects may freely point at uncollectable objects and vice
+versa.
+
+Objects allocated with the built-in "::operator new" are uncollectable.
+
+Objects derived from class "gc" are collectable.  For example:
+
+    class A: public gc {...};
+    A* a = new A;       // a is collectable. 
+
+Collectable instances of non-class types can be allocated using the GC
+(or UseGC) placement:
+
+    typedef int A[ 10 ];
+    A* a = new (GC) A;
+
+Uncollectable instances of classes derived from "gc" can be allocated
+using the NoGC placement:
+
+    class A: public gc {...};
+    A* a = new (NoGC) A;   // a is uncollectable.
+
+Both uncollectable and collectable objects can be explicitly deleted
+with "delete", which invokes an object's destructors and frees its
+storage immediately.
+
+A collectable object may have a clean-up function, which will be
+invoked when the collector discovers the object to be inaccessible.
+An object derived from "gc_cleanup" or containing a member derived
+from "gc_cleanup" has a default clean-up function that invokes the
+object's destructors.  Explicit clean-up functions may be specified as
+an additional placement argument:
+
+    A* a = ::new (GC, MyCleanup) A;
+
+An object is considered "accessible" by the collector if it can be
+reached by a path of pointers from static variables, automatic
+variables of active functions, or from some object with clean-up
+enabled; pointers from an object to itself are ignored.
+
+Thus, if objects A and B both have clean-up functions, and A points at
+B, B is considered accessible.  After A's clean-up is invoked and its
+storage released, B will then become inaccessible and will have its
+clean-up invoked.  If A points at B and B points to A, forming a
+cycle, then that's considered a storage leak, and neither will be
+collectable.  See the interface gc.h for low-level facilities for
+handling such cycles of objects with clean-up.
+
+The collector cannot guarrantee that it will find all inaccessible
+objects.  In practice, it finds almost all of them.
+
+
+Cautions:
+
+1. Be sure the collector has been augmented with "make c++".
+
+2.  If your compiler supports the new "operator new[]" syntax, then
+add -DOPERATOR_NEW_ARRAY to the Makefile.
+
+If your compiler doesn't support "operator new[]", beware that an
+array of type T, where T is derived from "gc", may or may not be
+allocated as a collectable object (it depends on the compiler).  Use
+the explicit GC placement to make the array collectable.  For example:
+
+    class A: public gc {...};
+    A* a1 = new A[ 10 ];        // collectable or uncollectable?
+    A* a2 = new (GC) A[ 10 ];   // collectable
+
+3. The destructors of collectable arrays of objects derived from
+"gc_cleanup" will not be invoked properly.  For example:
+
+    class A: public gc_cleanup {...};
+    A* a = new (GC) A[ 10 ];    // destructors not invoked correctly
+
+Typically, only the destructor for the first element of the array will
+be invoked when the array is garbage-collected.  To get all the
+destructors of any array executed, you must supply an explicit
+clean-up function:
+
+    A* a = new (GC, MyCleanUp) A[ 10 ];
+
+(Implementing clean-up of arrays correctly, portably, and in a way
+that preserves the correct exception semantics requires a language
+extension, e.g. the "gc" keyword.)
+
+4. Compiler bugs:
+
+* Solaris 2's CC (SC3.0) doesn't implement t->~T() correctly, so the
+destructors of classes derived from gc_cleanup won't be invoked.
+You'll have to explicitly register a clean-up function with
+new-placement syntax.
+
+* Evidently cfront 3.0 does not allow destructors to be explicitly
+invoked using the ANSI-conforming syntax t->~T().  If you're using
+cfront 3.0, you'll have to comment out the class gc_cleanup, which
+uses explicit invocation.
+
+5. GC name conflicts:
+
+Many other systems seem to use the identifier "GC" as an abbreviation
+for "Graphics Context".  Since version 5.0, GC placement has been replaced
+by UseGC.  GC is an alias for UseGC, unless GC_NAME_CONFLICT is defined.
+
+****************************************************************************/
+
+#include "gc.h"
+
+#ifndef THINK_CPLUS
+#define _cdecl
+#endif
+
+#if ! defined( OPERATOR_NEW_ARRAY ) \
+    && (__BORLANDC__ >= 0x450 || (__GNUC__ >= 2 && __GNUC_MINOR__ >= 6) \
+        || __WATCOMC__ >= 1050 || _MSC_VER >= 1100)
+#   define OPERATOR_NEW_ARRAY
+#endif
+
+enum GCPlacement {UseGC,
+#ifndef GC_NAME_CONFLICT
+		  GC=UseGC,
+#endif
+                  NoGC, PointerFreeGC};
+
+class gc {public:
+    inline void* operator new( size_t size );
+    inline void* operator new( size_t size, GCPlacement gcp );
+    inline void operator delete( void* obj );
+
+#ifdef OPERATOR_NEW_ARRAY
+    inline void* operator new[]( size_t size );
+    inline void* operator new[]( size_t size, GCPlacement gcp );
+    inline void operator delete[]( void* obj );
+#endif /* OPERATOR_NEW_ARRAY */
+    };    
+    /*
+    Instances of classes derived from "gc" will be allocated in the 
+    collected heap by default, unless an explicit NoGC placement is
+    specified. */
+
+class gc_cleanup: virtual public gc {public:
+    inline gc_cleanup();
+    inline virtual ~gc_cleanup();
+private:
+    inline static void _cdecl cleanup( void* obj, void* clientData );};
+    /*
+    Instances of classes derived from "gc_cleanup" will be allocated
+    in the collected heap by default.  When the collector discovers an
+    inaccessible object derived from "gc_cleanup" or containing a
+    member derived from "gc_cleanup", its destructors will be
+    invoked. */
+
+extern "C" {typedef void (*GCCleanUpFunc)( void* obj, void* clientData );}
+
+inline void* operator new( 
+    size_t size, 
+    GCPlacement gcp,
+    GCCleanUpFunc cleanup = 0,
+    void* clientData = 0 );
+    /*
+    Allocates a collectable or uncollected object, according to the
+    value of "gcp".
+
+    For collectable objects, if "cleanup" is non-null, then when the
+    allocated object "obj" becomes inaccessible, the collector will
+    invoke the function "cleanup( obj, clientData )" but will not
+    invoke the object's destructors.  It is an error to explicitly
+    delete an object allocated with a non-null "cleanup".
+
+    It is an error to specify a non-null "cleanup" with NoGC or for
+    classes derived from "gc_cleanup" or containing members derived
+    from "gc_cleanup". */
+
+#ifdef OPERATOR_NEW_ARRAY
+
+#ifdef _MSC_VER
+ /** This ensures that the system default operator new[] doesn't get
+  *  undefined, which is what seems to happen on VC++ 6 for some reason
+  *  if we define a multi-argument operator new[].
+  */
+ inline void *operator new[]( size_t size )
+ {
+    return ::operator new( size );
+ }
+#endif /* _MSC_VER */
+
+inline void* operator new[](
+    size_t size, 
+    GCPlacement gcp,
+    GCCleanUpFunc cleanup = 0,
+    void* clientData = 0 );
+    /*
+    The operator new for arrays, identical to the above. */
+
+#endif /* OPERATOR_NEW_ARRAY */
+
+/****************************************************************************
+
+Inline implementation
+
+****************************************************************************/
+
+inline void* gc::operator new( size_t size ) {
+    return GC_MALLOC( size );}
+    
+inline void* gc::operator new( size_t size, GCPlacement gcp ) {
+    if (gcp == UseGC) 
+        return GC_MALLOC( size );
+    else if (gcp == PointerFreeGC)
+	return GC_MALLOC_ATOMIC( size );
+    else
+        return GC_MALLOC_UNCOLLECTABLE( size );}
+
+inline void gc::operator delete( void* obj ) {
+    GC_FREE( obj );}
+    
+
+#ifdef OPERATOR_NEW_ARRAY
+
+inline void* gc::operator new[]( size_t size ) {
+    return gc::operator new( size );}
+    
+inline void* gc::operator new[]( size_t size, GCPlacement gcp ) {
+    return gc::operator new( size, gcp );}
+
+inline void gc::operator delete[]( void* obj ) {
+    gc::operator delete( obj );}
+    
+#endif /* OPERATOR_NEW_ARRAY */
+
+
+inline gc_cleanup::~gc_cleanup() {
+    GC_REGISTER_FINALIZER_IGNORE_SELF( GC_base(this), 0, 0, 0, 0 );}
+
+inline void gc_cleanup::cleanup( void* obj, void* displ ) {
+    ((gc_cleanup*) ((char*) obj + (ptrdiff_t) displ))->~gc_cleanup();}
+
+inline gc_cleanup::gc_cleanup() {
+    GC_finalization_proc oldProc;
+    void* oldData;
+    void* base = GC_base( (void *) this );
+    if (0 != base)  {
+      GC_REGISTER_FINALIZER_IGNORE_SELF( 
+        base, (GC_finalization_proc)cleanup, (void*) ((char*) this - (char*) base), 
+        &oldProc, &oldData );
+      if (0 != oldProc) {
+        GC_REGISTER_FINALIZER_IGNORE_SELF( base, oldProc, oldData, 0, 0 );}}}
+
+inline void* operator new( 
+    size_t size, 
+    GCPlacement gcp,
+    GCCleanUpFunc cleanup,
+    void* clientData )
+{
+    void* obj;
+
+    if (gcp == UseGC) {
+        obj = GC_MALLOC( size );
+        if (cleanup != 0) 
+            GC_REGISTER_FINALIZER_IGNORE_SELF( 
+                obj, cleanup, clientData, 0, 0 );}
+    else if (gcp == PointerFreeGC) {
+        obj = GC_MALLOC_ATOMIC( size );}
+    else {
+        obj = GC_MALLOC_UNCOLLECTABLE( size );};
+    return obj;}
+        
+
+#ifdef OPERATOR_NEW_ARRAY
+
+inline void* operator new[]( 
+    size_t size, 
+    GCPlacement gcp,
+    GCCleanUpFunc cleanup,
+    void* clientData )
+{
+    return ::operator new( size, gcp, cleanup, clientData );}
+
+#endif /* OPERATOR_NEW_ARRAY */
+
+
+#endif /* GC_CPP_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/include/gc_gcj.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,101 @@
+/* 
+ * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
+ * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.
+ * Copyright 1996-1999 by Silicon Graphics.  All rights reserved.
+ * Copyright 1999 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+/* This file assumes the collector has been compiled with GC_GCJ_SUPPORT */
+/* and that an ANSI C compiler is available.				 */
+
+/*
+ * We allocate objects whose first word contains a pointer to a struct
+ * describing the object type.  This struct contains a garbage collector mark
+ * descriptor at offset MARK_DESCR_OFFSET.  Alternatively, the objects
+ * may be marked by the mark procedure passed to GC_init_gcj_malloc.
+ */
+
+#ifndef MARK_DESCR_OFFSET
+#  define MARK_DESCR_OFFSET	sizeof(word)
+#endif
+	/* Gcj keeps GC descriptor as second word of vtable.	This	*/
+	/* probably needs to be adjusted for other clients.		*/
+	/* We currently assume that this offset is such that:		*/
+	/*	- all objects of this kind are large enough to have	*/
+	/*	  a value at that offset, and				*/
+	/* 	- it is not zero.					*/
+	/* These assumptions allow objects on the free list to be 	*/
+	/* marked normally.						*/
+
+#ifndef _GC_H
+#   include "gc.h"
+#endif
+
+/* The following allocators signal an out of memory condition with	*/
+/* return GC_oom_action();						*/
+/* The default GC_oom_action returns 0.					*/
+/* This functionality is currently restricted to the gcj allocators.	*/
+/* We may want to extend it to the others.				*/
+
+extern void * (*GC_oom_action)(void);
+
+/* The following function must be called before the gcj allocators	*/
+/* can be invoked.							*/
+/* mp_index and mp are the index and mark_proc (see gc_mark.h)		*/
+/* respectively for the allocated objects.  Mark_proc will be 		*/
+/* used to build the descriptor for objects allocated through the	*/
+/* debugging interface.  The mark_proc will be invoked on all such 	*/
+/* objects with an "environment" value of 1.  The client may chose	*/
+/* to use the same mark_proc for some of its generated mark descriptors.*/
+/* In that case, it should use a different "environment" value to	*/
+/* detect the presence or absence of the debug header.			*/
+
+/* the debugging interface.						*/
+/* Mp is really of type mark_proc, as defined in gc_mark.h.  We don't 	*/
+/* want to include that here for namespace pollution reasons.		*/
+extern void GC_init_gcj_malloc(int mp_index, void * /* really mark_proc */mp);
+
+/* Allocate an object, clear it, and store the pointer to the	*/
+/* type structure (vtable in gcj).				*/
+/* This adds a byte at the end of the object if GC_malloc would.*/
+extern void * GC_gcj_malloc(size_t lb, void * ptr_to_struct_containing_descr);
+/* The debug versions allocate such that the specified mark_proc	*/
+/* is always invoked.							*/
+extern void * GC_debug_gcj_malloc(size_t lb,
+				  void * ptr_to_struct_containing_descr,
+				  GC_EXTRA_PARAMS);
+
+/* Similar to the above, but the size is in words, and we don't	*/
+/* adjust it.  The size is assumed to be such that it can be 	*/
+/* allocated as a small object.					*/
+extern void * GC_gcj_fast_malloc(size_t lw,
+				 void * ptr_to_struct_containing_descr);
+extern void * GC_debug_gcj_fast_malloc(size_t lw,
+				 void * ptr_to_struct_containing_descr,
+				 GC_EXTRA_PARAMS);
+
+/* Similar to GC_gcj_malloc, but assumes that a pointer to near the	*/
+/* beginning of the resulting object is always maintained.		*/
+extern void * GC_gcj_malloc_ignore_off_page(size_t lb,
+				void * ptr_to_struct_containing_descr);
+
+# ifdef GC_DEBUG
+#   define GC_GCJ_MALLOC(s,d) GC_debug_gcj_malloc(s,d,GC_EXTRAS)
+#   define GC_GCJ_FAST_MALLOC(s,d) GC_debug_gcj_fast_malloc(s,d,GC_EXTRAS)
+#   define GC_GCJ_MALLOC_IGNORE_OFF_PAGE(s,d) GC_gcj_debug_malloc(s,d,GC_EXTRAS)
+# else
+#   define GC_GCJ_MALLOC(s,d) GC_gcj_malloc(s,d)
+#   define GC_GCJ_FAST_MALLOC(s,d) GC_gcj_fast_malloc(s,d)
+#   define GC_GCJ_MALLOC_IGNORE_OFF_PAGE(s,d) \
+	GC_gcj_debug_malloc_ignore_off_page(s,d)
+# endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/include/gc_inl.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,103 @@
+/* 
+ * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
+ * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+/* Boehm, October 3, 1995 2:07 pm PDT */
+ 
+# ifndef GC_PRIVATE_H
+#   include "private/gc_priv.h"
+# endif
+
+/* USE OF THIS FILE IS NOT RECOMMENDED unless the collector has been	*/
+/* compiled without -DALL_INTERIOR_POINTERS or with			*/
+/* -DDONT_ADD_BYTE_AT_END, or the specified size includes a pointerfree	*/
+/* word at the end.  In the standard collector configuration,		*/
+/* the final word of each object may not be scanned.			*/
+/* This is most useful for compilers that generate C.			*/
+/* Manual use is hereby discouraged.					*/
+
+/* Allocate n words (NOT BYTES).  X is made to point to the result.	*/
+/* It is assumed that n < MAXOBJSZ, and					*/
+/* that n > 0.  On machines requiring double word alignment of some	*/
+/* data, we also assume that n is 1 or even.  This bypasses the		*/
+/* MERGE_SIZES mechanism.  In order to minimize the number of distinct	*/
+/* free lists that are maintained, the caller should ensure that a 	*/
+/* small number of distinct values of n are used.  (The MERGE_SIZES	*/
+/* mechanism normally does this by ensuring that only the leading three	*/
+/* bits of n may be nonzero.  See misc.c for details.)  We really 	*/
+/* recommend this only in cases in which n is a constant, and no	*/
+/* locking is required.							*/
+/* In that case it may allow the compiler to perform substantial	*/
+/* additional optimizations.						*/
+# define GC_MALLOC_WORDS(result,n) \
+{	\
+    register ptr_t op;	\
+    register ptr_t *opp;	\
+    DCL_LOCK_STATE;	\
+	\
+    opp = &(GC_objfreelist[n]);	\
+    FASTLOCK();	\
+    if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {	\
+        FASTUNLOCK();	\
+        (result) = GC_generic_malloc_words_small((n), NORMAL);	\
+    } else { 	\
+        *opp = obj_link(op);	\
+        obj_link(op) = 0;	\
+        GC_words_allocd += (n);	\
+        FASTUNLOCK();	\
+        (result) = (GC_PTR) op;	\
+    }	\
+}
+
+
+/* The same for atomic objects:	*/
+# define GC_MALLOC_ATOMIC_WORDS(result,n) \
+{	\
+    register ptr_t op;	\
+    register ptr_t *opp;	\
+    DCL_LOCK_STATE;	\
+	\
+    opp = &(GC_aobjfreelist[n]);	\
+    FASTLOCK();	\
+    if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {	\
+        FASTUNLOCK();	\
+        (result) = GC_generic_malloc_words_small((n), PTRFREE);	\
+    } else { 	\
+        *opp = obj_link(op);	\
+        obj_link(op) = 0;	\
+        GC_words_allocd += (n);	\
+        FASTUNLOCK();	\
+        (result) = (GC_PTR) op;	\
+    }	\
+}
+
+/* And once more for two word initialized objects: */
+# define GC_CONS(result, first, second) \
+{	\
+    register ptr_t op;	\
+    register ptr_t *opp;	\
+    DCL_LOCK_STATE;	\
+	\
+    opp = &(GC_objfreelist[2]);	\
+    FASTLOCK();	\
+    if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {	\
+        FASTUNLOCK();	\
+        op = GC_generic_malloc_words_small(2, NORMAL);	\
+    } else {	\
+        *opp = obj_link(op);	\
+        GC_words_allocd += 2;	\
+        FASTUNLOCK();	\
+    } \
+    ((word *)op)[0] = (word)(first);	\
+    ((word *)op)[1] = (word)(second);	\
+    (result) = (GC_PTR) op;	\
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/include/gc_inline.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,1 @@
+# include "gc_inl.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/include/gc_nursery.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,90 @@
+
+/* 
+ * Copyright (c) 1999 by Silicon Graphics.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+/*
+ * THIS IMPLEMENTATION FOR THIS INTERFACE IS INCOMPLETE.
+ * NONE OF THIS HAS BEEN TESTED.  DO NOT USE.
+ *
+ * Comments on the interface are appreciated, especially from
+ * potential users of the interface.
+ *
+ * This is a Bartlett style copying collector for young objects.
+ * We assume for now that all objects allocated through this
+ * mechanism have pointers only in the first BITMAP_BITS words.
+ * (On a 32-bit machine, BITMAP_BITS is 30.)
+ * Objects allocated in this manner should be rarely referenced
+ * by objects not allocated either through this interface, or through
+ * the typed allocation interface.
+ * If this interface is used, we assume that type information provided
+ * through either this or the typed allocation interface is valid
+ * in a stronger sense:
+ *
+ * 1) No pointers are stored in fields not marked as such.
+ *    (Otherwise it is only necessary that objects referenced by
+ *    fields marked as nonpointers are also reachable via another
+ *    path.)
+ * 2) Values stored in pointer fields are either not addresses in
+ *    the heap, or they really are pointers.  In the latter case, it
+ *    is acceptable to move the object they refer to, and to update
+ *    the pointer.
+ *
+ * GC_free may not be invoked on objects allocated with GC_copying_malloc.
+ *
+ * No extra space is added to the end of objects allocated through this
+ * interface.  If the client needs to maintain pointers past the
+ * end, the size should be explicitly padded.
+ * 
+ * We assume that calls to this will usually be compiler generated.
+ * Hence the interface is allowed to be a bit ugly in return for speed.
+ */
+
+#include "gc_copy_descr.h"
+
+/* GC_copy_descr.h must define						*/
+/* GC_SIZE_FROM_DESCRIPTOR(descr) and					*/
+/* GC_BIT_MAP_FROM_DESCRIPTOR(descr).					*/
+/* It may either be the GC supplied version of the header file, or a	*/
+/* client specific one that derives the information from a client-	*/
+/* specific type descriptor.						*/
+
+typedef GC_PTR GC_copy_alloc_state;
+				/* Current allocator state.	*/
+				/* Multiple allocation states	*/
+				/* may be used for concurrent	*/
+				/* allocation, or to enhance	*/
+				/* locality.			*/
+				/* Should be treated as opaque.	*/
+
+/* Allocate a memory block of size given in the descriptor, and with	*/
+/* pointer layout given by the descriptor.  The resulting block may not	*/
+/* be cleared, and should immediately be initialized by the client.	*/
+/* (A concurrent GC may see an uninitialized pointer field.  If it	*/
+/* points outside the nursery, that's fine.  If it points inside, it	*/
+/* may retain an object, and be relocated.  But that's also fine, since	*/
+/* the new value will be immediately overwritten.			*/
+/* This variant acquires the allocation lock, and uses a default 	*/
+/* global allocation state.						*/
+GC_PTR GC_copying_malloc(GC_copy_descriptor);
+
+/* A variant of the above that does no locking on the fast path,	*/
+/* and passes an explicit pointer to an allocation state.		*/
+/* The allocation state is updated.					*/
+/* There will eventually need to be a macro or inline function version	*/
+/* of this.								*/
+GC_PTR GC_copying_malloc2(GC_copy_descriptor, GC_copy_alloc_state *);
+
+/* Initialize an allocation state so that it can be used for 	*/
+/* allocation.  This implicitly reserves a small section of the	*/
+/* nursery for use with this allocator.				*/
+void GC_init_copy_alloc_state(GC_copy_alloc_state *);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/include/gc_typed.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,93 @@
+/* 
+ * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
+ * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
+ * Copyright 1996 Silicon Graphics.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+/*
+ * Some simple primitives for allocation with explicit type information.
+ * Facilities for dynamic type inference may be added later.
+ * Should be used only for extremely performance critical applications,
+ * or if conservative collector leakage is otherwise a problem (unlikely).
+ * Note that this is implemented completely separately from the rest
+ * of the collector, and is not linked in unless referenced.
+ * This does not currently support GC_DEBUG in any interesting way.
+ */
+/* Boehm, May 19, 1994 2:13 pm PDT */
+
+#ifndef _GC_TYPED_H
+# define _GC_TYPED_H
+# ifndef _GC_H
+#   include "gc.h"
+# endif
+
+typedef GC_word * GC_bitmap;
+	/* The least significant bit of the first word is one if	*/
+	/* the first word in the object may be a pointer.		*/
+	
+# define GC_get_bit(bm, index) \
+		(((bm)[divWORDSZ(index)] >> modWORDSZ(index)) & 1)
+# define GC_set_bit(bm, index) \
+		(bm)[divWORDSZ(index)] |= (word)1 << modWORDSZ(index)
+
+typedef GC_word GC_descr;
+
+GC_API GC_descr GC_make_descriptor GC_PROTO((GC_bitmap bm, size_t len));
+		/* Return a type descriptor for the object whose layout	*/
+		/* is described by the argument.			*/
+		/* The least significant bit of the first word is one	*/
+		/* if the first word in the object may be a pointer.	*/
+		/* The second argument specifies the number of		*/
+		/* meaningful bits in the bitmap.  The actual object 	*/
+		/* may be larger (but not smaller).  Any additional	*/
+		/* words in the object are assumed not to contain 	*/
+		/* pointers.						*/
+		/* Returns a conservative approximation in the		*/
+		/* (unlikely) case of insufficient memory to build	*/
+		/* the descriptor.  Calls to GC_make_descriptor		*/
+		/* may consume some amount of a finite resource.  This	*/
+		/* is intended to be called once per type, not once	*/
+		/* per allocation.					*/
+
+GC_API GC_PTR GC_malloc_explicitly_typed
+			GC_PROTO((size_t size_in_bytes, GC_descr d));
+		/* Allocate an object whose layout is described by d.	*/
+		/* The resulting object MAY NOT BE PASSED TO REALLOC.	*/
+		/* The returned object is cleared.			*/
+
+GC_API GC_PTR GC_malloc_explicitly_typed_ignore_off_page
+                        GC_PROTO((size_t size_in_bytes, GC_descr d));
+		
+GC_API GC_PTR GC_calloc_explicitly_typed
+			GC_PROTO((size_t nelements,
+  				  size_t element_size_in_bytes,
+  				  GC_descr d));
+  	/* Allocate an array of nelements elements, each of the	*/
+  	/* given size, and with the given descriptor.		*/
+  	/* The elemnt size must be a multiple of the byte	*/
+  	/* alignment required for pointers.  E.g. on a 32-bit	*/
+  	/* machine with 16-bit aligned pointers, size_in_bytes	*/
+  	/* must be a multiple of 2.				*/
+	/* Returned object is cleared.				*/
+
+#ifdef GC_DEBUG
+#   define GC_MALLOC_EXPLICTLY_TYPED(bytes, d) GC_MALLOC(bytes)
+#   define GC_CALLOC_EXPLICTLY_TYPED(n, bytes, d) GC_MALLOC(n*bytes)
+#else
+#  define GC_MALLOC_EXPLICTLY_TYPED(bytes, d) \
+	GC_malloc_explicitly_typed(bytes, d)
+#  define GC_CALLOC_EXPLICTLY_TYPED(n, bytes, d) \
+	GC_calloc_explicitly_typed(n, bytes, d)
+#endif /* !GC_DEBUG */
+
+
+#endif /* _GC_TYPED_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/include/javaxfc.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,41 @@
+# ifndef GC_H
+#   include "gc.h"
+# endif
+
+/*
+ * Invoke all remaining finalizers that haven't yet been run.
+ * This is needed for strict compliance with the Java standard, 
+ * which can make the runtime guarantee that all finalizers are run.
+ * This is problematic for several reasons:
+ * 1) It means that finalizers, and all methods calle by them,
+ *    must be prepared to deal with objects that have been finalized in
+ *    spite of the fact that they are still referenced by statically
+ *    allocated pointer variables.
+ * 1) It may mean that we get stuck in an infinite loop running
+ *    finalizers which create new finalizable objects, though that's
+ *    probably unlikely.
+ * Thus this is not recommended for general use.
+ */
+void GC_finalize_all();
+
+/*
+ * A version of GC_register_finalizer that allows the object to be
+ * finalized before the objects it references.  This is again error
+ * prone, in that it makes it easy to accidentally reference finalized
+ * objects.  Again, recommended only for JVM implementors.
+ */
+void GC_register_finalizer_no_order(GC_PTR obj,
+			       GC_finalization_proc fn, GC_PTR cd,
+			       GC_finalization_proc *ofn, GC_PTR * ocd);
+
+void GC_debug_register_finalizer_no_order(GC_PTR obj,
+			       GC_finalization_proc fn, GC_PTR cd,
+			       GC_finalization_proc *ofn, GC_PTR * ocd);
+
+#ifdef GC_DEBUG
+#   define GC_REGISTER_FINALIZER(p, f, d, of, od) \
+	GC_debug_register_finalizer_no_order(p, f, d, of, od)
+#else
+#   define GC_REGISTER_FINALIZER(p, f, d, of, od) \
+	GC_register_finalizer_no_order(p, f, d, of, od)
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/include/leak_detector.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,7 @@
+#define GC_DEBUG
+#include "gc.h"
+#define malloc(n) GC_MALLOC(n)
+#define calloc(m,n) GC_MALLOC(m*n)
+#define free(p) GC_FREE(p)
+#define realloc(p,n) GC_REALLOC(n)
+#define CHECK_LEAKS() GC_gcollect()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/include/new_gc_alloc.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,452 @@
+/*
+ * Copyright (c) 1996-1998 by Silicon Graphics.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+//
+// This is a revision of gc_alloc.h for SGI STL versions > 3.0
+// Unlike earlier versions, it supplements the standard "alloc.h"
+// instead of replacing it.
+//
+// This is sloppy about variable names used in header files.
+// It also doesn't yet understand the new header file names or
+// namespaces.
+//
+// This assumes the collector has been compiled with -DATOMIC_UNCOLLECTABLE
+// and -DALL_INTERIOR_POINTERS.  We also recommend
+// -DREDIRECT_MALLOC=GC_uncollectable_malloc.
+//
+// Some of this could be faster in the explicit deallocation case.
+// In particular, we spend too much time clearing objects on the
+// free lists.  That could be avoided.
+//
+// This uses template classes with static members, and hence does not work
+// with g++ 2.7.2 and earlier.
+//
+// Unlike its predecessor, this one simply defines
+// 	gc_alloc
+//	single_client_gc_alloc
+//	traceable_alloc
+//	single_client_traceable_alloc
+//
+// It does not redefine alloc.  Nor does it change the default allocator,
+// though the user may wish to do so.  (The argument against changing
+// the default allocator is that it may introduce subtle link compatibility
+// problems.  The argument for changing it is that the usual default
+// allocator is usually a very bad choice for a garbage collected environment.)
+//
+
+#ifndef GC_ALLOC_H
+
+#include "gc.h"
+#include <alloc.h>
+
+#define GC_ALLOC_H
+
+#include <stddef.h>
+#include <string.h>
+
+// The following need to match collector data structures.
+// We can't include gc_priv.h, since that pulls in way too much stuff.
+// This should eventually be factored out into another include file.
+
+extern "C" {
+    extern void ** const GC_objfreelist_ptr;
+    extern void ** const GC_aobjfreelist_ptr;
+    extern void ** const GC_uobjfreelist_ptr;
+    extern void ** const GC_auobjfreelist_ptr;
+
+    extern void GC_incr_words_allocd(size_t words);
+    extern void GC_incr_mem_freed(size_t words);
+
+    extern char * GC_generic_malloc_words_small(size_t word, int kind);
+}
+
+// Object kinds; must match PTRFREE, NORMAL, UNCOLLECTABLE, and
+// AUNCOLLECTABLE in gc_priv.h.
+
+enum { GC_PTRFREE = 0, GC_NORMAL = 1, GC_UNCOLLECTABLE = 2,
+       GC_AUNCOLLECTABLE = 3 };
+
+enum { GC_max_fast_bytes = 255 };
+
+enum { GC_bytes_per_word = sizeof(char *) };
+
+enum { GC_byte_alignment = 8 };
+
+enum { GC_word_alignment = GC_byte_alignment/GC_bytes_per_word };
+
+inline void * &GC_obj_link(void * p)
+{   return *(void **)p;  }
+
+// Compute a number of words >= n+1 bytes.
+// The +1 allows for pointers one past the end.
+inline size_t GC_round_up(size_t n)
+{
+    return ((n + GC_byte_alignment)/GC_byte_alignment)*GC_word_alignment;
+}
+
+// The same but don't allow for extra byte.
+inline size_t GC_round_up_uncollectable(size_t n)
+{
+    return ((n + GC_byte_alignment - 1)/GC_byte_alignment)*GC_word_alignment;
+}
+
+template <int dummy>
+class GC_aux_template {
+public:
+  // File local count of allocated words.  Occasionally this is
+  // added into the global count.  A separate count is necessary since the
+  // real one must be updated with a procedure call.
+  static size_t GC_words_recently_allocd;
+
+  // Same for uncollectable mmory.  Not yet reflected in either
+  // GC_words_recently_allocd or GC_non_gc_bytes.
+  static size_t GC_uncollectable_words_recently_allocd;
+
+  // Similar counter for explicitly deallocated memory.
+  static size_t GC_mem_recently_freed;
+
+  // Again for uncollectable memory.
+  static size_t GC_uncollectable_mem_recently_freed;
+
+  static void * GC_out_of_line_malloc(size_t nwords, int kind);
+};
+
+template <int dummy>
+size_t GC_aux_template<dummy>::GC_words_recently_allocd = 0;
+
+template <int dummy>
+size_t GC_aux_template<dummy>::GC_uncollectable_words_recently_allocd = 0;
+
+template <int dummy>
+size_t GC_aux_template<dummy>::GC_mem_recently_freed = 0;
+
+template <int dummy>
+size_t GC_aux_template<dummy>::GC_uncollectable_mem_recently_freed = 0;
+
+template <int dummy>
+void * GC_aux_template<dummy>::GC_out_of_line_malloc(size_t nwords, int kind)
+{
+    GC_words_recently_allocd += GC_uncollectable_words_recently_allocd;
+    GC_non_gc_bytes +=
+                GC_bytes_per_word * GC_uncollectable_words_recently_allocd;
+    GC_uncollectable_words_recently_allocd = 0;
+
+    GC_mem_recently_freed += GC_uncollectable_mem_recently_freed;
+    GC_non_gc_bytes -= 
+                GC_bytes_per_word * GC_uncollectable_mem_recently_freed;
+    GC_uncollectable_mem_recently_freed = 0;
+
+    GC_incr_words_allocd(GC_words_recently_allocd);
+    GC_words_recently_allocd = 0;
+
+    GC_incr_mem_freed(GC_mem_recently_freed);
+    GC_mem_recently_freed = 0;
+
+    return GC_generic_malloc_words_small(nwords, kind);
+}
+
+typedef GC_aux_template<0> GC_aux;
+
+// A fast, single-threaded, garbage-collected allocator
+// We assume the first word will be immediately overwritten.
+// In this version, deallocation is not a noop, and explicit
+// deallocation is likely to help performance.
+template <int dummy>
+class single_client_gc_alloc_template {
+    public:
+     	static void * allocate(size_t n)
+        {
+	    size_t nwords = GC_round_up(n);
+	    void ** flh;
+	    void * op;
+
+  	    if (n > GC_max_fast_bytes) return GC_malloc(n);
+	    flh = GC_objfreelist_ptr + nwords;
+	    if (0 == (op = *flh)) {
+		return GC_aux::GC_out_of_line_malloc(nwords, GC_NORMAL);
+	    }
+	    *flh = GC_obj_link(op);
+	    GC_aux::GC_words_recently_allocd += nwords;
+	    return op;
+        }
+     	static void * ptr_free_allocate(size_t n)
+        {
+	    size_t nwords = GC_round_up(n);
+	    void ** flh;
+	    void * op;
+
+  	    if (n > GC_max_fast_bytes) return GC_malloc_atomic(n);
+	    flh = GC_aobjfreelist_ptr + nwords;
+	    if (0 == (op = *flh)) {
+		return GC_aux::GC_out_of_line_malloc(nwords, GC_PTRFREE);
+	    }
+	    *flh = GC_obj_link(op);
+	    GC_aux::GC_words_recently_allocd += nwords;
+	    return op;
+        }
+	static void deallocate(void *p, size_t n)
+	{
+            size_t nwords = GC_round_up(n);
+            void ** flh;
+	   
+	    if (n > GC_max_fast_bytes)  {
+		GC_free(p);
+	    } else {
+	        flh = GC_objfreelist_ptr + nwords;
+	        GC_obj_link(p) = *flh;
+		memset((char *)p + GC_bytes_per_word, 0,
+		       GC_bytes_per_word * (nwords - 1));
+	        *flh = p;
+	        GC_aux::GC_mem_recently_freed += nwords;
+	    }
+	}
+	static void ptr_free_deallocate(void *p, size_t n)
+	{
+            size_t nwords = GC_round_up(n);
+            void ** flh;
+	   
+	    if (n > GC_max_fast_bytes) {
+		GC_free(p);
+	    } else {
+	    	flh = GC_aobjfreelist_ptr + nwords;
+	    	GC_obj_link(p) = *flh;
+	    	*flh = p;
+	    	GC_aux::GC_mem_recently_freed += nwords;
+	    }
+	}
+};
+
+typedef single_client_gc_alloc_template<0> single_client_gc_alloc;
+
+// Once more, for uncollectable objects.
+template <int dummy>
+class single_client_traceable_alloc_template {
+    public:
+     	static void * allocate(size_t n)
+        {
+	    size_t nwords = GC_round_up_uncollectable(n);
+	    void ** flh;
+	    void * op;
+
+  	    if (n > GC_max_fast_bytes) return GC_malloc_uncollectable(n);
+	    flh = GC_uobjfreelist_ptr + nwords;
+	    if (0 == (op = *flh)) {
+		return GC_aux::GC_out_of_line_malloc(nwords, GC_UNCOLLECTABLE);
+	    }
+	    *flh = GC_obj_link(op);
+	    GC_aux::GC_uncollectable_words_recently_allocd += nwords;
+	    return op;
+        }
+     	static void * ptr_free_allocate(size_t n)
+        {
+	    size_t nwords = GC_round_up_uncollectable(n);
+	    void ** flh;
+	    void * op;
+
+  	    if (n > GC_max_fast_bytes) return GC_malloc_atomic_uncollectable(n);
+	    flh = GC_auobjfreelist_ptr + nwords;
+	    if (0 == (op = *flh)) {
+		return GC_aux::GC_out_of_line_malloc(nwords, GC_AUNCOLLECTABLE);
+	    }
+	    *flh = GC_obj_link(op);
+	    GC_aux::GC_uncollectable_words_recently_allocd += nwords;
+	    return op;
+        }
+	static void deallocate(void *p, size_t n)
+	{
+            size_t nwords = GC_round_up_uncollectable(n);
+            void ** flh;
+	   
+	    if (n > GC_max_fast_bytes)  {
+		GC_free(p);
+	    } else {
+	        flh = GC_uobjfreelist_ptr + nwords;
+	        GC_obj_link(p) = *flh;
+	        *flh = p;
+	        GC_aux::GC_uncollectable_mem_recently_freed += nwords;
+	    }
+	}
+	static void ptr_free_deallocate(void *p, size_t n)
+	{
+            size_t nwords = GC_round_up_uncollectable(n);
+            void ** flh;
+	   
+	    if (n > GC_max_fast_bytes) {
+		GC_free(p);
+	    } else {
+	    	flh = GC_auobjfreelist_ptr + nwords;
+	    	GC_obj_link(p) = *flh;
+	    	*flh = p;
+	    	GC_aux::GC_uncollectable_mem_recently_freed += nwords;
+	    }
+	}
+};
+
+typedef single_client_traceable_alloc_template<0> single_client_traceable_alloc;
+
+template < int dummy >
+class gc_alloc_template {
+    public:
+     	static void * allocate(size_t n) { return GC_malloc(n); }
+     	static void * ptr_free_allocate(size_t n)
+		{ return GC_malloc_atomic(n); }
+	static void deallocate(void *, size_t) { }
+	static void ptr_free_deallocate(void *, size_t) { }
+};
+
+typedef gc_alloc_template < 0 > gc_alloc;
+
+template < int dummy >
+class traceable_alloc_template {
+    public:
+     	static void * allocate(size_t n) { return GC_malloc_uncollectable(n); }
+     	static void * ptr_free_allocate(size_t n)
+		{ return GC_malloc_atomic_uncollectable(n); }
+	static void deallocate(void *p, size_t) { GC_free(p); }
+	static void ptr_free_deallocate(void *p, size_t) { GC_free(p); }
+};
+
+typedef traceable_alloc_template < 0 > traceable_alloc;
+
+// We want to specialize simple_alloc so that it does the right thing
+// for all pointerfree types.  At the moment there is no portable way to
+// even approximate that.  The following approximation should work for
+// SGI compilers, and recent versions of g++.
+
+# define __GC_SPECIALIZE(T,alloc) \
+class simple_alloc<T, alloc> { \
+public: \
+    static T *allocate(size_t n) \
+	{ return 0 == n? 0 : \
+			 (T*) alloc::ptr_free_allocate(n * sizeof (T)); } \
+    static T *allocate(void) \
+	{ return (T*) alloc::ptr_free_allocate(sizeof (T)); } \
+    static void deallocate(T *p, size_t n) \
+	{ if (0 != n) alloc::ptr_free_deallocate(p, n * sizeof (T)); } \
+    static void deallocate(T *p) \
+	{ alloc::ptr_free_deallocate(p, sizeof (T)); } \
+};
+
+__GC_SPECIALIZE(char, gc_alloc)
+__GC_SPECIALIZE(int, gc_alloc)
+__GC_SPECIALIZE(unsigned, gc_alloc)
+__GC_SPECIALIZE(float, gc_alloc)
+__GC_SPECIALIZE(double, gc_alloc)
+
+__GC_SPECIALIZE(char, traceable_alloc)
+__GC_SPECIALIZE(int, traceable_alloc)
+__GC_SPECIALIZE(unsigned, traceable_alloc)
+__GC_SPECIALIZE(float, traceable_alloc)
+__GC_SPECIALIZE(double, traceable_alloc)
+
+__GC_SPECIALIZE(char, single_client_gc_alloc)
+__GC_SPECIALIZE(int, single_client_gc_alloc)
+__GC_SPECIALIZE(unsigned, single_client_gc_alloc)
+__GC_SPECIALIZE(float, single_client_gc_alloc)
+__GC_SPECIALIZE(double, single_client_gc_alloc)
+
+__GC_SPECIALIZE(char, single_client_traceable_alloc)
+__GC_SPECIALIZE(int, single_client_traceable_alloc)
+__GC_SPECIALIZE(unsigned, single_client_traceable_alloc)
+__GC_SPECIALIZE(float, single_client_traceable_alloc)
+__GC_SPECIALIZE(double, single_client_traceable_alloc)
+
+#ifdef __STL_USE_STD_ALLOCATORS
+
+__STL_BEGIN_NAMESPACE
+
+template <class _T>
+struct _Alloc_traits<_T, gc_alloc >
+{
+  static const bool _S_instanceless = true;
+  typedef simple_alloc<_T, gc_alloc > _Alloc_type;
+  typedef __allocator<_T, gc_alloc > allocator_type;
+};
+
+inline bool operator==(const gc_alloc&,
+                       const gc_alloc&)
+{
+  return true;
+}
+
+inline bool operator!=(const gc_alloc&,
+                       const gc_alloc&)
+{
+  return false;
+}
+
+template <class _T>
+struct _Alloc_traits<_T, single_client_gc_alloc >
+{
+  static const bool _S_instanceless = true;
+  typedef simple_alloc<_T, single_client_gc_alloc > _Alloc_type;
+  typedef __allocator<_T, single_client_gc_alloc > allocator_type;
+};
+
+inline bool operator==(const single_client_gc_alloc&,
+                       const single_client_gc_alloc&)
+{
+  return true;
+}
+
+inline bool operator!=(const single_client_gc_alloc&,
+                       const single_client_gc_alloc&)
+{
+  return false;
+}
+
+template <class _T>
+struct _Alloc_traits<_T, traceable_alloc >
+{
+  static const bool _S_instanceless = true;
+  typedef simple_alloc<_T, traceable_alloc > _Alloc_type;
+  typedef __allocator<_T, traceable_alloc > allocator_type;
+};
+
+inline bool operator==(const traceable_alloc&,
+                       const traceable_alloc&)
+{
+  return true;
+}
+
+inline bool operator!=(const traceable_alloc&,
+                       const traceable_alloc&)
+{
+  return false;
+}
+
+template <class _T>
+struct _Alloc_traits<_T, single_client_traceable_alloc >
+{
+  static const bool _S_instanceless = true;
+  typedef simple_alloc<_T, single_client_traceable_alloc > _Alloc_type;
+  typedef __allocator<_T, single_client_traceable_alloc > allocator_type;
+};
+
+inline bool operator==(const single_client_traceable_alloc&,
+                       const single_client_traceable_alloc&)
+{
+  return true;
+}
+
+inline bool operator!=(const single_client_traceable_alloc&,
+                       const single_client_traceable_alloc&)
+{
+  return false;
+}
+
+__STL_END_NAMESPACE
+
+#endif /* __STL_USE_STD_ALLOCATORS */
+
+#endif /* GC_ALLOC_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/include/private/cord_pos.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,118 @@
+/* 
+ * Copyright (c) 1993-1994 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+/* Boehm, May 19, 1994 2:23 pm PDT */
+# ifndef CORD_POSITION_H
+
+/* The representation of CORD_position.  This is private to the	*/
+/* implementation, but the size is known to clients.  Also	*/
+/* the implementation of some exported macros relies on it.	*/
+/* Don't use anything defined here and not in cord.h.		*/
+
+# define MAX_DEPTH 48
+	/* The maximum depth of a balanced cord + 1.		*/
+	/* We don't let cords get deeper than MAX_DEPTH.	*/
+
+struct CORD_pe {
+    CORD pe_cord;
+    size_t pe_start_pos;
+};
+
+/* A structure describing an entry on the path from the root 	*/
+/* to current position.						*/
+typedef struct CORD_Pos {
+    size_t cur_pos;
+    int path_len;
+#	define CORD_POS_INVALID (0x55555555)
+		/* path_len == INVALID <==> position invalid */
+    const char *cur_leaf;	/* Current leaf, if it is a string.	*/
+    				/* If the current leaf is a function,	*/
+    				/* then this may point to function_buf	*/
+    				/* containing the next few characters.	*/
+    				/* Always points to a valid string	*/
+    				/* containing the current character 	*/
+    				/* unless cur_end is 0.			*/
+    size_t cur_start;	/* Start position of cur_leaf	*/
+    size_t cur_end;	/* Ending position of cur_leaf	*/
+    			/* 0 if cur_leaf is invalid.	*/
+    struct CORD_pe path[MAX_DEPTH + 1];
+    	/* path[path_len] is the leaf corresponding to cur_pos	*/
+    	/* path[0].pe_cord is the cord we point to.		*/
+#   define FUNCTION_BUF_SZ 8
+    char function_buf[FUNCTION_BUF_SZ];	/* Space for next few chars	*/
+    					/* from function node.		*/
+} CORD_pos[1];
+
+/* Extract the cord from a position:	*/
+CORD CORD_pos_to_cord(CORD_pos p);
+	
+/* Extract the current index from a position:	*/
+size_t CORD_pos_to_index(CORD_pos p);
+	
+/* Fetch the character located at the given position:	*/
+char CORD_pos_fetch(CORD_pos p);
+	
+/* Initialize the position to refer to the give cord and index.	*/
+/* Note that this is the most expensive function on positions:	*/
+void CORD_set_pos(CORD_pos p, CORD x, size_t i);
+	
+/* Advance the position to the next character.	*/
+/* P must be initialized and valid.		*/
+/* Invalidates p if past end:			*/
+void CORD_next(CORD_pos p);
+
+/* Move the position to the preceding character.	*/
+/* P must be initialized and valid.			*/
+/* Invalidates p if past beginning:			*/
+void CORD_prev(CORD_pos p);
+	
+/* Is the position valid, i.e. inside the cord?		*/
+int CORD_pos_valid(CORD_pos p);
+
+char CORD__pos_fetch(CORD_pos);
+void CORD__next(CORD_pos);
+void CORD__prev(CORD_pos);
+
+#define CORD_pos_fetch(p)	\
+    (((p)[0].cur_end != 0)? \
+     	(p)[0].cur_leaf[(p)[0].cur_pos - (p)[0].cur_start] \
+     	: CORD__pos_fetch(p))
+
+#define CORD_next(p)	\
+    (((p)[0].cur_pos + 1 < (p)[0].cur_end)? \
+    	(p)[0].cur_pos++ \
+    	: (CORD__next(p), 0))
+
+#define CORD_prev(p)	\
+    (((p)[0].cur_end != 0 && (p)[0].cur_pos > (p)[0].cur_start)? \
+    	(p)[0].cur_pos-- \
+    	: (CORD__prev(p), 0))
+
+#define CORD_pos_to_index(p) ((p)[0].cur_pos)
+
+#define CORD_pos_to_cord(p) ((p)[0].path[0].pe_cord)
+
+#define CORD_pos_valid(p) ((p)[0].path_len != CORD_POS_INVALID)
+
+/* Some grubby stuff for performance-critical friends:	*/
+#define CORD_pos_chars_left(p) ((long)((p)[0].cur_end) - (long)((p)[0].cur_pos))
+	/* Number of characters in cache.  <= 0 ==> none	*/
+
+#define CORD_pos_advance(p,n) ((p)[0].cur_pos += (n) - 1, CORD_next(p))
+	/* Advance position by n characters	*/
+	/* 0 < n < CORD_pos_chars_left(p)	*/
+
+#define CORD_pos_cur_char_addr(p) \
+	(p)[0].cur_leaf + ((p)[0].cur_pos - (p)[0].cur_start)
+	/* address of current character in cache.	*/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/include/private/gc_hdrs.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,303 @@
+/* 
+ * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
+ * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+/* Boehm, July 11, 1995 11:54 am PDT */
+# ifndef GC_HEADERS_H
+# define GC_HEADERS_H
+typedef struct hblkhdr hdr;
+
+# if CPP_WORDSZ != 32 && CPP_WORDSZ < 36
+	--> Get a real machine.
+# endif
+
+/*
+ * The 2 level tree data structure that is used to find block headers.
+ * If there are more than 32 bits in a pointer, the top level is a hash
+ * table.
+ *
+ * This defines HDR, GET_HDR, and SET_HDR, the main macros used to
+ * retrieve and set object headers.  We also define some variants to
+ * retrieve 2 unrelated headers in interleaved fashion.  This
+ * slightly improves scheduling.
+ *
+ * Since 5.0 alpha 5, we can also take advantage of a header lookup
+ * cache.  This is a locally declared direct mapped cache, used inside
+ * the marker.  The HC_GET_HDR and HC_GET_HDR2 macros use and maintain this
+ * cache.  Assuming we get reasonable hit rates, this shaves a few
+ * memory references from each pointer validation.
+ */
+
+# if CPP_WORDSZ > 32
+#   define HASH_TL
+# endif
+
+/* Define appropriate out-degrees for each of the two tree levels	*/
+# ifdef SMALL_CONFIG
+#   define LOG_BOTTOM_SZ 11
+	/* Keep top index size reasonable with smaller blocks. */
+# else
+#   define LOG_BOTTOM_SZ 10
+# endif
+# ifndef HASH_TL
+#   define LOG_TOP_SZ (WORDSZ - LOG_BOTTOM_SZ - LOG_HBLKSIZE)
+# else
+#   define LOG_TOP_SZ 11
+# endif
+# define TOP_SZ (1 << LOG_TOP_SZ)
+# define BOTTOM_SZ (1 << LOG_BOTTOM_SZ)
+
+#ifndef SMALL_CONFIG
+# define USE_HDR_CACHE
+#endif
+
+/* #define COUNT_HDR_CACHE_HITS  */
+
+extern hdr * GC_invalid_header; /* header for an imaginary block 	*/
+				/* containing no objects.		*/
+
+
+/* Check whether p and corresponding hhdr point to long or invalid	*/
+/* object.  If so, advance them	to					*/
+/* beginning of	block, or set hhdr to GC_invalid_header.		*/
+#define ADVANCE(p, hhdr, source) \
+            if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { \
+              p = GC_FIND_START(p, hhdr, (word)source); \
+              if (p == 0) { \
+		hhdr = GC_invalid_header; \
+	      } else { \
+                hhdr = GC_find_header(p); \
+	      } \
+    	    }
+
+#ifdef USE_HDR_CACHE
+
+# ifdef COUNT_HDR_CACHE_HITS
+    extern word GC_hdr_cache_hits;
+    extern word GC_hdr_cache_misses;
+#   define HC_HIT() ++GC_hdr_cache_hits
+#   define HC_MISS() ++GC_hdr_cache_misses
+# else
+#   define HC_HIT()
+#   define HC_MISS()
+# endif
+
+  typedef struct hce {
+    word block_addr;  	/* right shifted by LOG_HBLKSIZE */
+    hdr * hce_hdr;
+  } hdr_cache_entry;
+
+# define HDR_CACHE_SIZE 8  /* power of 2 */
+
+# define DECLARE_HDR_CACHE \
+	hdr_cache_entry hdr_cache[HDR_CACHE_SIZE]
+
+# define INIT_HDR_CACHE BZERO(hdr_cache, sizeof(hdr_cache));
+
+# define HCE(h) hdr_cache + (((word)(h) >> LOG_HBLKSIZE) & (HDR_CACHE_SIZE-1))
+
+# define HCE_VALID_FOR(hce,h) ((hce) -> block_addr == \
+				((word)(h) >> LOG_HBLKSIZE))
+
+# define HCE_HDR(h) ((hce) -> hce_hdr)
+
+
+/* Analogous to GET_HDR, except that in the case of large objects, it	*/
+/* Returns the header for the object beginning, and updates p.		*/
+/* Returns &GC_bad_header instead of 0.  All of this saves a branch	*/
+/* in the fast path.							*/
+# define HC_GET_HDR(p, hhdr, source) \
+	{ \
+	  hdr_cache_entry * hce = HCE(p); \
+	  if (HCE_VALID_FOR(hce, p)) { \
+	    HC_HIT(); \
+	    hhdr = hce -> hce_hdr; \
+	  } else { \
+	    HC_MISS(); \
+	    GET_HDR(p, hhdr); \
+	    ADVANCE(p, hhdr, source); \
+	    hce -> block_addr = (word)(p) >> LOG_HBLKSIZE; \
+	    hce -> hce_hdr = hhdr; \
+	  } \
+	}
+
+# define HC_GET_HDR2(p1, hhdr1, source1, p2, hhdr2, source2) \
+	{ \
+	  hdr_cache_entry * hce1 = HCE(p1); \
+	  hdr_cache_entry * hce2 = HCE(p2); \
+	  if (HCE_VALID_FOR(hce1, p1)) { \
+	    HC_HIT(); \
+	    hhdr1 = hce1 -> hce_hdr; \
+	  } else { \
+	    HC_MISS(); \
+	    GET_HDR(p1, hhdr1); \
+	    ADVANCE(p1, hhdr1, source1); \
+	    hce1 -> block_addr = (word)(p1) >> LOG_HBLKSIZE; \
+	    hce1 -> hce_hdr = hhdr1; \
+	  } \
+	  if (HCE_VALID_FOR(hce2, p2)) { \
+	    HC_HIT(); \
+	    hhdr2 = hce2 -> hce_hdr; \
+	  } else { \
+	    HC_MISS(); \
+	    GET_HDR(p2, hhdr2); \
+	    ADVANCE(p2, hhdr2, source2); \
+	    hce2 -> block_addr = (word)(p2) >> LOG_HBLKSIZE; \
+	    hce2 -> hce_hdr = hhdr2; \
+	  } \
+	}
+
+#else /* !USE_HDR_CACHE */
+
+# define DECLARE_HDR_CACHE
+
+# define INIT_HDR_CACHE
+
+# define HC_GET_HDR(p, hhdr, source) \
+	{ \
+	  GET_HDR(p, hhdr); \
+	  ADVANCE(p, hhdr, source); \
+	}
+
+# define HC_GET_HDR2(p1, hhdr1, source1, p2, hhdr2, source2) \
+	{ \
+	  GET_HDR2(p1, hhdr1, p2, hhdr2); \
+	  ADVANCE(p1, hhdr1, source1); \
+	  ADVANCE(p2, hhdr2, source2); \
+	}
+
+#endif
+
+typedef struct bi {
+    hdr * index[BOTTOM_SZ];
+	/*
+ 	 * The bottom level index contains one of three kinds of values:
+	 * 0 means we're not responsible for this block,
+	 *   or this is a block other than the first one in a free block.
+	 * 1 < (long)X <= MAX_JUMP means the block starts at least
+	 *        X * HBLKSIZE bytes before the current address.
+	 * A valid pointer points to a hdr structure. (The above can't be
+	 * valid pointers due to the GET_MEM return convention.)
+	 */
+    struct bi * asc_link;	/* All indices are linked in	*/
+    				/* ascending order...		*/
+    struct bi * desc_link;	/* ... and in descending order.	*/
+    word key;			/* high order address bits.	*/
+# ifdef HASH_TL
+    struct bi * hash_link;	/* Hash chain link.		*/
+# endif
+} bottom_index;
+
+/* extern bottom_index GC_all_nils; - really part of GC_arrays */
+
+/* extern bottom_index * GC_top_index []; - really part of GC_arrays */
+				/* Each entry points to a bottom_index.	*/
+				/* On a 32 bit machine, it points to 	*/
+				/* the index for a set of high order	*/
+				/* bits equal to the index.  For longer	*/
+				/* addresses, we hash the high order	*/
+				/* bits to compute the index in 	*/
+				/* GC_top_index, and each entry points	*/
+				/* to a hash chain.			*/
+				/* The last entry in each chain is	*/
+				/* GC_all_nils.				*/
+
+
+# define MAX_JUMP (HBLKSIZE - 1)
+
+# define HDR_FROM_BI(bi, p) \
+		((bi)->index[((word)(p) >> LOG_HBLKSIZE) & (BOTTOM_SZ - 1)])
+# ifndef HASH_TL
+#   define BI(p) (GC_top_index \
+		[(word)(p) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE)])
+#   define HDR_INNER(p) HDR_FROM_BI(BI(p),p)
+#   ifdef SMALL_CONFIG
+#	define HDR(p) GC_find_header((ptr_t)(p))
+#   else
+#	define HDR(p) HDR_INNER(p)
+#   endif
+#   define GET_BI(p, bottom_indx) (bottom_indx) = BI(p)
+#   define GET_HDR(p, hhdr) (hhdr) = HDR(p)
+#   define SET_HDR(p, hhdr) HDR_INNER(p) = (hhdr)
+#   define GET_HDR_ADDR(p, ha) (ha) = &(HDR_INNER(p))
+#   define GET_HDR2(p1, hhdr1, p2, hhdr2) \
+	{ GET_HDR(p1, hhdr1); GET_HDR(p2, hhdr2); }
+# else /* hash */
+/*  Hash function for tree top level */
+#   define TL_HASH(hi) ((hi) & (TOP_SZ - 1))
+/*  Set bottom_indx to point to the bottom index for address p */
+#   define GET_BI(p, bottom_indx) \
+	{ \
+	    register word hi = \
+	        (word)(p) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE); \
+	    register bottom_index * _bi = GC_top_index[TL_HASH(hi)]; \
+	    \
+	    while (_bi -> key != hi && _bi != GC_all_nils) \
+	    	_bi = _bi -> hash_link; \
+	    (bottom_indx) = _bi; \
+	}
+#   define GET_HDR_ADDR(p, ha) \
+	{ \
+	    register bottom_index * bi; \
+	    \
+	    GET_BI(p, bi);	\
+	    (ha) = &(HDR_FROM_BI(bi, p)); \
+	}
+#   define GET_HDR(p, hhdr) { register hdr ** _ha; GET_HDR_ADDR(p, _ha); \
+			      (hhdr) = *_ha; }
+#   define SET_HDR(p, hhdr) { register hdr ** _ha; GET_HDR_ADDR(p, _ha); \
+			      *_ha = (hhdr); }
+#   define HDR(p) GC_find_header((ptr_t)(p))
+    /* And some interleaved versions for two pointers at once.  	*/
+    /* This hopefully helps scheduling on processors like IA64.		*/
+#   define GET_BI2(p1, bottom_indx1, p2, bottom_indx2) \
+	{ \
+	    register word hi1 = \
+	        (word)(p1) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE); \
+	    register word hi2 = \
+	        (word)(p2) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE); \
+	    register bottom_index * _bi1 = GC_top_index[TL_HASH(hi1)]; \
+	    register bottom_index * _bi2 = GC_top_index[TL_HASH(hi2)]; \
+	    \
+	    while (_bi1 -> key != hi1 && _bi1 != GC_all_nils) \
+	    	_bi1 = _bi1 -> hash_link; \
+	    while (_bi2 -> key != hi2 && _bi2 != GC_all_nils) \
+	    	_bi2 = _bi2 -> hash_link; \
+	    (bottom_indx1) = _bi1; \
+	    (bottom_indx2) = _bi2; \
+	}
+#   define GET_HDR_ADDR2(p1, ha1, p2, ha2) \
+	{ \
+	    register bottom_index * bi1; \
+	    register bottom_index * bi2; \
+	    \
+	    GET_BI2(p1, bi1, p2, bi2);	\
+	    (ha1) = &(HDR_FROM_BI(bi1, p1)); \
+	    (ha2) = &(HDR_FROM_BI(bi2, p2)); \
+	}
+#   define GET_HDR2(p1, hhdr1, p2, hhdr2) \
+	{ register hdr ** _ha1;  \
+	  register hdr ** _ha2;  \
+	  GET_HDR_ADDR2(p1, _ha1, p2, _ha2); \
+	  (hhdr1) = *_ha1;  \
+	  (hhdr2) = *_ha2;  \
+	}
+# endif
+			    
+/* Is the result a forwarding address to someplace closer to the	*/
+/* beginning of the block or NIL?					*/
+# define IS_FORWARDING_ADDR_OR_NIL(hhdr) ((unsigned long) (hhdr) <= MAX_JUMP)
+
+/* Get an HBLKSIZE aligned address closer to the beginning of the block */
+/* h.  Assumes hhdr == HDR(h) and IS_FORWARDING_ADDR(hhdr).		*/
+# define FORWARDED_ADDR(h, hhdr) ((struct hblk *)(h) - (unsigned long)(hhdr))
+# endif /*  GC_HEADERS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgc/include/private/gc_priv.h	Mon Oct 02 03:03:13 2000 +0000
@@ -0,0 +1,1884 @@
+/* 
+ * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
+ * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
+ * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
+ * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved.
+ *
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+/* Boehm, February 16, 1996 2:30 pm PST */
+ 
+
+# ifndef GC_PRIVATE_H
+# define GC_PRIVATE_H
+
+#if defined(mips) && defined(SYSTYPE_BSD) && defined(sony_news)
+    /* sony RISC NEWS, NEWSOS 4 */
+#   define BSD_TIME
+/*    typedef long ptrdiff_t;   -- necessary on some really old systems	*/
+#endif
+
+#if defined(mips) && defined(SYSTYPE_BSD43)
+    /* MIPS RISCOS 4 */
+#   define BSD_TIME
+#endif
+
+#ifdef BSD_TIME
+#   include <sys/types.h>
+#   include <sys/time.h>
+#   include <sys/resource.h>
+#endif /* BSD_TIME */
+
+# ifndef GC_H
+#   include "gc.h"
+# endif
+
+typedef GC_word word;
+typedef GC_signed_word signed_word;
+
+# ifndef GCCONFIG_H
+#   include "gcconfig.h"
+# endif
+
+# ifndef HEADERS_H
+#   include "gc_hdrs.h"
+# endif
+
+typedef int GC_bool;
+# define TRUE 1
+# define FALSE 0
+
+typedef char * ptr_t;	/* A generic pointer to which we can add	*/
+			/* byte displacements.				*/
+			/* Preferably identical to caddr_t, if it 	*/
+			/* exists.					*/
+			
+#if defined(__STDC__)
+#   include <stdlib.h>
+#   if !(defined( sony_news ) )
+#       include <stddef.h>
+#   endif
+#   define VOLATILE volatile
+#else
+#   ifdef MSWIN32
+#   	include <stdlib.h>
+#   endif
+#   define VOLATILE
+#endif
+
+#define CONST GC_CONST
+
+#if 0 /* was once defined for AMIGA */
+#   define GC_FAR __far
+#else
+#   define GC_FAR
+#endif
+
+
+/*********************************/
+/*                               */
+/* Definitions for conservative  */
+/* collector                     */
+/*                               */
+/*********************************/
+
+/*********************************/
+/*                               */
+/* Easily changeable parameters  */
+/*                               */
+/*********************************/
+
+#define STUBBORN_ALLOC	/* Define stubborn allocation primitives	*/
+#if defined(SRC_M3) || defined(SMALL_CONFIG)
+# undef STUBBORN_ALLOC
+#endif
+
+
+/* #define ALL_INTERIOR_POINTERS */
+		    /* Forces all pointers into the interior of an 	*/
+		    /* object to be considered valid.  Also causes the	*/
+		    /* sizes of all objects to be inflated by at least 	*/
+		    /* one byte.  This should suffice to guarantee	*/
+		    /* that in the presence of a compiler that does	*/
+		    /* not perform garbage-collector-unsafe		*/
+		    /* optimizations, all portable, strictly ANSI	*/
+		    /* conforming C programs should be safely usable	*/
+		    /* with malloc replaced by GC_malloc and free	*/
+		    /* calls removed.  There are several disadvantages: */
+		    /* 1. There are probably no interesting, portable,	*/
+		    /*    strictly ANSI	conforming C programs.		*/
+		    /* 2. This option makes it hard for the collector	*/
+		    /*    to allocate space that is not ``pointed to''  */
+		    /*    by integers, etc.  Under SunOS 4.X with a 	*/
+		    /*    statically linked libc, we empiricaly		*/
+		    /*    observed that it would be difficult to 	*/
+		    /*	  allocate individual objects larger than 100K.	*/
+		    /* 	  Even if only smaller objects are allocated,	*/
+		    /*    more swap space is likely to be needed.       */
+		    /*    Fortunately, much of this will never be	*/
+		    /*    touched.					*/
+		    /* If you can easily avoid using this option, do.	*/
+		    /* If not, try to keep individual objects small.	*/
+		    
+#define PRINTSTATS  /* Print garbage collection statistics          	*/
+		    /* For less verbose output, undefine in reclaim.c 	*/
+
+#define PRINTTIMES  /* Print the amount of time consumed by each garbage   */
+		    /* collection.                                         */
+
+#define PRINTBLOCKS /* Print object sizes associated with heap blocks,     */
+		    /* whether the objects are atomic or composite, and    */
+		    /* whether or not the block was found to be empty      */
+		    /* during the reclaim phase.  Typically generates       */
+		    /* about one screenful per garbage collection.         */
+#undef PRINTBLOCKS
+
+#ifdef SILENT
+#  ifdef PRINTSTATS
+#    undef PRINTSTATS
+#  endif
+#  ifdef PRINTTIMES
+#    undef PRINTTIMES
+#  endif
+#  ifdef PRINTNBLOCKS
+#    undef PRINTNBLOCKS
+#  endif
+#endif
+
+#if defined(PRINTSTATS) && !defined(GATHERSTATS)
+#   define GATHERSTATS
+#endif
+
+#ifdef FINALIZE_ON_DEMAND
+#   define GC_INVOKE_FINALIZERS()
+#else
+#   define GC_INVOKE_FINALIZERS() (void)GC_invoke_finalizers()
+#endif
+
+#define MERGE_SIZES /* Round up some object sizes, so that fewer distinct */
+		    /* free lists are actually maintained.  This applies  */
+		    /* only to the top level routines in misc.c, not to   */
+		    /* user generated code that calls GC_allocobj and     */
+		    /* GC_allocaobj directly.                             */
+		    /* Slows down average programs slightly.  May however */
+		    /* substantially reduce fragmentation if allocation   */
+		    /* request sizes are widely scattered.                */
+		    /* May save significant amounts of space for obj_map  */
+		    /* entries.						  */
+
+/* ALIGN_DOUBLE requires MERGE_SIZES at present. */
+# if defined(ALIGN_DOUBLE) && !defined(MERGE_SIZES)
+#   define MERGE_SIZES
+# endif
+
+#if defined(ALL_INTERIOR_POINTERS) && !defined(DONT_ADD_BYTE_AT_END)
+# define ADD_BYTE_AT_END
+#endif
+
+
+# ifndef LARGE_CONFIG
+#   define MINHINCR 16	/* Minimum heap increment, in blocks of HBLKSIZE  */
+			/* Must be multiple of largest page size.	  */
+#   define MAXHINCR 512	/* Maximum heap increment, in blocks              */
+# else
+#   define MINHINCR 64
+#   define MAXHINCR 4096
+# endif
+
+# define TIME_LIMIT 50	   /* We try to keep pause times from exceeding	 */
+			   /* this by much. In milliseconds.		 */
+
+# define BL_LIMIT GC_black_list_spacing
+			   /* If we need a block of N bytes, and we have */
+			   /* a block of N + BL_LIMIT bytes available, 	 */
+			   /* and N > BL_LIMIT,				 */
+			   /* but all possible positions in it are 	 */
+			   /* blacklisted, we just use it anyway (and	 */
+			   /* print a warning, if warnings are enabled). */
+			   /* This risks subsequently leaking the block	 */
+			   /* due to a false reference.  But not using	 */
+			   /* the block risks unreasonable immediate	 */
+			   /* heap growth.				 */
+
+/*********************************/
+/*                               */
+/* Stack saving for debugging	 */
+/*                               */
+/*********************************/
+
+#ifdef SAVE_CALL_CHAIN
+
+/*
+ * Number of frames and arguments to save in objects allocated by
+ * debugging allocator.
+ */
+#   define NFRAMES 6	/* Number of frames to save. Even for		*/
+			/* alignment reasons.				*/
+#   define NARGS 2	/* Mumber of arguments to save for each call.	*/
+
+#   define NEED_CALLINFO
+
+/* Fill in the pc and argument information for up to NFRAMES of my	*/
+/* callers.  Ignore my frame and my callers frame.			*/
+void GC_save_callers (/* struct callinfo info[NFRAMES] */);
+
+void GC_print_callers (/* struct callinfo info[NFRAMES] */);
+
+#else
+
+# ifdef GC_ADD_CALLER
+#   define NFRAMES 1
+#   define NARGS 0
+#   define NEED_CALLINFO
+# endif
+
+#endif
+
+#ifdef NEED_CALLINFO
+    struct callinfo {
+	word ci_pc;
+#	if NARGS > 0
+	    word ci_arg[NARGS];	/* bit-wise complement to avoid retention */
+#	endif
+#	if defined(ALIGN_DOUBLE) && (NFRAMES * (NARGS + 1)) % 2 == 1
+	    /* Likely alignment problem. */
+	    word ci_dummy;
+#	endif
+    };
+#endif
+
+
+/*********************************/
+/*                               */
+/* OS interface routines	 */
+/*                               */
+/*********************************/
+
+#ifdef BSD_TIME
+#   undef CLOCK_TYPE
+#   undef GET_TIME
+#   undef MS_TIME_DIFF
+#   define CLOCK_TYPE struct timeval
+#   define GET_TIME(x) { struct rusage rusage; \
+			 getrusage (RUSAGE_SELF,  &rusage); \
+			 x = rusage.ru_utime; }
+#   define MS_TIME_DIFF(a,b) ((double) (a.tv_sec - b.tv_sec) * 1000.0 \
+                               + (double) (a.tv_usec - b.tv_usec) / 1000.0)
+#else /* !BSD_TIME */
+# ifdef MSWIN32
+#   include <windows.h>
+#   include <winbase.h>
+#   define CLOCK_TYPE DWORD
+#   define GET_TIME(x) x = GetTickCount()
+#   define MS_TIME_DIFF(a,b) ((long)((a)-(b)))
+# else /* !MSWIN32, !BSD_TIME */
+#   include <time.h>
+#   if !defined(__STDC__) && defined(SPARC) && defined(SUNOS4)
+      clock_t clock();	/* Not in time.h, where it belongs	*/
+#   endif
+#   if defined(FREEBSD) && !defined(CLOCKS_PER_SEC)
+#     include <machine/limits.h>
+#     define CLOCKS_PER_SEC CLK_TCK
+#   endif
+#   if !defined(CLOCKS_PER_SEC)
+#     define CLOCKS_PER_SEC 1000000
+/*
+ * This is technically a bug in the implementation.  ANSI requires that
+ * CLOCKS_PER_SEC be defined.  But at least under SunOS4.1.1, it isn't.
+ * Also note that the combination of ANSI C and POSIX is incredibly gross
+ * here. The type clock_t is used by both clock() and times().  But on
+ * some machines these use different notions of a clock tick,  CLOCKS_PER_SEC
+ * seems to apply only to clock.  Hence we use it here.  On many machines,
+ * including SunOS, clock actually uses units of microseconds (which are
+ * not really clock ticks).
+ */
+#   endif
+#   define CLOCK_TYPE clock_t
+#   define GET_TIME(x) x = clock()
+#   define MS_TIME_DIFF(a,b) ((unsigned long) \
+		(1000.0*(double)((a)-(b))/(double)CLOCKS_PER_SEC))
+# endif /* !MSWIN32 */
+#endif /* !BSD_TIME */
+
+/* We use bzero and bcopy internally.  They may not be available.	*/
+# if defined(SPARC) && defined(SUNOS4)
+#   define BCOPY_EXISTS
+# endif
+# if defined(M68K) && defined(AMIGA)
+#   define BCOPY_EXISTS
+# endif
+# if defined(M68K) && defined(NEXT)
+#   define BCOPY_EXISTS
+# endif
+# if defined(VAX)
+#   define BCOPY_EXISTS
+# endif
+# if defined(AMIGA)
+#   include <string.h>
+#   define BCOPY_EXISTS
+# endif
+
+# ifndef BCOPY_EXISTS
+#   include <string.h>
+#   define BCOPY(x,y,n) memcpy(y, x, (size_t)(n))
+#   define BZERO(x,n)  memset(x, 0, (size_t)(n))
+# else
+#   define BCOPY(x,y,n) bcopy((char *)(x),(char *)(y),(int)(n))
+#   define BZERO(x,n) bzero((char *)(x),(int)(n))
+# endif
+
+/* HBLKSIZE aligned allocation.  0 is taken to mean failure 	*/
+/* space is assumed to be cleared.				*/
+/* In the case os USE_MMAP, the argument must also be a 	*/
+/* physical page size.						*/
+/* GET_MEM is currently not assumed to retrieve 0 filled space, */
+/* though we should perhaps take advantage of the case in which */
+/* does.							*/
+# ifdef PCR
+    char * real_malloc();
+#   define GET_MEM(bytes) HBLKPTR(real_malloc((size_t)bytes + GC_page_size) \
+				  + GC_page_size-1)
+# else
+#   ifdef OS2
+      void * os2_alloc(size_t bytes);
+#     define GET_MEM(bytes) HBLKPTR((ptr_t)os2_alloc((size_t)bytes \
+				    + GC_page_size) \
+                                    + GC_page_size-1)
+#   else
+#     if defined(AMIGA) || defined(NEXT) || defined(MACOSX) || defined(DOS4GW)
+#       define GET_MEM(bytes) HBLKPTR((size_t) \
+				      calloc(1, (size_t)bytes + GC_page_size) \
+                                      + GC_page_size-1)
+#     else
+#	ifdef MSWIN32
+          extern ptr_t GC_win32_get_mem();
+#         define GET_MEM(bytes) (struct hblk *)GC_win32_get_mem(bytes)
+#	else
+#	  ifdef MACOS
+#	    if defined(USE_TEMPORARY_MEMORY)
+		extern Ptr GC_MacTemporaryNewPtr(size_t size,
+						 Boolean clearMemory);
+#               define GET_MEM(bytes) HBLKPTR( \
+		    GC_MacTemporaryNewPtr(bytes + GC_page_size, true) \
+		    + GC_page_size-1)
+#	    else
+#         	    define GET_MEM(bytes) HBLKPTR( \
+			NewPtrClear(bytes + GC_page_size) + GC_page_size-1)
+#	    endif
+#	  else
+              extern ptr_t GC_unix_get_mem();
+#             define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes)
+#	  endif
+#	endif
+#     endif
+#   endif
+# endif
+
+/*
+ * Mutual exclusion between allocator/collector routines.
+ * Needed if there is more than one allocator thread.
+ * FASTLOCK() is assumed to try to acquire the lock in a cheap and
+ * dirty way that is acceptable for a few instructions, e.g. by
+ * inhibiting preemption.  This is assumed to have succeeded only
+ * if a subsequent call to FASTLOCK_SUCCEEDED() returns TRUE.
+ * FASTUNLOCK() is called whether or not FASTLOCK_SUCCEEDED().
+ * If signals cannot be tolerated with the FASTLOCK held, then
+ * FASTLOCK should disable signals.  The code executed under
+ * FASTLOCK is otherwise immune to interruption, provided it is
+ * not restarted.
+ * DCL_LOCK_STATE declares any local variables needed by LOCK and UNLOCK
+ * and/or DISABLE_SIGNALS and ENABLE_SIGNALS and/or FASTLOCK.
+ * (There is currently no equivalent for FASTLOCK.)
+ */  
+# ifdef THREADS
+#  ifdef PCR_OBSOLETE	/* Faster, but broken with multiple lwp's	*/
+#    include  "th/PCR_Th.h"
+#    include  "th/PCR_ThCrSec.h"
+     extern struct PCR_Th_MLRep GC_allocate_ml;
+#    define DCL_LOCK_STATE  PCR_sigset_t GC_old_sig_mask
+#    define LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml) 
+#    define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml)
+#    define FASTLOCK() PCR_ThCrSec_EnterSys()
+     /* Here we cheat (a lot): */
+#        define FASTLOCK_SUCCEEDED() (*(int *)(&GC_allocate_ml) == 0)
+		/* TRUE if nobody currently holds the lock */
+#    define FASTUNLOCK() PCR_ThCrSec_ExitSys()
+#  endif
+#  ifdef PCR
+#    include <base/PCR_Base.h>
+#    include <th/PCR_Th.h>
+     extern PCR_Th_ML GC_allocate_ml;
+#    define DCL_LOCK_STATE \
+	 PCR_ERes GC_fastLockRes; PCR_sigset_t GC_old_sig_mask
+#    define LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml)
+#    define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml)
+#    define FASTLOCK() (GC_fastLockRes = PCR_Th_ML_Try(&GC_allocate_ml))
+#    define FASTLOCK_SUCCEEDED() (GC_fastLockRes == PCR_ERes_okay)
+#    define FASTUNLOCK()  {\
+        if( FASTLOCK_SUCCEEDED() ) PCR_Th_ML_Release(&GC_allocate_ml); }
+#  endif
+#  ifdef SRC_M3
+     extern word RT0u__inCritical;
+#    define LOCK() RT0u__inCritical++
+#    define UNLOCK() RT0u__inCritical--
+#  endif
+#  ifdef SOLARIS_THREADS
+#    include <thread.h>
+#    include <signal.h>
+     extern mutex_t GC_allocate_ml;
+#    define LOCK() mutex_lock(&GC_allocate_ml);
+#    define UNLOCK() mutex_unlock(&GC_allocate_ml);
+#  endif
+#  if defined(LINUX_THREADS) 
+#   if defined(I386)|| defined(POWERPC) || defined(ALPHA) || defined(IA64) \
+    || defined(M68K)
+#    include <pthread.h>
+#    define USE_SPIN_LOCK
+#    if defined(I386)
+       inline static int GC_test_and_set(volatile unsigned int *addr) {
+	  int oldval;
+	  /* Note: the "xchg" instruction does not need a "lock" prefix */
+	  __asm__ __volatile__("xchgl %0, %1"
+		: "=r"(oldval), "=m"(*(addr))
+		: "0"(1), "m"(*(addr)));
+	  return oldval;
+       }
+#    endif
+#    if defined(IA64)
+       inline static int GC_test_and_set(volatile unsigned int *addr) {
+	  int oldval;
+	  __asm__ __volatile__("xchg4 %0=%1,%2"
+		: "=r"(oldval), "=m"(*addr)
+		: "r"(1), "1"(*addr));
+	  return oldval;
+       }
+       inline static void GC_clear(volatile unsigned int *addr) {
+	 __asm__ __volatile__("st4.rel %0=r0" : "=m" (*addr));
+       }
+#      define GC_CLEAR_DEFINED
+#    endif
+#    ifdef M68K
+       /* Contributed by Tony Mantler.  I'm not sure how well it was	*/
+       /* tested.							*/
+       inline static int GC_test_and_set(volatile unsigned int *addr) {
+          char oldval; /* this must be no longer than 8 bits */
+
+          /* The return value is semi-phony. */
+          /* 'tas' sets bit 7 while the return */
+          /* value pretends bit 0 was set */
+          __asm__ __volatile__(
+                 "tas %1@; sne %0; negb %0"
+                 : "=d" (oldval)
+                 : "a" (addr));
+          return oldval;
+       }
+#    endif
+#    if defined(POWERPC)
+      inline static int GC_test_and_set(volatile unsigned int *addr) {
+        int oldval;
+        int temp = 1; // locked value
+
+        __asm__ __volatile__(
+               "1:\tlwarx %0,0,%3\n"   // load and reserve
+               "\tcmpwi %0, 0\n"       // if load is
+               "\tbne 2f\n"            //   non-zero, return already set
+               "\tstwcx. %2,0,%1\n"    // else store conditional
+               "\tbne- 1b\n"           // retry if lost reservation
+               "2:\t\n"                // oldval is zero if we set
+              : "=&r"(oldval), "=p"(addr)
+              : "r"(temp), "1"(addr)
+              : "memory");
+        return (int)oldval;
+      }
+      inline static void GC_clear(volatile unsigned int *addr) {
+	 __asm__ __volatile__("eieio");
+         *(addr) = 0;
+      }
+#     define GC_CLEAR_DEFINED
+#    endif
+#    ifdef ALPHA
+      inline static int GC_test_and_set(volatile unsigned int * addr)
+      {
+        unsigned long oldvalue;
+        unsigned long temp;
+
+        __asm__ __volatile__(
+                             "1:     ldl_l %0,%1\n"
+                             "       and %0,%3,%2\n"
+                             "       bne %2,2f\n"
+                             "       xor %0,%3,%0\n"
+                             "       stl_c %0,%1\n"
+                             "       beq %0,3f\n"
+                             "       mb\n"
+                             "2:\n"
+                             ".section .text2,\"ax\"\n"
+                             "3:     br 1b\n"
+                             ".previous"
+                             :"=&r" (temp), "=m" (*addr), "=&r" (oldvalue)
+                             :"Ir" (1), "m" (*addr));
+
+        return oldvalue;
+      }
+      /* Should probably also define GC_clear, since it needs	*/
+      /* a memory barrier ??					*/
+#    endif /* ALPHA */
+#    ifdef ARM32
+      inline static int GC_test_and_set(volatile unsigned int *addr) {
+        int oldval;
+        /* SWP on ARM is very similar to XCHG on x86.  Doesn't lock the
+         * bus because there are no SMP ARM machines.  If/when there are,
+         * this code will likely need to be updated. */
+        /* See linuxthreads/sysdeps/arm/pt-machine.h in glibc-2.1 */
+        __asm__ __volatile__("swp %0, %1, [%2]"
+      			     : "=r"(oldval)
+      			     : "r"(1), "r"(addr));
+        return oldval;
+      }
+#    endif
+#    ifndef GC_CLEAR_DEFINED
+       inline static void GC_clear(volatile unsigned int *addr) {
+	  /* Try to discourage gcc from moving anything past this. */
+	  __asm__ __volatile__(" ");
+          *(addr) = 0;
+       }
+#    endif
+
+     extern volatile unsigned int GC_allocate_lock;
+     extern pthread_t GC_lock_holder;
+     extern void GC_lock(void);
+	/* Allocation lock holder.  Only set if acquired by client through */
+	/* GC_call_with_alloc_lock.					   */
+#    define SET_LOCK_HOLDER() GC_lock_holder = pthread_self()
+#    define NO_THREAD (pthread_t)(-1)
+#    define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
+#    define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self()))
+#    define LOCK() \
+		{ if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); }
+#    define UNLOCK() \
+		GC_clear(&GC_allocate_lock)
+     extern VOLATILE GC_bool GC_collecting;
+#    define ENTER_GC() \
+		{ \
+		    GC_collecting = 1; \
+		}
+#    define EXIT_GC() GC_collecting = 0;
+#   else /* LINUX_THREADS on hardware for which we don't know how	*/
+	 /* to do test and set.						*/
+#    include <pthread.h>
+     extern pthread_mutex_t GC_allocate_ml;
+#    define LOCK() pthread_mutex_lock(&GC_allocate_ml)
+#    define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
+#   endif
+#  endif /* LINUX_THREADS */
+#  if defined(HPUX_THREADS)
+#    include <pthread.h>
+     extern pthread_mutex_t GC_allocate_ml;
+#    define LOCK() pthread_mutex_lock(&GC_allocate_ml)
+#    define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
+#  endif
+#  if defined(IRIX_THREADS) || defined(IRIX_JDK_THREADS) 
+     /* This may also eventually be appropriate for HPUX_THREADS */
+#    include <pthread.h>
+#    ifndef HPUX_THREADS
+	/* This probably should never be included, but I can't test	*/
+	/* on Irix anymore.						*/
+#       include <mutex.h>
+#    endif
+
+#    ifndef HPUX_THREADS
+#      if __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \
+	|| !defined(_COMPILER_VERSION) || _COMPILER_VERSION < 700
+#        define GC_test_and_set(addr, v) test_and_set(addr,v)
+#      else
+#	 define GC_test_and_set(addr, v) __test_and_set(addr,v)
+#      endif
+#    else
+       /* I couldn't find a way to do this inline on HP/UX	*/
+#    endif
+     extern unsigned long GC_allocate_lock;
+	/* This is not a mutex because mutexes that obey the (optional) 	*/
+	/* POSIX scheduling rules are subject to convoys in high contention	*/
+	/* applications.  This is basically a spin lock.			*/
+     extern pthread_t GC_lock_holder;
+     extern void GC_lock(void);
+	/* Allocation lock holder.  Only set if acquired by client through */
+	/* GC_call_with_alloc_lock.					   */
+#    define SET_LOCK_HOLDER() GC_lock_holder = pthread_self()
+#    define NO_THREAD (pthread_t)(-1)
+#    define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
+#    define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self()))
+#    ifdef HPUX_THREADS
+#      define LOCK() { if (!GC_test_and_clear(&GC_allocate_lock)) GC_lock(); }
+       /* The following is INCORRECT, since the memory model is too weak. */
+#      define UNLOCK() { GC_noop1(&GC_allocate_lock); \
+			*(volatile unsigned long *)(&GC_allocate_lock) = 1; }
+#    else
+#      define LOCK() { if (GC_test_and_set(&GC_allocate_lock, 1)) GC_lock(); }
+#      if __mips >= 3 && (defined (_ABIN32) || defined(_ABI64)) \
+	   && defined(_COMPILER_VERSION) && _COMPILER_VERSION >= 700
+#	    define UNLOCK() __lock_release(&GC_allocate_lock)
+#      else
+	    /* The function call in the following should prevent the	*/
+	    /* compiler from moving assignments to below the UNLOCK.	*/
+	    /* This is probably not necessary for ucode or gcc 2.8.	*/
+	    /* It may be necessary for Ragnarok and future gcc		*/
+	    /* versions.						*/
+#           define UNLOCK() { GC_noop1(&GC_allocate_lock); \
+			*(volatile unsigned long *)(&GC_allocate_lock) = 0; }
+#      endif
+#    endif
+     extern VOLATILE GC_bool GC_collecting;
+#    define ENTER_GC() \
+		{ \
+		    GC_collecting = 1; \
+		}
+#    define EXIT_GC() GC_collecting = 0;
+#  endif /* IRIX_THREADS || IRIX_JDK_THREADS */
+#  ifdef WIN32_THREADS
+#    include <windows.h>
+     GC_API CRITICAL_SECTION GC_allocate_ml;
+#    define LOCK() EnterCriticalSection(&GC_allocate_ml);
+#    define UNLOCK() LeaveCriticalSection(&GC_allocate_ml);
+#  endif
+#  ifndef SET_LOCK_HOLDER
+#      define SET_LOCK_HOLDER()
+#      define UNSET_LOCK_HOLDER()
+#      define I_HOLD_LOCK() FALSE
+		/* Used on platforms were locks can be reacquired,	*/
+		/* so it doesn't matter if we lie.			*/
+#  endif
+# else
+#    define LOCK()
+#    define UNLOCK()
+# endif
+# ifndef SET_LOCK_HOLDER
+#   define SET_LOCK_HOLDER()
+#   define UNSET_LOCK_HOLDER()
+#   define I_HOLD_LOCK() FALSE
+		/* Used on platforms were locks can be reacquired,	*/
+		/* so it doesn't matter if we lie.			*/
+# endif
+# ifndef ENTER_GC
+#   define ENTER_GC()
+#   define EXIT_GC()
+# endif
+
+# ifndef DCL_LOCK_STATE
+#   define DCL_LOCK_STATE
+# endif
+# ifndef FASTLOCK
+#   define FASTLOCK() LOCK()
+#   define FASTLOCK_SUCCEEDED() TRUE
+#   define FASTUNLOCK() UNLOCK()
+# endif
+
+/* Delay any interrupts or signals that may abort this thread.  Data	*/
+/* structures are in a consistent state outside this pair of calls.	*/
+/* ANSI C allows both to be empty (though the standard isn't very	*/
+/* clear on that point).  Standard malloc implementations are usually	*/
+/* neither interruptable nor thread-safe, and thus correspond to	*/
+/* empty definitions.							*/
+# ifdef PCR
+#   define DISABLE_SIGNALS() \
+		 PCR_Th_SetSigMask(PCR_allSigsBlocked,&GC_old_sig_mask)
+#   define ENABLE_SIGNALS() \
+		PCR_Th_SetSigMask(&GC_old_sig_mask, NIL)
+# else
+#   if defined(SRC_M3) || defined(AMIGA) || defined(SOLARIS_THREADS) \
+	|| defined(MSWIN32) || defined(MACOS) || defined(DJGPP) \
+	|| defined(NO_SIGNALS) || defined(IRIX_THREADS) \
+	|| defined(IRIX_JDK_THREADS) || defined(LINUX_THREADS) 
+			/* Also useful for debugging.		*/
+	/* Should probably use thr_sigsetmask for SOLARIS_THREADS. */
+#     define DISABLE_SIGNALS()
+#     define ENABLE_SIGNALS()
+#   else
+#     define DISABLE_SIGNALS() GC_disable_signals()
+	void GC_disable_signals();
+#     define ENABLE_SIGNALS() GC_enable_signals()
+	void GC_enable_signals();
+#   endif
+# endif
+
+/*
+ * Stop and restart mutator threads.
+ */
+# ifdef PCR
+#     include "th/PCR_ThCtl.h"
+#     define STOP_WORLD() \
+ 	PCR_ThCtl_SetExclusiveMode(PCR_ThCtl_ExclusiveMode_stopNormal, \
+ 				   PCR_allSigsBlocked, \
+ 				   PCR_waitForever)
+#     define START_WORLD() \
+	PCR_ThCtl_SetExclusiveMode(PCR_ThCtl_ExclusiveMode_null, \
+ 				   PCR_allSigsBlocked, \
+ 				   PCR_waitForever);
+# else
+#   if defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \
+	|| defined(IRIX_THREADS) || defined(LINUX_THREADS) \
+	|| defined(IRIX_JDK_THREADS) || defined(HPUX_THREADS)
+      void GC_stop_world();
+      void GC_start_world();
+#     define STOP_WORLD() GC_stop_world()
+#     define START_WORLD() GC_start_world()
+#   else
+#     define STOP_WORLD()
+#     define START_WORLD()
+#   endif
+# endif
+
+/* Abandon ship */
+# ifdef PCR
+#   define ABORT(s) PCR_Base_Panic(s)
+# else
+#   ifdef SMALL_CONFIG
+#	define ABORT(msg) abort();
+#   else
+	GC_API void GC_abort();
+#       define ABORT(msg) GC_abort(msg);
+#   endif
+# endif
+
+/* Exit abnormally, but without making a mess (e.g. out of memory) */
+# ifdef PCR
+#   define EXIT() PCR_Base_Exit(1,PCR_waitForever)
+# else
+#   define EXIT() (void)exit(1)
+# endif
+
+/* Print warning message, e.g. almost out of memory.	*/
+# define WARN(msg,arg) (*GC_current_warn_proc)(msg, (GC_word)(arg))
+extern GC_warn_proc GC_current_warn_proc;
+
+/*********************************/
+/*                               */
+/* Word-size-dependent defines   */
+/*                               */
+/*********************************/
+
+#if CPP_WORDSZ == 32
+#  define WORDS_TO_BYTES(x)   ((x)<<2)
+#  define BYTES_TO_WORDS(x)   ((x)>>2)
+#  define LOGWL               ((word)5)    /* log[2] of CPP_WORDSZ */
+#  define modWORDSZ(n) ((n) & 0x1f)        /* n mod size of word	    */
+#  if ALIGNMENT != 4
+#	define UNALIGNED
+#  endif
+#endif
+
+#if CPP_WORDSZ == 64
+#  define WORDS_TO_BYTES(x)   ((x)<<3)
+#  define BYTES_TO_WORDS(x)   ((x)>>3)
+#  define LOGWL               ((word)6)    /* log[2] of CPP_WORDSZ */
+#  define modWORDSZ(n) ((n) & 0x3f)        /* n mod size of word	    */
+#  if ALIGNMENT != 8
+#	define UNALIGNED
+#  endif
+#endif
+
+#define WORDSZ ((word)CPP_WORDSZ)
+#define SIGNB  ((word)1 << (WORDSZ-1))
+#define BYTES_PER_WORD      ((word)(sizeof (word)))
+#define ONES                ((word)(-1))
+#define divWORDSZ(n) ((n) >> LOGWL)	   /* divide n by size of word      */
+
+/*********************/
+/*                   */
+/*  Size Parameters  */
+/*                   */
+/*********************/
+
+/*  heap block size, bytes. Should be power of 2 */
+
+#ifndef HBLKSIZE
+# ifdef SMALL_CONFIG
+#   define CPP_LOG_HBLKSIZE 10
+# else
+#   if CPP_WORDSZ == 32
+#     define CPP_LOG_HBLKSIZE 12
+#   else
+#     define CPP_LOG_HBLKSIZE 13
+#   endif
+# endif
+#else
+# if HBLKSIZE == 512
+#   define CPP_LOG_HBLKSIZE 9
+# endif
+# if HBLKSIZE == 1024
+#   define CPP_LOG_HBLKSIZE 10
+# endif
+# if HBLKSIZE == 2048
+#   define CPP_LOG_HBLKSIZE 11
+# endif
+# if HBLKSIZE == 4096
+#   define CPP_LOG_HBLKSIZE 12
+# endif
+# if HBLKSIZE == 8192
+#   define CPP_LOG_HBLKSIZE 13
+# endif
+# if HBLKSIZE == 16384
+#   define CPP_LOG_HBLKSIZE 14
+# endif
+# ifndef CPP_LOG_HBLKSIZE
+    --> fix HBLKSIZE
+# endif
+# undef HBLKSIZE
+#endif
+# define CPP_HBLKSIZE (1 << CPP_LOG_HBLKSIZE)
+# define LOG_HBLKSIZE   ((word)CPP_LOG_HBLKSIZE)
+# define HBLKSIZE ((word)CPP_HBLKSIZE)
+
+
+/*  max size objects supported by freelist (larger objects may be   */
+/*  allocated, but less efficiently)                                */
+
+#define CPP_MAXOBJSZ    BYTES_TO_WORDS(CPP_HBLKSIZE/2)
+#define MAXOBJSZ ((word)CPP_MAXOBJSZ)
+		
+# define divHBLKSZ(n) ((n) >> LOG_HBLKSIZE)
+
+# define HBLK_PTR_DIFF(p,q) divHBLKSZ((ptr_t)p - (ptr_t)q)
+	/* Equivalent to subtracting 2 hblk pointers.	*/
+	/* We do it this way because a compiler should	*/
+	/* find it hard to use an integer division	*/
+	/* instead of a shift.  The bundled SunOS 4.1	*/
+	/* o.w. sometimes pessimizes the subtraction to	*/
+	/* involve a call to .div.			*/
+ 
+# define modHBLKSZ(n) ((n) & (HBLKSIZE-1))
+ 
+# define HBLKPTR(objptr) ((struct hblk *)(((word) (objptr)) & ~(HBLKSIZE-1)))
+
+# define HBLKDISPL(objptr) (((word) (objptr)) & (HBLKSIZE-1))
+
+/* Round up byte allocation requests to integral number of words, etc. */
+# ifdef ADD_BYTE_AT_END
+#   define ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + WORDS_TO_BYTES(1))
+#   ifdef ALIGN_DOUBLE
+#       define ALIGNED_WORDS(n) (BYTES_TO_WORDS((n) + WORDS_TO_BYTES(2)) & ~1)
+#   else
+#       define ALIGNED_WORDS(n) ROUNDED_UP_WORDS(n)
+#   endif
+#   define SMALL_OBJ(bytes) ((bytes) < WORDS_TO_BYTES(MAXOBJSZ))
+#   define ADD_SLOP(bytes) ((bytes)+1)
+# else
+#   define ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + (WORDS_TO_BYTES(1) - 1))
+#   ifdef ALIGN_DOUBLE
+#       define ALIGNED_WORDS(n) \
+			(BYTES_TO_WORDS((n) + WORDS_TO_BYTES(2) - 1) & ~1)
+#   else
+#       define ALIGNED_WORDS(n) ROUNDED_UP_WORDS(n)
+#   endif
+#   define SMALL_OBJ(bytes) ((bytes) <= WORDS_TO_BYTES(MAXOBJSZ))
+#   define ADD_SLOP(bytes) (bytes)
+# endif
+
+
+/*
+ * Hash table representation of sets of pages.  This assumes it is
+ * OK to add spurious entries to sets.
+ * Used by black-listing code, and perhaps by dirty bit maintenance code.
+ */
+ 
+# ifdef LARGE_CONFIG
+#   define LOG_PHT_ENTRIES  17
+# else
+#   define LOG_PHT_ENTRIES  14	/* Collisions are likely if heap grows	*/
+				/* to more than 16K hblks = 64MB.	*/
+				/* Each hash table occupies 2K bytes.   */
+# endif
+# define PHT_ENTRIES ((word)1 << LOG_PHT_ENTRIES)
+# define PHT_SIZE (PHT_ENTRIES >> LOGWL)
+typedef word page_hash_table[PHT_SIZE];
+
+# define PHT_HASH(addr) ((((word)(addr)) >> LOG_HBLKSIZE) & (PHT_ENTRIES - 1))
+
+# define get_pht_entry_from_index(bl, index) \
+		(((bl)[divWORDSZ(index)] >> modWORDSZ(index)) & 1)
+# define set_pht_entry_from_index(bl, index) \
+		(bl)[divWORDSZ(index)] |= (word)1 << modWORDSZ(index)
+# define clear_pht_entry_from_index(bl, index) \
+		(bl)[divWORDSZ(index)] &= ~((word)1 << modWORDSZ(index))
+	
+
+
+/********************************************/
+/*                                          */
+/*    H e a p   B l o c k s                 */
+/*                                          */
+/********************************************/
+
+/*  heap block header */
+#define HBLKMASK   (HBLKSIZE-1)
+
+#define BITS_PER_HBLK (HBLKSIZE * 8)
+
+#define MARK_BITS_PER_HBLK (BITS_PER_HBLK/CPP_WORDSZ)
+	   /* upper bound                                    */
+	   /* We allocate 1 bit/word.  Only the first word   */
+	   /* in each object is actually marked.             */
+
+# ifdef ALIGN_DOUBLE
+#   define MARK_BITS_SZ (((MARK_BITS_PER_HBLK + 2*CPP_WORDSZ - 1) \
+			  / (2*CPP_WORDSZ))*2)
+# else
+#   define MARK_BITS_SZ ((MARK_BITS_PER_HBLK + CPP_WORDSZ - 1)/CPP_WORDSZ)
+# endif
+	   /* Upper bound on number of mark words per heap block  */
+
+struct hblkhdr {
+    word hb_sz;  /* If in use, size in words, of objects in the block. */
+		 /* if free, the size in bytes of the whole block      */
+    struct hblk * hb_next; 	/* Link field for hblk free list	 */
+    				/* and for lists of chunks waiting to be */
+    				/* reclaimed.				 */
+    struct hblk * hb_prev;	/* Backwards link for free list.	*/
+    word hb_descr;   		/* object descriptor for marking.  See	*/
+    				/* mark.h.				*/
+    char* hb_map;	/* A pointer to a pointer validity map of the block. */
+    		      	/* See GC_obj_map.				     */
+    		     	/* Valid for all blocks with headers.		     */
+    		     	/* Free blocks point to GC_invalid_map.		     */
+    unsigned char hb_obj_kind;
+    			 /* Kind of objects in the block.  Each kind 	*/
+    			 /* identifies a mark procedure and a set of 	*/
+    			 /* list headers.  Sometimes called regions.	*/
+    unsigned char hb_flags;
+#	define IGNORE_OFF_PAGE	1	/* Ignore pointers that do not	*/
+					/* point to the first page of 	*/
+					/* this object.			*/
+#	define WAS_UNMAPPED 2	/* This is a free block, which has	*/
+				/* been unmapped from the address 	*/
+				/* space.				*/
+				/* GC_remap must be invoked on it	*/
+				/* before it can be reallocated.	*/
+				/* Only set with USE_MUNMAP.		*/
+    unsigned short hb_last_reclaimed;
+    				/* Value of GC_gc_no when block was	*/
+    				/* last allocated or swept. May wrap.   */
+				/* For a free block, this is maintained */
+				/* unly for USE_MUNMAP, and indicates	*/
+				/* when the header was allocated, or	*/
+				/* when the size of the block last	*/
+				/* changed.				*/
+    word hb_marks[MARK_BITS_SZ];
+			    /* Bit i in the array refers to the             */
+			    /* object starting at the ith word (header      */
+			    /* INCLUDED) in the heap block.                 */
+			    /* The lsb of word 0 is numbered 0.		    */
+			    /* Unused bits are invalid, and are 	    */
+			    /* occasionally set, e.g for uncollectable	    */
+			    /* objects.					    */
+};
+
+/*  heap block body */
+
+# define DISCARD_WORDS 0
+	/* Number of words to be dropped at the beginning of each block	*/
+	/* Must be a multiple of WORDSZ.  May reasonably be nonzero	*/
+	/* on machines that don't guarantee longword alignment of	*/
+	/* pointers, so that the number of false hits is minimized.	*/
+	/* 0 and WORDSZ are probably the only reasonable values.	*/
+
+# define BODY_SZ ((HBLKSIZE-WORDS_TO_BYTES(DISCARD_WORDS))/sizeof(word))
+
+struct hblk {
+#   if (DISCARD_WORDS != 0)
+        word garbage[DISCARD_WORDS];
+#   endif
+    word hb_body[BODY_SZ];
+};
+
+# define HDR_WORDS ((word)DISCARD_WORDS)
+# define HDR_BYTES ((word)WORDS_TO_BYTES(DISCARD_WORDS))
+
+# define OBJ_SZ_TO_BLOCKS(sz) \
+    divHBLKSZ(HDR_BYTES + WORDS_TO_BYTES(sz) + HBLKSIZE-1)
+    /* Size of block (in units of HBLKSIZE) needed to hold objects of	*/
+    /* given sz (in words).						*/
+
+/* Object free list link */
+# define obj_link(p) (*(ptr_t *)(p))
+
+/* The type of mark procedures.  This really belongs in gc_mark.h.	*/
+/* But we put it here, so that we can avoid scanning the mark proc	*/
+/* table.								*/
+typedef struct ms_entry * (*mark_proc)(/* word * addr,
+					  struct ms_entry *mark_stack_ptr,
+					  struct ms_entry *mark_stack_limit,
+					  word env */);
+# define LOG_MAX_MARK_PROCS 6
+# define MAX_MARK_PROCS (1 << LOG_MAX_MARK_PROCS)
+
+/* Root sets.  Logically private to mark_rts.c.  But we don't want the	*/
+/* tables scanned, so we put them here.					*/
+/* MAX_ROOT_SETS is the maximum number of ranges that can be 	*/
+/* registered as static roots. 					*/
+# ifdef LARGE_CONFIG
+#   define MAX_ROOT_SETS 4096
+# else
+#   ifdef PCR
+#     define MAX_ROOT_SETS 1024
+#   else
+#     ifdef MSWIN32
+#	define MAX_ROOT_SETS 512
+	    /* Under NT, we add only written pages, which can result 	*/
+	    /* in many small root sets.					*/
+#     else
+#       define MAX_ROOT_SETS 64
+#     endif
+#   endif
+# endif
+
+# define MAX_EXCLUSIONS (MAX_ROOT_SETS/4)
+/* Maximum number of segments that can be excluded from root sets.	*/
+
+/*
+ * Data structure for excluded static roots.
+ */
+struct exclusion {
+    ptr_t e_start;
+    ptr_t e_end;
+};
+
+/* Data structure for list of root sets.				*/
+/* We keep a hash table, so that we can filter out duplicate additions.	*/
+/* Under Win32, we need to do a better job of filtering overlaps, so	*/
+/* we resort to sequential search, and pay the price.			*/
+struct roots {
+	ptr_t r_start;
+	ptr_t r_end;
+#	ifndef MSWIN32
+	  struct roots * r_next;
+#	endif
+	GC_bool r_tmp;
+	  	/* Delete before registering new dynamic libraries */
+};
+
+#ifndef MSWIN32
+    /* Size of hash table index to roots.	*/
+#   define LOG_RT_SIZE 6
+#   define RT_SIZE (1 << LOG_RT_SIZE) /* Power of 2, may be != MAX_ROOT_SETS */
+#endif
+
+/* Lists of all heap blocks and free lists	*/
+/* as well as other random data structures	*/
+/* that should not be scanned by the		*/
+/* collector.					*/
+/* These are grouped together in a struct	*/
+/* so that they can be easily skipped by the	*/
+/* GC_mark routine.				*/
+/* The ordering is weird to make GC_malloc	*/
+/* faster by keeping the important fields	*/
+/* sufficiently close together that a		*/
+/* single load of a base register will do.	*/
+/* Scalars that could easily appear to		*/
+/* be pointers are also put here.		*/
+/* The main fields should precede any 		*/
+/* conditionally included fields, so that	*/
+/* gc_inl.h will work even if a different set	*/
+/* of macros is defined when the client is	*/
+/* compiled.					*/
+
+struct _GC_arrays {
+  word _heapsize;
+  word _max_heapsize;
+  word _requested_heapsize;	/* Heap size due to explicit expansion */
+  ptr_t _last_heap_addr;
+  ptr_t _prev_heap_addr;
+  word _large_free_bytes;
+	/* Total bytes contained in blocks on large object free */
+	/* list.						*/
+  word _words_allocd_before_gc;
+		/* Number of words allocated before this	*/
+		/* collection cycle.				*/
+  word _words_allocd;
+  	/* Number of words allocated during this collection cycle */
+  word _words_wasted;
+  	/* Number of words wasted due to internal fragmentation	*/
+  	/* in large objects, or due to dropping blacklisted     */
+	/* blocks, since last gc.  Approximate.                 */
+  word _words_finalized;
+  	/* Approximate number of words in objects (and headers)	*/
+  	/* That became ready for finalization in the last 	*/
+  	/* collection.						*/
+  word _non_gc_bytes_at_gc;
+  	/* Number of explicitly managed bytes of storage 	*/
+  	/* at last collection.					*/
+  word _mem_freed;
+  	/* Number of explicitly deallocated words of memory	*/
+  	/* since last collection.				*/
+  ptr_t _scratch_end_ptr;
+  ptr_t _scratch_last_end_ptr;
+	/* Used by headers.c, and can easily appear to point to	*/
+	/* heap.						*/
+  mark_proc _mark_procs[MAX_MARK_PROCS];
+  	/* Table of user-defined mark procedures.  There is	*/
+	/* a small number of these, which can be referenced	*/
+	/* by DS_PROC mark descriptors.  See gc_mark.h.		*/
+  ptr_t _objfreelist[MAXOBJSZ+1];
+			  /* free list for objects */
+  ptr_t _aobjfreelist[MAXOBJSZ+1];
+			  /* free list for atomic objs 	*/
+
+  ptr_t _uobjfreelist[MAXOBJSZ+1];
+			  /* uncollectable but traced objs 	*/
+			  /* objects on this and auobjfreelist  */
+			  /* are always marked, except during   */
+			  /* garbage collections.		*/
+# ifdef ATOMIC_UNCOLLECTABLE
+    ptr_t _auobjfreelist[MAXOBJSZ+1];
+# endif
+			  /* uncollectable but traced objs 	*/
+
+# ifdef GATHERSTATS
+    word _composite_in_use;
+   		/* Number of words in accessible composite	*/
+		/* objects.					*/
+    word _atomic_in_use;
+   		/* Number of words in accessible atomic		*/
+		/* objects.					*/
+# endif
+# ifdef USE_MUNMAP
+    word _unmapped_bytes;
+# endif
+# ifdef MERGE_SIZES
+    unsigned _size_map[WORDS_TO_BYTES(MAXOBJSZ+1)];
+    	/* Number of words to allocate for a given allocation request in */
+    	/* bytes.							 */
+# endif 
+
+# ifdef STUBBORN_ALLOC
+    ptr_t _sobjfreelist[MAXOBJSZ+1];
+# endif
+  			  /* free list for immutable objects	*/
+  ptr_t _obj_map[MAXOBJSZ+1];
+                       /* If not NIL, then a pointer to a map of valid  */
+    		       /* object addresses. _obj_map[sz][i] is j if the	*/
+    		       /* address block_start+i is a valid pointer      */
+    		       /* to an object at				*/
+    		       /* block_start+i&~3 - WORDS_TO_BYTES(j).		*/
+    		       /* (If ALL_INTERIOR_POINTERS is defined, then	*/
+    		       /* instead ((short *)(hb_map[sz])[i] is j if	*/
+    		       /* block_start+WORDS_TO_BYTES(i) is in the	*/
+    		       /* interior of an object starting at		*/
+    		       /* block_start+WORDS_TO_BYTES(i-j)).		*/
+    		       /* It is OBJ_INVALID if				*/
+    		       /* block_start+WORDS_TO_BYTES(i) is not		*/
+    		       /* valid as a pointer to an object.              */
+    		       /* We assume all values of j <= OBJ_INVALID.	*/
+    		       /* The zeroth entry corresponds to large objects.*/
+#   ifdef ALL_INTERIOR_POINTERS
+#	define map_entry_type short
+#       define OBJ_INVALID 0x7fff
+#	define MAP_ENTRY(map, bytes) \
+		(((map_entry_type *)(map))[BYTES_TO_WORDS(bytes)])
+#	define MAP_ENTRIES BYTES_TO_WORDS(HBLKSIZE)
+#	define MAP_SIZE (MAP_ENTRIES * sizeof(map_entry_type))
+#	define OFFSET_VALID(displ) TRUE
+#	define CPP_MAX_OFFSET (HBLKSIZE - HDR_BYTES - 1)
+#	define MAX_OFFSET ((word)CPP_MAX_OFFSET)
+#   else
+#	define map_entry_type char
+#       define OBJ_INVALID 0x7f
+#	define MAP_ENTRY(map, bytes) \
+		(map)[bytes]
+#	define MAP_ENTRIES HBLKSIZE
+#	define MAP_SIZE MAP_ENTRIES
+#	define CPP_MAX_OFFSET (WORDS_TO_BYTES(OBJ_INVALID) - 1)	
+#	define MAX_OFFSET ((word)CPP_MAX_OFFSET)
+# 	define VALID_OFFSET_SZ \
+	  (CPP_MAX_OFFSET > WORDS_TO_BYTES(CPP_MAXOBJSZ)? \
+	   CPP_MAX_OFFSET+1 \
+	   : WORDS_TO_BYTES(CPP_MAXOBJSZ)+1)
+  	char _valid_offsets[VALID_OFFSET_SZ];
+				/* GC_valid_offsets[i] == TRUE ==> i 	*/
+				/* is registered as a displacement.	*/
+#	define OFFSET_VALID(displ) GC_valid_offsets[displ]
+  	char _modws_valid_offsets[sizeof(word)];
+				/* GC_valid_offsets[i] ==>		  */
+				/* GC_modws_valid_offsets[i%sizeof(word)] */
+#   endif
+# ifdef STUBBORN_ALLOC
+    page_hash_table _changed_pages;
+        /* Stubborn object pages that were changes since last call to	*/
+	/* GC_read_changed.						*/
+    page_hash_table _prev_changed_pages;
+        /* Stubborn object pages that were changes before last call to	*/
+	/* GC_read_changed.						*/
+# endif
+# if defined(PROC_VDB) || defined(MPROTECT_VDB)
+    page_hash_table _grungy_pages; /* Pages that were dirty at last 	   */
+				     /* GC_read_dirty.			   */
+# endif
+# ifdef MPROTECT_VDB
+    VOLATILE page_hash_table _dirty_pages;	
+			/* Pages dirtied since last GC_read_dirty. */
+# endif
+# ifdef PROC_VDB
+    page_hash_table _written_pages;	/* Pages ever dirtied	*/
+# endif
+# ifdef LARGE_CONFIG
+#   if CPP_WORDSZ > 32
+#     define MAX_HEAP_SECTS 4096 	/* overflows at roughly 64 GB	   */
+#   else
+#     define MAX_HEAP_SECTS 768		/* Separately added heap sections. */
+#   endif
+# else
+#   define MAX_HEAP_SECTS 256
+# endif
+  struct HeapSect {
+      ptr_t hs_start; word hs_bytes;
+  } _heap_sects[MAX_HEAP_SECTS];
+# ifdef MSWIN32
+    ptr_t _heap_bases[MAX_HEAP_SECTS];
+    		/* Start address of memory regions obtained from kernel. */
+# endif
+  struct roots _static_roots[MAX_ROOT_SETS];
+# ifndef MSWIN32
+    struct roots * _root_index[RT_SIZE];
+# endif
+  struct exclusion _excl_table[MAX_EXCLUSIONS];
+  /* Block header index; see gc_headers.h */
+  bottom_index * _all_nils;
+  bottom_index * _top_index [TOP_SZ];
+#ifdef SAVE_CALL_CHAIN
+  struct callinfo _last_stack[NFRAMES];	/* Stack at last garbage collection.*/
+  					/* Useful for debugging	mysterious  */
+  					/* object disappearances.	    */
+  					/* In the multithreaded case, we    */
+  					/* currently only save the calling  */
+  					/* stack.			    */
+#endif
+};
+
+GC_API GC_FAR struct _GC_arrays GC_arrays; 
+
+# define GC_objfreelist GC_arrays._objfreelist
+# define GC_aobjfreelist GC_arrays._aobjfreelist
+# define GC_uobjfreelist GC_arrays._uobjfreelist
+# ifdef ATOMIC_UNCOLLECTABLE
+#   define GC_auobjfreelist GC_arrays._auobjfreelist
+# endif
+# define GC_sobjfreelist GC_arrays._sobjfreelist
+# define GC_valid_offsets GC_arrays._valid_offsets
+# define GC_modws_valid_offsets GC_arrays._modws_valid_offsets
+# ifdef STUBBORN_ALLOC
+#    define GC_changed_pages GC_arrays._changed_pages
+#    define GC_prev_changed_pages GC_arrays._prev_changed_pages
+# endif
+# define GC_obj_map GC_arrays._obj_map
+# define GC_last_heap_addr GC_arrays._last_heap_addr
+# define GC_prev_heap_addr GC_arrays._prev_heap_addr
+# define GC_words_allocd GC_arrays._words_allocd
+# define GC_words_wasted GC_arrays._words_wasted
+# define GC_large_free_bytes GC_arrays._large_free_bytes
+# define GC_words_finalized GC_arrays._words_finalized
+# define GC_non_gc_bytes_at_gc GC_arrays._non_gc_bytes_at_gc
+# define GC_mem_freed GC_arrays._mem_freed
+# define GC_scratch_end_ptr GC_arrays._scratch_end_ptr
+# define GC_scratch_last_end_ptr GC_arrays._scratch_last_end_ptr
+# define GC_mark_procs GC_arrays._mark_procs
+# define GC_heapsize GC_arrays._heapsize
+# define GC_max_heapsize GC_arrays._max_heapsize
+# define GC_requested_heapsize GC_arrays._requested_heapsize
+# define GC_words_allocd_before_gc GC_arrays._words_allocd_before_gc
+# define GC_heap_sects GC_arrays._heap_sects
+# define GC_last_stack GC_arrays._last_stack
+# ifdef USE_MUNMAP
+#   define GC_unmapped_bytes GC_arrays._unmapped_bytes
+# endif
+# ifdef MSWIN32
+#   define GC_heap_bases GC_arrays._heap_bases
+# endif
+# define GC_static_roots GC_arrays._static_roots
+# define GC_root_index GC_arrays._root_index
+# define GC_excl_table GC_arrays._excl_table
+# define GC_all_nils GC_arrays._all_nils
+# define GC_top_index GC_arrays._top_index
+# if defined(PROC_VDB) || defined(MPROTECT_VDB)
+#   define GC_grungy_pages GC_arrays._grungy_pages
+# endif
+# ifdef MPROTECT_VDB
+#   define GC_dirty_pages GC_arrays._dirty_pages
+# endif
+# ifdef PROC_VDB
+#   define GC_written_pages GC_arrays._written_pages
+# endif
+# ifdef GATHERSTATS
+#   define GC_composite_in_use GC_arrays._composite_in_use
+#   define GC_atomic_in_use GC_arrays._atomic_in_use
+# endif
+# ifdef MERGE_SIZES
+#   define GC_size_map GC_arrays._size_map
+# endif
+
+# define beginGC_arrays ((ptr_t)(&GC_arrays))
+# define endGC_arrays (((ptr_t)(&GC_arrays)) + (sizeof GC_arrays))
+
+#define USED_HEAP_SIZE (GC_heapsize - GC_large_free_bytes)
+
+/* Object kinds: */
+# define MAXOBJKINDS 16
+
+extern struct obj_kind {
+   ptr_t *ok_freelist;	/* Array of free listheaders for this kind of object */
+   			/* Point either to GC_arrays or to storage allocated */
+   			/* with GC_scratch_alloc.			     */
+   struct hblk **ok_reclaim_list;
+   			/* List headers for lists of blocks waiting to be */
+   			/* swept.					  */
+   word ok_descriptor;  /* Descriptor template for objects in this	*/
+   			/* block.					*/
+   GC_bool ok_relocate_descr;
+   			/* Add object size in bytes to descriptor 	*/
+   			/* template to obtain descriptor.  Otherwise	*/
+   			/* template is used as is.			*/
+   GC_bool ok_init;   /* Clear objects before putting them on the free list. */
+} GC_obj_kinds[MAXOBJKINDS];
+
+# define endGC_obj_kinds (((ptr_t)(&GC_obj_kinds)) + (sizeof GC_obj_kinds))
+
+# define end_gc_area ((ptr_t)endGC_arrays == (ptr_t)(&GC_obj_kinds) ? \
+			endGC_obj_kinds : endGC_arrays)
+
+/* Predefined kinds: */
+# define PTRFREE 0
+# define NORMAL  1
+# define UNCOLLECTABLE 2
+# ifdef ATOMIC_UNCOLLECTABLE
+#   define AUNCOLLECTABLE 3
+#   define STUBBORN 4
+#   define IS_UNCOLLECTABLE(k) (((k) & ~1) == UNCOLLECTABLE)
+# else
+#   define STUBBORN 3
+#   define IS_UNCOLLECTABLE(k) ((k) == UNCOLLECTABLE)
+# endif
+
+extern int GC_n_kinds;
+
+GC_API word GC_fo_entries;
+
+extern word GC_n_heap_sects;	/* Number of separately added heap	*/
+				/* sections.				*/
+
+extern word GC_page_size;
+
+# ifdef MSWIN32
+extern word GC_n_heap_bases;	/* See GC_heap_bases.	*/
+# endif
+
+extern word GC_total_stack_black_listed;
+			/* Number of bytes on stack blacklist. 	*/
+
+extern word GC_black_list_spacing;
+			/* Average number of bytes between blacklisted	*/
+			/* blocks. Approximate.				*/
+			/* Counts only blocks that are 			*/
+			/* "stack-blacklisted", i.e. that are 		*/
+			/* problematic in the interior of an object.	*/
+
+extern char * GC_invalid_map;
+			/* Pointer to the nowhere valid hblk map */
+			/* Blocks pointing to this map are free. */
+
+extern struct hblk * GC_hblkfreelist[];
+				/* List of completely empty heap blocks	*/
+				/* Linked through hb_next field of 	*/
+				/* header structure associated with	*/
+				/* block.				*/
+
+extern GC_bool GC_is_initialized;	/* GC_init() has been run.	*/
+
+extern GC_bool GC_objects_are_marked;	/* There are marked objects in  */
+					/* the heap.			*/
+
+#ifndef SMALL_CONFIG
+  extern GC_bool GC_incremental;
+			/* Using incremental/generational collection. */
+#else
+# define GC_incremental FALSE
+			/* Hopefully allow optimizer to remove some code. */
+#endif
+
+extern GC_bool GC_dirty_maintained;
+				/* Dirty bits are being maintained, 	*/
+				/* either for incremental collection,	*/
+				/* or to limit the root set.		*/
+
+extern word GC_root_size;	/* Total size of registered root sections */
+
+extern GC_bool GC_debugging_started;	/* GC_debug_malloc has been called. */ 
+
+extern ptr_t GC_least_plausible_heap_addr;
+extern ptr_t GC_greatest_plausible_heap_addr;
+			/* Bounds on the heap.  Guaranteed valid	*/
+			/* Likely to include future heap expansion.	*/
+			
+/* Operations */
+# ifndef abs
+#   define abs(x)  ((x) < 0? (-(x)) : (x))
+# endif
+
+
+/*  Marks are in a reserved area in                          */
+/*  each heap block.  Each word has one mark bit associated  */
+/*  with it. Only those corresponding to the beginning of an */
+/*  object are used.                                         */
+
+
+/* Mark bit operations */
+
+/*
+ * Retrieve, set, clear the mark bit corresponding
+ * to the nth word in a given heap block.
+ *
+ * (Recall that bit n corresponds to object beginning at word n
+ * relative to the beginning of the block, including unused words)
+ */
+
+# define mark_bit_from_hdr(hhdr,n) (((hhdr)->hb_marks[divWORDSZ(n)] \
+			    >> (modWORDSZ(n))) & (word)1)
+# define set_mark_bit_from_hdr(hhdr,n) (hhdr)->hb_marks[divWORDSZ(n)] \
+				|= (word)1 << modWORDSZ(n)
+
+# define clear_mark_bit_from_hdr(hhdr,n) (hhdr)->hb_marks[divWORDSZ(n)] \
+				&= ~((word)1 << modWORDSZ(n))
+
+/* Important internal collector routines */
+
+ptr_t GC_approx_sp();
+
+GC_bool GC_should_collect();
+
+void GC_apply_to_all_blocks(/*fn, client_data*/);
+			/* Invoke fn(hbp, client_data) for each 	*/
+			/* allocated heap block.			*/
+struct hblk * GC_next_used_block(/* struct hblk * h */);
+			/* Return first in-use block >= h	*/
+struct hblk * GC_prev_block(/* struct hblk * h */);
+			/* Return last block <= h.  Returned block	*/
+			/* is managed by GC, but may or may not be in	*/
+			/* use.						*/
+void GC_mark_init();
+void GC_clear_marks();	/* Clear mark bits for all heap objects. */
+void GC_invalidate_mark_state();	/* Tell the marker that	marked 	   */
+					/* objects may point to	unmarked   */
+					/* ones, and roots may point to	   */
+					/* unmarked objects.		   */
+					/* Reset mark stack.		   */
+void GC_mark_from_mark_stack(); /* Mark from everything on the mark stack. */
+				/* Return after about one pages worth of   */
+				/* work.				   */
+GC_bool GC_mark_stack_empty();
+GC_bool GC_mark_some(/* cold_gc_frame */);
+			/* Perform about one pages worth of marking	*/
+			/* work of whatever kind is needed.  Returns	*/
+			/* quickly if no collection is in progress.	*/
+			/* Return TRUE if mark phase finished.		*/
+void GC_initiate_gc();		/* initiate collection.			*/
+				/* If the mark state is invalid, this	*/
+				/* becomes full colleection.  Otherwise */
+				/* it's partial.			*/
+void GC_push_all(/*b,t*/);	/* Push everything in a range 		*/
+				/* onto mark stack.			*/
+void GC_push_dirty(/*b,t*/);      /* Push all possibly changed	 	*/
+				  /* subintervals of [b,t) onto		*/
+				  /* mark stack.			*/
+#ifndef SMALL_CONFIG
+  void GC_push_conditional(/* ptr_t b, ptr_t t, GC_bool all*/);
+#else
+# define GC_push_conditional(b, t, all) GC_push_all(b, t)
+#endif
+                                /* Do either of the above, depending	*/
+				/* on the third arg.			*/
+void GC_push_all_stack(/*b,t*/);    /* As above, but consider		*/
+				    /*  interior pointers as valid  	*/
+void GC_push_all_eager(/*b,t*/);    /* Same as GC_push_all_stack, but   */
+				    /* ensures that stack is scanned	*/
+				    /* immediately, not just scheduled  */
+				    /* for scanning.			*/
+#ifndef THREADS
+  void GC_push_all_stack_partially_eager(/* bottom, top, cold_gc_frame */);
+			/* Similar to GC_push_all_eager, but only the	*/
+			/* part hotter than cold_gc_frame is scanned	*/
+			/* immediately.  Needed to endure that callee-	*/
+			/* save registers are not missed.		*/
+#else
+  /* In the threads case, we push part of the current thread stack	*/
+  /* with GC_push_all_eager when we push the registers.  This gets the  */
+  /* callee-save registers that may disappear.  The remainder of the	*/
+  /* stacks are scheduled for scanning in *GC_push_other_roots, which	*/
+  /* is thread-package-specific.					*/
+#endif
+void GC_push_current_stack(/* ptr_t cold_gc_frame */);
+			/* Push enough of the current stack eagerly to	*/
+			/* ensure that callee-save registers saved in	*/
+			/* GC frames are scanned.			*/
+			/* In the non-threads case, schedule entire	*/
+			/* stack for scanning.				*/
+void GC_push_roots(/* GC_bool all, ptr_t cold_gc_frame */);
+			/* Push all or dirty roots.	*/
+extern void (*GC_push_other_roots)();
+			/* Push system or application specific roots	*/
+			/* onto the mark stack.  In some environments	*/
+			/* (e.g. threads environments) this is		*/
+			/* predfined to be non-zero.  A client supplied */
+			/* replacement should also call the original	*/
+			/* function.					*/
+extern void (*GC_start_call_back)(/* void */);
+			/* Called at start of full collections.		*/
+			/* Not called if 0.  Called with allocation 	*/
+			/* lock held.					*/
+			/* 0 by default.				*/
+void GC_push_regs();	/* Push register contents onto mark stack.	*/
+			/* If NURSERY is defined, the default push	*/
+			/* action can be overridden with GC_push_proc	*/
+void GC_remark();	/* Mark from all marked objects.  Used	*/
+		 	/* only if we had to drop something.	*/
+
+# ifdef NURSERY
+    extern void (*GC_push_proc)(ptr_t);
+# endif
+# if defined(MSWIN32)
+  void __cdecl GC_push_one();
+# else
+  void GC_push_one(/*p*/);    /* If p points to an object, mark it    */
+                              /* and push contents on the mark stack  */
+# endif
+void GC_push_one_checked(/*p*/); /* Ditto, omits plausibility test	*/
+void GC_push_marked(/* struct hblk h, hdr * hhdr */);
+		/* Push contents of all marked objects in h onto	*/
+		/* mark stack.						*/
+#ifdef SMALL_CONFIG
+# define GC_push_next_marked_dirty(h) GC_push_next_marked(h)
+#else
+  struct hblk * GC_push_next_marked_dirty(/* h */);
+		/* Invoke GC_push_marked on next dirty block above h.	*/
+		/* Return a pointer just past the end of this block.	*/
+#endif /* !SMALL_CONFIG */
+struct hblk * GC_push_next_marked(/* h */);
+		/* Ditto, but also mark from clean pages.	*/
+struct hblk * GC_push_next_marked_uncollectable(/* h */);
+		/* Ditto, but mark only from uncollectable pages.	*/
+GC_bool GC_stopped_mark(); /* Stop world and mark from all roots	*/
+			/* and rescuers.			*/
+void GC_clear_hdr_marks(/* hhdr */);  /* Clear the mark bits in a header */
+void GC_set_hdr_marks(/* hhdr */);  /* Set the mark bits in a header */
+void GC_add_roots_inner();
+GC_bool GC_is_static_root(/* ptr_t p */);
+		/* Is the address p in one of the registered static	*/
+		/* root sections?					*/
+void GC_register_dynamic_libraries();
+		/* Add dynamic library data sections to the root set. */
+
+/* Machine dependent startup routines */
+ptr_t GC_get_stack_base();
+void GC_register_data_segments();
+
+/* Black listing: */
+void GC_bl_init(); 	
+# ifndef ALL_INTERIOR_POINTERS
+    void GC_add_to_black_list_normal(/* bits, maybe source */);
+			/* Register bits as a possible future false	*/
+			/* reference from the heap or static data	*/
+#   ifdef PRINT_BLACK_LIST
+#     define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \
+			GC_add_to_black_list_normal(bits, source)
+#   else
+#     define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \
+			GC_add_to_black_list_normal(bits)
+#   endif
+# else
+#   ifdef PRINT_BLACK_LIST
+#     define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \
+			GC_add_to_black_list_stack(bits, source)
+#   else
+#     define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \
+			GC_add_to_black_list_stack(bits)
+#   endif