changeset 473:373489eeaf90

Applied downs' lphobos update
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Mon, 04 Aug 2008 19:28:49 +0200
parents 15c804b6ce77
children 074e74c1a72b
files lphobos/build.sh lphobos/etc/c/zlib.d lphobos/gc/gc.d lphobos/gc/gc_guess_stack.d lphobos/gc/gcbits.d lphobos/gc/gcx.d lphobos/gc/win32.d lphobos/hello.d lphobos/internal/aaA.d lphobos/internal/adi.d lphobos/internal/contract.d lphobos/internal/critical.d lphobos/internal/dmain2.d lphobos/internal/eh.d lphobos/internal/objectimpl.d lphobos/internal/qsort2.d lphobos/internal/switch.d lphobos/llvm/intrinsic.d lphobos/object.d lphobos/phobos.d lphobos/std/bitarray.d lphobos/std/c/stdarg.d lphobos/std/c/stdlib.d lphobos/std/c/windows/com.d lphobos/std/c/windows/stat.d lphobos/std/c/windows/windows.d lphobos/std/c/windows/winsock.d lphobos/std/cstream.d lphobos/std/date.d lphobos/std/date.d~ lphobos/std/dateparse.d lphobos/std/file.d lphobos/std/intrinsic.d lphobos/std/math.d lphobos/std/md5.d lphobos/std/mmfile.d lphobos/std/moduleinit.d lphobos/std/outbuffer.d lphobos/std/path.d lphobos/std/process.d lphobos/std/random.d lphobos/std/regexp.d lphobos/std/socket.d lphobos/std/stream.d lphobos/std/string.d lphobos/std/system.d lphobos/std/thread.d lphobos/std/traits.d lphobos/std/zip.d lphobos/std/zlib.d lphobos/typeinfo1/ti_float.d
diffstat 51 files changed, 27320 insertions(+), 459 deletions(-) [+]
line wrap: on
line diff
--- a/lphobos/build.sh	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/build.sh	Mon Aug 04 19:28:49 2008 +0200
@@ -5,69 +5,96 @@
 rm -f obj/*.bc
 rm -f ../lib/*.bc
 
-LLVMDCFLAGS="-c -odobj -g"
-REBUILDFLAGS="-dc=llvmdc-posix-internal -c -oqobj -g"
+LLVMDCFLAGS="-c -odobj -oq -gc -noasm"
+LLVMDCFLAGS_ASM="-c -odobj -oq -gc"
 
 echo "compiling contract runtime"
-llvmdc internal/contract.d -c -of../lib/llvmdcore.bc -noruntime || exit 1
+llvmdc internal/contract.d -c -of../lib/llvmdcore.bc || exit 1 #-noruntime || exit 1
 
 echo "compiling common runtime"
-rebuild internal/arrays.d \
+llvmdc-build internal/arrays.d \
         internal/mem.d \
-        $REBUILDFLAGS || exit 1
+        internal/critical.d \
+        internal/dmain2.d \
+        $LLVMDCFLAGS_ASM || exit 1
+mv *.bc obj
 
 echo "compiling module init backend"
 llvm-as -f -o=obj/moduleinit_backend.bc internal/moduleinit_backend.ll || exit 1
 llvm-link -f -o=../lib/llvmdcore.bc `ls obj/internal.*.bc` ../lib/llvmdcore.bc obj/moduleinit_backend.bc || exit 1
 
 echo "compiling typeinfo 1"
-rebuild typeinfos1.d $REBUILDFLAGS || exit 1
+llvmdc-build typeinfos1.d $LLVMDCFLAGS || exit 1
+mv *.bc obj
 llvm-link -f -o=../lib/llvmdcore.bc `ls obj/typeinfo1.*.bc` ../lib/llvmdcore.bc || exit 1
 
 echo "compiling typeinfo 2"
-rebuild typeinfos2.d $REBUILDFLAGS || exit 1
+llvmdc-build typeinfos2.d $LLVMDCFLAGS || exit 1
+mv *.bc obj
 llvm-link -f -o=../lib/llvmdcore.bc `ls obj/typeinfo2.*.bc` ../lib/llvmdcore.bc || exit 1
 
+echo "compiling exceptions"
+llvmdc-build internal/eh.d $LLVMDCFLAGS -debug || exit 1
+mv *.bc obj
+llvm-link -f -o=../lib/llvmdcore.bc obj/*eh.bc ../lib/llvmdcore.bc || exit 1
+
 echo "compiling object/interface casting runtime support"
 llvmdc internal/cast.d $LLVMDCFLAGS || exit 1
+mv *.bc obj
 llvm-link -f -o=../lib/llvmdcore.bc obj/cast.bc ../lib/llvmdcore.bc || exit 1
 
 echo "compiling string foreach/switch runtime support"
 llvmdc internal/aApply.d $LLVMDCFLAGS || exit 1
 llvmdc internal/aApplyR.d $LLVMDCFLAGS || exit 1
 llvmdc internal/switch.d $LLVMDCFLAGS || exit 1
+mv *.bc obj
 llvm-link -f -o=../lib/llvmdcore.bc obj/aApply.bc obj/aApplyR.bc obj/switch.bc ../lib/llvmdcore.bc || exit 1
 
 echo "compiling array runtime support"
 llvmdc internal/qsort2.d $LLVMDCFLAGS || exit 1
+mv *.bc obj
 llvm-link -f -o=../lib/llvmdcore.bc obj/qsort2.bc ../lib/llvmdcore.bc || exit 1
 llvmdc internal/adi.d $LLVMDCFLAGS || exit 1
+mv *.bc obj
 llvm-link -f -o=../lib/llvmdcore.bc obj/adi.bc ../lib/llvmdcore.bc || exit 1
 llvmdc internal/aaA.d $LLVMDCFLAGS || exit 1
+mv *.bc obj
 llvm-link -f -o=../lib/llvmdcore.bc obj/aaA.bc ../lib/llvmdcore.bc || exit 1
 
 echo "compiling object implementation"
-llvmdc internal/objectimpl.d $LLVMDCFLAGS || exit 1
+llvmdc internal/objectimpl.d -c -odobj -g || exit 1
 llvm-link -f -o=../lib/llvmdcore.bc obj/objectimpl.bc ../lib/llvmdcore.bc || exit 1
 
 echo "compiling llvm runtime support"
-rebuild llvmsupport.d $REBUILDFLAGS || exit 1
+llvmdc-build llvmsupport.d $LLVMDCFLAGS || exit 1
+mv *.bc obj
 llvm-link -f -o=../lib/llvmdcore.bc `ls obj/llvm.*.bc` ../lib/llvmdcore.bc || exit 1
 
 echo "compiling garbage collector"
-llvmdc gc/gclinux.d $LLVMDCFLAGS || exit 1
-llvmdc gc/gcx.d $LLVMDCFLAGS -Igc || exit 1
-llvmdc gc/gcbits.d $LLVMDCFLAGS -Igc || exit 1
-llvmdc gc/gc.d $LLVMDCFLAGS -Igc || exit 1
+cd gc
+llvmdc $(ls *.d |grep -v win32) $LLVMDCFLAGS_ASM -I.. ||exit 1
+# llvmdc gclinux.d $LLVMDCFLAGS -I.. || exit 1
+# llvmdc gcx.d $LLVMDCFLAGS -I.. || exit 1
+# llvmdc gcbits.d $LLVMDCFLAGS -I.. || exit 1
+# llvmdc gc.d $LLVMDCFLAGS -I.. || exit 1
+mv std.gc.bc gc.bc
+mv *.bc ../obj
+cd ..
 llvm-link -f -o=../lib/llvmdcore.bc obj/gclinux.bc obj/gcx.bc obj/gcbits.bc obj/gc.bc ../lib/llvmdcore.bc || exit 1
 
 echo "compiling phobos"
-rebuild phobos.d $REBUILDFLAGS || exit 1
+llvmdc-build phobos.d $LLVMDCFLAGS || exit 1
+mv *.bc obj
 echo "linking phobos"
 llvm-link -f -o=../lib/llvmdcore.bc `ls obj/std.*.bc` ../lib/llvmdcore.bc || exit 1
 
+echo "Compiling auxiliary"
+llvmdc-build etc/c/zlib.d $LLVMDCFLAGS || exit 1
+mv *.bc obj
+llvm-link -f -o=../lib/llvmdcore.bc `ls obj/etc.*.bc` ../lib/llvmdcore.bc || exit 1
+
 echo "optimizing"
-opt -f -std-compile-opts -o=../lib/llvmdcore.bc ../lib/llvmdcore.bc || exit 1
+opt -stats -p -f -std-compile-opts -disable-inlining -o=../lib/llvmdcore.bc ../lib/llvmdcore.bc || exit 1
 
 
 echo "SUCCESS"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/etc/c/zlib.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,1215 @@
+/* zlib.d: modified from zlib.h by Walter Bright */
+/* NOTE: This file has been patched from the original DMD distribution to
+   work with the GDC compiler.
+
+   Modified by David Friedman, February 2007
+*/
+
+module etc.c.zlib;
+
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.2.1, November 17th, 2003
+
+  Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+private import std.stdint;
+
+extern (C):
+alias uint Culong_t;
+alias int Clong_t;
+
+char[] ZLIB_VERSION = "1.2.1";
+
+/*
+     The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed
+  data.  This version of the library supports only one compression method
+  (deflation) but other algorithms will be added later and will have the same
+  stream interface.
+
+     Compression can be done in a single step if the buffers are large
+  enough (for example if an input file is mmap'ed), or can be done by
+  repeated calls of the compression function.  In the latter case, the
+  application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+     The compressed data format used by the in-memory functions is the zlib
+  format, which is a zlib wrapper documented in RFC 1950, wrapped around a
+  deflate stream, which is itself documented in RFC 1951.
+
+     The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio using the functions that start
+  with "gz".  The gzip format is different from the zlib format.  gzip is a
+  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+     The zlib format was designed to be compact and fast for use in memory
+  and on communications channels.  The gzip format was designed for single-
+  file compression on file systems, has a larger header than zlib to maintain
+  directory information, and uses a different, slower check method than zlib.
+
+     This library does not provide any functions to write gzip files in memory.
+  However such functions could be easily written using zlib's deflate function,
+  the documentation in the gzip RFC, and the examples in gzio.c.
+
+     The library does not install any signal handler. The decoder checks
+  the consistency of the compressed data, so the library should never
+  crash even in case of corrupted input.
+*/
+
+alias void* (*alloc_func) (void* opaque, uint items, uint size);
+alias void   (*free_func)  (void* opaque, void* address);
+
+struct z_stream
+{
+    ubyte    *next_in;  /* next input byte */
+    uint     avail_in;  /* number of bytes available at next_in */
+    Culong_t total_in;  /* total nb of input bytes read so far */
+
+    ubyte    *next_out; /* next output byte should be put there */
+    uint     avail_out; /* remaining free space at next_out */
+    Culong_t total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    void*    state;     /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    void*      opaque;  /* private data object passed to zalloc and zfree */
+
+    int      data_type;  /* best guess about the data type: ascii or binary */
+    Culong_t adler;      /* adler32 value of the uncompressed data */
+    Culong_t reserved;   /* reserved for future use */
+}
+
+alias z_stream* z_streamp;
+
+/*
+   The application must update next_in and avail_in when avail_in has
+   dropped to zero. It must update next_out and avail_out when avail_out
+   has dropped to zero. The application must initialize zalloc, zfree and
+   opaque before calling the init function. All other fields are set by the
+   compression library and must not be updated by the application.
+
+   The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree. This can be useful for custom
+   memory management. The compression library attaches no meaning to the
+   opaque value.
+
+   zalloc must return Z_NULL if there is not enough memory for the object.
+   If zlib is used in a multi-threaded application, zalloc and zfree must be
+   thread safe.
+
+   On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this
+   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+   pointers returned by zalloc for objects of exactly 65536 bytes *must*
+   have their offset normalized to zero. The default allocation function
+   provided by this library ensures this (see zutil.c). To reduce memory
+   requirements and avoid any allocation of 64K objects, at the expense of
+   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+   The fields total_in and total_out can be used for statistics or
+   progress reports. After compression, total_in holds the total size of
+   the uncompressed data and may be saved for use in the decompressor
+   (particularly if the decompressor wants to decompress everything in
+   a single step).
+*/
+
+                        /* constants */
+
+enum
+{
+	Z_NO_FLUSH      = 0,
+	Z_PARTIAL_FLUSH = 1, /* will be removed, use Z_SYNC_FLUSH instead */
+	Z_SYNC_FLUSH    = 2,
+	Z_FULL_FLUSH    = 3,
+	Z_FINISH        = 4,
+	Z_BLOCK         = 5
+}
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+enum
+{
+	Z_OK            = 0,
+	Z_STREAM_END    = 1,
+	Z_NEED_DICT     = 2,
+	Z_ERRNO         = -1,
+	Z_STREAM_ERROR  = -2,
+	Z_DATA_ERROR    = -3,
+	Z_MEM_ERROR     = -4,
+	Z_BUF_ERROR     = -5,
+	Z_VERSION_ERROR = -6,
+}
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+enum
+{
+	Z_NO_COMPRESSION         = 0,
+	Z_BEST_SPEED             = 1,
+	Z_BEST_COMPRESSION       = 9,
+	Z_DEFAULT_COMPRESSION    = -1,
+}
+/* compression levels */
+
+enum
+{
+	Z_FILTERED            = 1,
+	Z_HUFFMAN_ONLY        = 2,
+	Z_RLE                 = 3,
+	Z_DEFAULT_STRATEGY    = 0,
+}
+/* compression strategy; see deflateInit2() below for details */
+
+enum
+{
+	Z_BINARY   = 0,
+	Z_ASCII    = 1,
+	Z_UNKNOWN  = 2,
+}
+/* Possible values of the data_type field (though see inflate()) */
+
+enum
+{
+	Z_DEFLATED   = 8,
+}
+/* The deflate compression method (the only one supported in this version) */
+
+const int Z_NULL = 0;  /* for initializing zalloc, zfree, opaque */
+
+                        /* basic functions */
+
+char* zlibVersion();
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is
+   not compatible with the zlib.h header file used by the application.
+   This check is automatically made by deflateInit and inflateInit.
+ */
+
+int deflateInit(z_streamp strm, int level)
+{
+    return deflateInit_(strm, level, ZLIB_VERSION.ptr, z_stream.sizeof);
+}
+/* 
+     Initializes the internal stream state for compression. The fields
+   zalloc, zfree and opaque must be initialized before by the caller.
+   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+   use default allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at
+   all (the input data is simply copied a block at a time).
+   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+   compression (currently equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).
+   msg is set to null if there is no error message.  deflateInit does not
+   perform any compression: this will be done by deflate().
+*/
+
+
+int deflate(z_streamp strm, int flush);
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce some
+  output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows. deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly. This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).
+    Some output may be provided even if flush is not set.
+
+  Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating avail_in or avail_out accordingly; avail_out
+  should never be zero before the call. The application can consume the
+  compressed output when it wants, for example when the output buffer is full
+  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+  and with zero avail_out, it must be called again after making room in the
+  output buffer because there might be more output pending.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+  flushed to the output buffer and the output is aligned on a byte boundary, so
+  that the decompressor can get all input data available so far. (In particular
+  avail_in is zero after the call if enough output space has been provided
+  before the call.)  Flushing may degrade compression for some compression
+  algorithms and so it should be used only when necessary.
+
+    If flush is set to Z_FULL_FLUSH, all output is flushed as with
+  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+  restart from this point if previous compressed data has been damaged or if
+  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+  the compression.
+
+    If deflate returns with avail_out == 0, this function must be called again
+  with the same value of the flush parameter and more output space (updated
+  avail_out), until the flush is complete (deflate returns with non-zero
+  avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+  avail_out is greater than six to avoid repeated flush markers due to
+  avail_out == 0 on return.
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there
+  was enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error. After
+  deflate has returned Z_STREAM_END, the only possible operations on the
+  stream are deflateReset or deflateEnd.
+
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step. In this case, avail_out must be at least
+  the value returned by deflateBound (see below). If deflate does not return
+  Z_STREAM_END, then it must be called again as described above.
+
+    deflate() sets strm->adler to the adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update data_type if it can make a good guess about
+  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+  binary. This field is only for information purposes and does not affect
+  the compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+  (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
+  fatal, and deflate() can be called again with more input and more output
+  space to continue compressing.
+*/
+
+
+int deflateEnd(z_streamp strm);
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded). In the error case,
+   msg may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+int inflateInit(z_streamp strm)
+{
+    return inflateInit_(strm, ZLIB_VERSION.ptr, z_stream.sizeof);
+}
+/* 
+     Initializes the internal stream state for decompression. The fields
+   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+   the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+   value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+   use default allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller.  msg is set to null if there is no error
+   message. inflateInit does not perform any decompression apart from reading
+   the zlib header if present: this will be done by inflate().  (So next_in and
+   avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+int inflate(z_streamp strm, int flush);
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+  The detailed semantics are as follows. inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing
+    will resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there
+    is no more input data or no more space in the output buffer (see below
+    about the flush parameter).
+
+  Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating the next_* and avail_* values accordingly.
+  The application can consume the uncompressed output when it wants, for
+  example when the output buffer is full (avail_out == 0), or after each
+  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+  must be called again after making room in the output buffer because there
+  might be more output pending.
+
+    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH,
+  Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much
+  output as possible to the output buffer. Z_BLOCK requests that inflate() stop
+  if and when it get to the next deflate block boundary. When decoding the zlib
+  or gzip format, this will cause inflate() to return immediately after the
+  header and before the first block. When doing a raw inflate, inflate() will
+  go ahead and process the first block, and will return when it gets to the end
+  of that block, or when it runs out of data.
+
+    The Z_BLOCK option assists in appending to or combining deflate streams.
+  Also to assist in this, on return inflate() will set strm->data_type to the
+  number of unused bits in the last byte taken from strm->next_in, plus 64
+  if inflate() is currently decoding the last block in the deflate stream,
+  plus 128 if inflate() returned immediately after decoding an end-of-block
+  code or decoding the complete header up to just before the first byte of the
+  deflate stream. The end-of-block will not be indicated until all of the
+  uncompressed data from that block has been written to strm->next_out.  The
+  number of unused bits may in general be greater than seven, except when
+  bit 7 of data_type is set, in which case the number of unused bits will be
+  less than eight.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error. However if all decompression is to be performed in a single step
+  (a single call of inflate), the parameter flush should be set to
+  Z_FINISH. In this case all pending input is processed and all pending
+  output is flushed; avail_out must be large enough to hold all the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster approach
+  may be used for the single inflate() call.
+
+     In this implementation, inflate() always flushes as much output as
+  possible to the output buffer, and always uses the faster approach on the
+  first call. So the only effect of the flush parameter in this implementation
+  is on the return value of inflate(), as noted below, or when it returns early
+  because Z_BLOCK is used.
+
+     If a preset dictionary is needed after this call (see inflateSetDictionary
+  below), inflate sets strm-adler to the adler32 checksum of the dictionary
+  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+  strm->adler to the adler32 checksum of all output produced so far (that is,
+  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+  below. At the end of the stream, inflate() checks that its computed adler32
+  checksum is equal to that saved by the compressor and returns Z_STREAM_END
+  only if the checksum is correct.
+
+    inflate() will decompress and check either zlib-wrapped or gzip-wrapped
+  deflate data.  The header type is detected automatically.  Any information
+  contained in the gzip header is not retained, so applications that need that
+  information should instead use raw inflate, see inflateInit2() below, or
+  inflateBack() and perform their own processing of the gzip header and
+  trailer.
+
+    inflate() returns Z_OK if some progress has been made (more input processed
+  or more output produced), Z_STREAM_END if the end of the compressed data has
+  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect check
+  value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+  if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+  Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+  output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+  inflate() can be called again with more input and more output space to
+  continue decompressing. If Z_DATA_ERROR is returned, the application may then
+  call inflateSync() to look for a good compression block if a partial recovery
+  of the data is desired.
+*/
+
+
+int inflateEnd(z_streamp strm);
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent. In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+int deflateInit2(z_streamp strm,
+                 int  level,
+                 int  method,
+                 int  windowBits,
+                 int  memLevel,
+                 int  strategy)
+{
+    return deflateInit2_(strm, level, method, windowBits, memLevel,
+                         strategy, ZLIB_VERSION.ptr, z_stream.sizeof);
+}
+/*
+     This is another version of deflateInit with more compression options. The
+   fields next_in, zalloc, zfree and opaque must be initialized before by
+   the caller.
+
+     The method parameter is the compression method. It must be Z_DEFLATED in
+   this version of the library.
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer). It should be in the range 8..15 for this
+   version of the library. Larger values of this parameter result in better
+   compression at the expense of memory usage. The default value is 15 if
+   deflateInit is used instead.
+
+     windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
+   determines the window size. deflate() will then generate raw deflate data
+   with no zlib header or trailer, and will not compute an adler32 check value.
+
+     windowBits can also be greater than 15 for optional gzip encoding. Add
+   16 to windowBits to write a simple gzip header and trailer around the
+   compressed data instead of a zlib wrapper. The gzip header will have no
+   file name, no extra data, no comment, no modification time (set to zero),
+   no header crc, and the operating system will be set to 255 (unknown).
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state. memLevel=1 uses minimum memory but
+   is slow and reduces compression ratio; memLevel=9 uses maximum memory
+   for optimal speed. The default value is 8. See zconf.h for total memory
+   usage as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm. Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match), or Z_RLE to limit match distances to one (run-length
+   encoding). Filtered data consists mostly of small values with a somewhat
+   random distribution. In this case, the compression algorithm is tuned to
+   compress them better. The effect of Z_FILTERED is to force more Huffman
+   coding and less string matching; it is somewhat intermediate between
+   Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as
+   Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy
+   parameter only affects the compression ratio but not the correctness of the
+   compressed output even if it is not set appropriately.
+
+      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+   method). msg is set to null if there is no error message.  deflateInit2 does
+   not perform any compression: this will be done by deflate().
+*/
+                            
+int deflateSetDictionary(z_streamp strm, ubyte* dictionary, uint  dictLength);
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output. This function must be called
+   immediately after deflateInit, deflateInit2 or deflateReset, before any
+   call of deflate. The compressor and decompressor must use exactly the same
+   dictionary (see inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary. Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size in
+   deflate or deflate2. Thus the strings most likely to be useful should be
+   put at the end of the dictionary, not at the front.
+
+     Upon return of this function, strm->adler is set to the adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor. (The adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.) If a raw deflate was requested, then the
+   adler32 value is not computed and strm->adler is not set.
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if the compression method is bsort). deflateSetDictionary does not
+   perform any compression: this will be done by deflate().
+*/
+
+int deflateCopy(z_streamp dest, z_streamp source);
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter. The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and
+   can consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+int deflateReset(z_streamp strm);
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.
+   The stream will keep the same compression level and any other attributes
+   that may have been set by deflateInit2.
+
+      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+int deflateParams(z_streamp strm, int level, int strategy);
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different
+   strategy. If the compression level is changed, the input available so far
+   is compressed with the old level (and may be flushed); the new level will
+   take effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to
+   be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+   if strm->avail_out was zero.
+*/
+
+uint deflateBound(z_streamp strm, uint Culong_t);
+/*
+     deflateBound() returns an upper bound on the compressed size after
+   deflation of sourceLen bytes.  It must be called after deflateInit()
+   or deflateInit2().  This would be used to allocate an output buffer
+   for deflation in a single pass, and so would be called before deflate().
+*/
+
+int deflatePrime(z_streamp strm, int bits, int value);
+/*
+     deflatePrime() inserts bits in the deflate output stream.  The intent
+  is that this function is used to start off the deflate output with the
+  bits leftover from a previous deflate stream when appending to it.  As such,
+  this function can only be used for raw deflate, and must be used before the
+  first deflate() call after a deflateInit2() or deflateReset().  bits must be
+  less than or equal to 16, and that many of the least significant bits of
+  value will be inserted in the output.
+
+      deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+int inflateInit2(z_streamp strm, int windowBits)
+{
+    return inflateInit2_(strm, windowBits, ZLIB_VERSION.ptr, z_stream.sizeof);
+}
+/*   
+     This is another version of inflateInit with an extra parameter. The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library. The default value is 15 if inflateInit is used
+   instead. windowBits must be greater than or equal to the windowBits value
+   provided to deflateInit2() while compressing, or it must be equal to 15 if
+   deflateInit2() was not used. If a compressed stream with a larger window
+   size is given as input, inflate() will return with the error code
+   Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+   determines the window size. inflate() will then process raw deflate data,
+   not looking for a zlib or gzip header, not generating a check value, and not
+   looking for any check values for comparison at the end of the stream. This
+   is for use with other formats that use the deflate compressed data format
+   such as zip.  Those formats provide their own check values. If a custom
+   format is developed using the raw deflate format for compressed data, it is
+   recommended that a check value such as an adler32 or a crc32 be applied to
+   the uncompressed data as is done in the zlib, gzip, and zip formats.  For
+   most applications, the zlib format should be used as is. Note that comments
+   above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+     windowBits can also be greater than 15 for optional gzip decoding. Add
+   32 to windowBits to enable zlib and gzip decoding with automatic header
+   detection, or add 16 to decode only the gzip format (the zlib format will
+   return a Z_DATA_ERROR).
+
+     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
+   memLevel). msg is set to null if there is no error message.  inflateInit2
+   does not perform any decompression apart from reading the zlib header if
+   present: this will be done by inflate(). (So next_in and avail_in may be
+   modified, but next_out and avail_out are unchanged.)
+*/
+
+int inflateSetDictionary(z_streamp strm, ubyte* dictionary, uint  dictLength);
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence. This function must be called immediately after a call of inflate
+   if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
+   can be determined from the adler32 value returned by this call of
+   inflate. The compressor and decompressor must use exactly the same
+   dictionary (see deflateSetDictionary).
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect adler32 value). inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+int inflateSync(z_streamp strm);
+/* 
+    Skips invalid compressed data until a full flush point (see above the
+  description of deflate with Z_FULL_FLUSH) can be found, or until all
+  available input is skipped. No output is provided.
+
+    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+  case, the application may save the current current value of total_in which
+  indicates where valid compressed data was found. In the error case, the
+  application may repeatedly call inflateSync, providing more input each time,
+  until success or end of the input data.
+*/
+
+int inflateCopy (z_streamp dest, z_streamp source);
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when randomly accessing a large stream.  The
+   first pass through the stream can periodically record the inflate state,
+   allowing restarting inflate at those points when randomly accessing the
+   stream.
+
+     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+int inflateReset(z_streamp strm);
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.
+   The stream will keep attributes that may have been set by inflateInit2.
+
+      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+
+int inflateBackInit(z_stream* strm, int windowBits, ubyte* window)
+{
+    return inflateBackInit_(strm, windowBits, window, ZLIB_VERSION.ptr, z_stream.sizeof);   
+}
+/*
+     Initialize the internal stream state for decompression using inflateBack()
+   calls.  The fields zalloc, zfree and opaque in strm must be initialized
+   before the call.  If zalloc and zfree are Z_NULL, then the default library-
+   derived memory allocation routines are used.  windowBits is the base two
+   logarithm of the window size, in the range 8..15.  window is a caller
+   supplied buffer of that size.  Except for special applications where it is
+   assured that deflate was used with small window sizes, windowBits must be 15
+   and a 32K byte window must be supplied to be able to decompress general
+   deflate streams.
+
+     See inflateBack() for the usage of these routines.
+
+     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+   the paramaters are invalid, Z_MEM_ERROR if the internal state could not
+   be allocated, or Z_VERSION_ERROR if the version of the library does not
+   match the version of the header file.
+*/
+
+alias uint function(void*, ubyte**) in_func;
+alias int function(void*, ubyte*, uint) out_func;
+
+int inflateBack(z_stream* strm,
+                in_func f_in,
+                void* in_desc,
+                out_func f_out,
+                void* out_desc);
+/*
+     inflateBack() does a raw inflate with a single call using a call-back
+   interface for input and output.  This is more efficient than inflate() for
+   file i/o applications in that it avoids copying between the output and the
+   sliding window by simply making the window itself the output buffer.  This
+   function trusts the application to not change the output buffer passed by
+   the output function, at least until inflateBack() returns.
+
+     inflateBackInit() must be called first to allocate the internal state
+   and to initialize the state with the user-provided window buffer.
+   inflateBack() may then be used multiple times to inflate a complete, raw
+   deflate stream with each call.  inflateBackEnd() is then called to free
+   the allocated state.
+
+     A raw deflate stream is one with no zlib or gzip header or trailer.
+   This routine would normally be used in a utility that reads zip or gzip
+   files and writes out uncompressed files.  The utility would decode the
+   header and process the trailer on its own, hence this routine expects
+   only the raw deflate stream to decompress.  This is different from the
+   normal behavior of inflate(), which expects either a zlib or gzip header and
+   trailer around the deflate stream.
+
+     inflateBack() uses two subroutines supplied by the caller that are then
+   called by inflateBack() for input and output.  inflateBack() calls those
+   routines until it reads a complete deflate stream and writes out all of the
+   uncompressed data, or until it encounters an error.  The function's
+   parameters and return types are defined above in the in_func and out_func
+   typedefs.  inflateBack() will call in(in_desc, &buf) which should return the
+   number of bytes of provided input, and a pointer to that input in buf.  If
+   there is no input available, in() must return zero--buf is ignored in that
+   case--and inflateBack() will return a buffer error.  inflateBack() will call
+   out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].  out()
+   should return zero on success, or non-zero on failure.  If out() returns
+   non-zero, inflateBack() will return with an error.  Neither in() nor out()
+   are permitted to change the contents of the window provided to
+   inflateBackInit(), which is also the buffer that out() uses to write from.
+   The length written by out() will be at most the window size.  Any non-zero
+   amount of input may be provided by in().
+
+     For convenience, inflateBack() can be provided input on the first call by
+   setting strm->next_in and strm->avail_in.  If that input is exhausted, then
+   in() will be called.  Therefore strm->next_in must be initialized before
+   calling inflateBack().  If strm->next_in is Z_NULL, then in() will be called
+   immediately for input.  If strm->next_in is not Z_NULL, then strm->avail_in
+   must also be initialized, and then if strm->avail_in is not zero, input will
+   initially be taken from strm->next_in[0 .. strm->avail_in - 1].
+
+     The in_desc and out_desc parameters of inflateBack() is passed as the
+   first parameter of in() and out() respectively when they are called.  These
+   descriptors can be optionally used to pass any information that the caller-
+   supplied in() and out() functions need to do their job.
+
+     On return, inflateBack() will set strm->next_in and strm->avail_in to
+   pass back any unused input that was provided by the last in() call.  The
+   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+   if in() or out() returned an error, Z_DATA_ERROR if there was a format
+   error in the deflate stream (in which case strm->msg is set to indicate the
+   nature of the error), or Z_STREAM_ERROR if the stream was not properly
+   initialized.  In the case of Z_BUF_ERROR, an input or output error can be
+   distinguished using strm->next_in which will be Z_NULL only if in() returned
+   an error.  If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to
+   out() returning non-zero.  (in() will always be called before out(), so
+   strm->next_in is assured to be defined if out() returns non-zero.)  Note
+   that inflateBack() cannot return Z_OK.
+*/
+
+int inflateBackEnd(z_stream* strm);
+/*
+     All memory allocated by inflateBackInit() is freed.
+
+     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+   state was inconsistent.
+*/
+
+uint zlibCompileFlags();
+/* Return flags indicating compile-time options.
+
+    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+     1.0: size of uInt
+     3.2: size of uLong
+     5.4: size of voidpf (pointer)
+     7.6: size of z_off_t
+
+    Compiler, assembler, and debug options:
+     8: DEBUG
+     9: ASMV or ASMINF -- use ASM code
+     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+     11: 0 (reserved)
+
+    One-time table building (smaller code, but not thread-safe if true):
+     12: BUILDFIXED -- build static block decoding tables when needed
+     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+     14,15: 0 (reserved)
+
+    Library content (indicates missing functionality):
+     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+                          deflate code when not needed)
+     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+                    and decode gzip streams (to avoid linking crc code)
+     18-19: 0 (reserved)
+
+    Operation variations (changes in library functionality):
+     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+     21: FASTEST -- deflate algorithm with only one, lowest compression level
+     22,23: 0 (reserved)
+
+    The sprintf variant used by gzprintf (zero is best):
+     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+     26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+    Remainder:
+     27-31: 0 (reserved)
+ */
+
+                        /* utility functions */
+
+/*
+     The following utility functions are implemented on top of the
+   basic stream-oriented functions. To simplify the interface, some
+   default options are assumed (compression level and memory usage,
+   standard memory allocation functions). The source code of these
+   utility functions can easily be modified if you need special options.
+*/
+
+int compress(ubyte* dest,
+             Culong_t* destLen,
+             ubyte* source,
+             Culong_t sourceLen);
+/*
+     Compresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be at least the value returned
+   by compressBound(sourceLen). Upon exit, destLen is the actual size of the
+   compressed buffer.
+     This function can be used to compress a whole file at once if the
+   input file is mmap'ed.
+     compress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer.
+*/
+
+int compress2(ubyte* dest,
+              Culong_t* destLen,
+              ubyte* source,
+              Culong_t sourceLen,
+              int level);
+/*
+     Compresses the source buffer into the destination buffer. The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer. Upon entry, destLen is the total size of the
+   destination buffer, which must be at least the value returned by
+   compressBound(sourceLen). Upon exit, destLen is the actual size of the
+   compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+uint compressBound(Culong_t sourceLen);
+/*
+     compressBound() returns an upper bound on the compressed size after
+   compress() or compress2() on sourceLen bytes.  It would be used before
+   a compress() or compress2() call to allocate the destination buffer.
+*/
+
+int uncompress(ubyte* dest,
+               uint* Culong_t,
+               ubyte* source,
+               uint Culong_t);
+/*
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+     This function can be used to decompress a whole file at once if the
+   input file is mmap'ed.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
+*/
+
+
+typedef void* gzFile;
+alias int z_off_t;		// file offset
+
+gzFile gzopen(char* path, char* mode);
+/*
+     Opens a gzip (.gz) file for reading or writing. The mode parameter
+   is as in fopen ("rb" or "wb") but can also include a compression level
+   ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+   Huffman only compression as in "wb1h", or 'R' for run-length encoding
+   as in "wb1R". (See the description of deflateInit2 for more information
+   about the strategy parameter.)
+
+     gzopen can be used to read a file which is not in gzip format; in this
+   case gzread will directly read from the file without decompression.
+
+     gzopen returns NULL if the file could not be opened or if there was
+   insufficient memory to allocate the (de)compression state; errno
+   can be checked to distinguish the two cases (if errno is zero, the
+   zlib error is Z_MEM_ERROR).  */
+
+gzFile gzdopen(int fd, char* mode);
+/*
+     gzdopen() associates a gzFile with the file descriptor fd.  File
+   descriptors are obtained from calls like open, dup, creat, pipe or
+   fileno (in the file has been previously opened with fopen).
+   The mode parameter is as in gzopen.
+     The next call of gzclose on the returned gzFile will also close the
+   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+     gzdopen returns NULL if there was insufficient memory to allocate
+   the (de)compression state.
+*/
+
+int gzsetparams(gzFile file, int level, int strategy);
+/*
+     Dynamically update the compression level or strategy. See the description
+   of deflateInit2 for the meaning of these parameters.
+     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+   opened for writing.
+*/
+
+int gzread(gzFile file, void* buf, uint len);
+/*
+     Reads the given number of uncompressed bytes from the compressed file.
+   If the input file was not in gzip format, gzread copies the given number
+   of bytes into the buffer.
+     gzread returns the number of uncompressed bytes actually read (0 for
+   end of file, -1 for error). */
+
+int gzwrite(gzFile file, void* buf, uint len);
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes actually written
+   (0 in case of error).
+*/
+
+int gzprintf(gzFile file, char* format, ...);
+/*
+     Converts, formats, and writes the args to the compressed file under
+   control of the format string, as in fprintf. gzprintf returns the number of
+   uncompressed bytes actually written (0 in case of error).  The number of
+   uncompressed bytes written is limited to 4095. The caller should assure that
+   this limit is not exceeded. If it is exceeded, then gzprintf() will return
+   return an error (0) with nothing written. In this case, there may also be a
+   buffer overflow with unpredictable consequences, which is possible only if
+   zlib was compiled with the insecure functions sprintf() or vsprintf()
+   because the secure snprintf() or vsnprintf() functions were not available.
+*/
+
+int gzputs(gzFile file, char* s);
+/*
+      Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+      gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+char* gzgets(gzFile file, char* buf, int len);
+/*
+      Reads bytes from the compressed file until len-1 characters are read, or
+   a newline character is read and transferred to buf, or an end-of-file
+   condition is encountered.  The string is then terminated with a null
+   character.
+      gzgets returns buf, or Z_NULL in case of error.
+*/
+
+int gzputc(gzFile file, int c);
+/*
+      Writes c, converted to an unsigned char, into the compressed file.
+   gzputc returns the value that was written, or -1 in case of error.
+*/
+
+int    gzgetc(gzFile file);
+/*
+      Reads one byte from the compressed file. gzgetc returns this byte
+   or -1 in case of end of file or error.
+*/
+
+int gzungetc(int c, gzFile file);
+/*
+      Push one character back onto the stream to be read again later.
+   Only one character of push-back is allowed.  gzungetc() returns the
+   character pushed, or -1 on failure.  gzungetc() will fail if a
+   character has been pushed but not read yet, or if c is -1. The pushed
+   character will be discarded if the stream is repositioned with gzseek()
+   or gzrewind().
+*/
+
+int gzflush(gzFile file, int flush);
+/*
+     Flushes all pending output into the compressed file. The parameter
+   flush is as in the deflate() function. The return value is the zlib
+   error number (see function gzerror below). gzflush returns Z_OK if
+   the flush parameter is Z_FINISH and all output could be flushed.
+     gzflush should be called only when strictly necessary because it can
+   degrade compression.
+*/
+
+z_off_t gzseek(gzFile file, z_off_t offset, int whence);
+/* 
+      Sets the starting position for the next gzread or gzwrite on the
+   given compressed file. The offset represents a number of bytes in the
+   uncompressed data stream. The whence parameter is defined as in lseek(2);
+   the value SEEK_END is not supported.
+     If the file is opened for reading, this function is emulated but can be
+   extremely slow. If the file is opened for writing, only forward seeks are
+   supported; gzseek then compresses a sequence of zeroes up to the new
+   starting position.
+
+      gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error, in
+   particular if the file is opened for writing and the new starting position
+   would be before the current position.
+*/
+
+int gzrewind(gzFile file);
+/*
+     Rewinds the given file. This function is supported only for reading.
+
+   gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+z_off_t  gztell(gzFile file);
+/*
+     Returns the starting position for the next gzread or gzwrite on the
+   given compressed file. This position represents a number of bytes in the
+   uncompressed data stream.
+
+   gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+int gzeof(gzFile file);
+/*
+     Returns 1 when EOF has previously been detected reading the given
+   input stream, otherwise zero.
+*/
+
+int gzclose(gzFile file);
+/*
+     Flushes all pending output if necessary, closes the compressed file
+   and deallocates all the (de)compression state. The return value is the zlib
+   error number (see function gzerror below).
+*/
+
+char* gzerror(gzFile file, int *errnum);
+/*
+     Returns the error message for the last error which occurred on the
+   given compressed file. errnum is set to zlib error number. If an
+   error occurred in the file system and not in the compression library,
+   errnum is set to Z_ERRNO and the application may consult errno
+   to get the exact error code.
+*/
+
+void gzclearerr (gzFile file);
+/*
+     Clears the error and end-of-file flags for file. This is analogous to the
+   clearerr() function in stdio. This is useful for continuing to read a gzip
+   file that is being written concurrently.
+*/
+
+                        /* checksum functions */
+
+/*
+     These functions are not related to compression but are exported
+   anyway because they might be useful in applications using the
+   compression library.
+*/
+
+ Culong_t adler32  (Culong_t adler, ubyte *buf, uint len);
+
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NULL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+     uint adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+Culong_t crc32(Culong_t crc, ubyte *buf, uint len);
+/*
+     Update a running crc with the bytes buf[0..len-1] and return the updated
+   crc. If buf is NULL, this function returns the required initial value
+   for the crc. Pre- and post-conditioning (one's complement) is performed
+   within this function so it shouldn't be done by the application.
+   Usage example:
+
+     uint crc = crc32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       crc = crc32(crc, buffer, length);
+     }
+     if (crc != original_crc) error();
+*/
+
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+int deflateInit_(z_streamp strm,
+                 int level,
+                 char* versionx,
+                 int stream_size);
+                 
+int inflateInit_(z_streamp strm,
+                 char* versionx,
+                 int stream_size);
+                 
+int deflateInit2_(z_streamp strm,
+                  int level,
+                  int method,
+                  int windowBits,
+                  int memLevel,
+                  int strategy,
+                  char* versionx,
+                  int stream_size);
+                  
+int inflateBackInit_(z_stream* strm,
+                     int windowBits,
+                     ubyte* window,
+                     char* z_version,
+                     int stream_size);
+                     
+int inflateInit2_(z_streamp strm,
+                  int windowBits,
+                  char* versionx,
+                  int stream_size);
+                  
+char* zError(int err);
+int inflateSyncPoint(z_streamp z);
+Culong_t* get_crc_table();
--- a/lphobos/gc/gc.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/gc/gc.d	Mon Aug 04 19:28:49 2008 +0200
@@ -1,151 +1,1028 @@
-/**
- * Part of the D programming language runtime library.
- */
-
-/*
- *  Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com
- *  Written by Walter Bright
- *
- *  This software is provided 'as-is', without any express or implied
- *  warranty. In no event will the authors be held liable for any damages
- *  arising from the use of this software.
- *
- *  Permission is granted to anyone to use this software for any purpose,
- *  including commercial applications, and to alter it and redistribute it
- *  freely, subject to the following restrictions:
- *
- *  o  The origin of this software must not be misrepresented; you must not
- *     claim that you wrote the original software. If you use this software
- *     in a product, an acknowledgment in the product documentation would be
- *     appreciated but is not required.
- *  o  Altered source versions must be plainly marked as such, and must not
- *     be misrepresented as being the original software.
- *  o  This notice may not be removed or altered from any source
- *     distribution.
- */
-
-
-// Storage allocation
-
-module std.gc;
-
-//debug = PRINTF;
-
-public import std.c.stdarg;
-public import std.c.stdlib;
-public import std.c.string;
-public import gcx;
-public import std.outofmemory;
-public import gcstats;
-public import std.thread;
-
-version=GCCLASS;
-
-version (GCCLASS)
-    alias GC gc_t;
-else
-    alias GC* gc_t;
-
-gc_t _gc;
-
-void addRoot(void *p)		      { _gc.addRoot(p); }
-void removeRoot(void *p)	      { _gc.removeRoot(p); }
-void addRange(void *pbot, void *ptop) { _gc.addRange(pbot, ptop); }
-void removeRange(void *pbot)	      { _gc.removeRange(pbot); }
-void fullCollect()		      { _gc.fullCollect(); }
-void fullCollectNoStack()	      { _gc.fullCollectNoStack(); }
-void genCollect()		      { _gc.genCollect(); }
-void minimize()			      { _gc.minimize(); }
-void disable()			      { _gc.disable(); }
-void enable()			      { _gc.enable(); }
-void getStats(out GCStats stats)      { _gc.getStats(stats); }
-void hasPointers(void* p)	      { _gc.hasPointers(p); }
-void hasNoPointers(void* p)	      { _gc.hasNoPointers(p); }
-void setV1_0()			      { _gc.setV1_0(); }
-
-void[] malloc(size_t nbytes)
-{
-    void* p = _gc.malloc(nbytes);
-    return p[0 .. nbytes];
-}
-
-void[] realloc(void* p, size_t nbytes)
-{
-    void* q = _gc.realloc(p, nbytes);
-    return q[0 .. nbytes];
-}
-
-size_t extend(void* p, size_t minbytes, size_t maxbytes)
-{
-    return _gc.extend(p, minbytes, maxbytes);
-}
-
-size_t capacity(void* p)
-{
-    return _gc.capacity(p);
-}
-
-void setTypeInfo(TypeInfo ti, void* p)
-{
-    if (ti.flags() & 1)
-	hasNoPointers(p);
-    else
-	hasPointers(p);
-}
-
-void* getGCHandle()
-{
-    return cast(void*)_gc;
-}
-
-void setGCHandle(void* p)
-{
-    void* oldp = getGCHandle();
-    gc_t g = cast(gc_t)p;
-    if (g.gcversion != gcx.GCVERSION)
-	throw new Error("incompatible gc versions");
-
-    // Add our static data to the new gc
-    GC.scanStaticData(g);
-
-    _gc = g;
-//    return oldp;
-}
-
-void endGCHandle()
-{
-    GC.unscanStaticData(_gc);
-}
-
-extern (C)
-{
-
-void _d_monitorrelease(Object h);
-
-
-void gc_init()
-{
-    version (GCCLASS)
-    {	void* p;
-	ClassInfo ci = GC.classinfo;
-
-	p = std.c.stdlib.malloc(ci.init.length);
-	(cast(byte*)p)[0 .. ci.init.length] = ci.init[];
-	_gc = cast(GC)p;
-    }
-    else
-    {
-	_gc = cast(GC *) std.c.stdlib.calloc(1, GC.sizeof);
-    }
-    _gc.initialize();
-    GC.scanStaticData(_gc);
-    std.thread.Thread.thread_init();
-}
-
-void gc_term()
-{
-    _gc.fullCollectNoStack();
-    _gc.Dtor();
-}
-
-}
+/**
+ * Part of the D programming language runtime library.
+ */
+
+/*
+ *  Copyright (C) 2004-2008 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, subject to the following restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/* NOTE: This file has been patched from the original DMD distribution to
+   work with the GDC compiler.
+
+   Modified by David Friedman, February 2007
+*/
+
+
+// Storage allocation
+
+module std.gc;
+
+//debug = PRINTF;
+
+public import std.c.stdarg;
+public import std.c.stdlib;
+public import std.c.string;
+public import gcx;
+public import std.outofmemory;
+public import gcstats;
+public import std.thread;
+
+version=GCCLASS;
+
+version (GCCLASS)
+    alias GC gc_t;
+else
+    alias GC* gc_t;
+
+gc_t _gc;
+
+void addRoot(void *p)		      { _gc.addRoot(p); }
+void removeRoot(void *p)	      { _gc.removeRoot(p); }
+void addRange(void *pbot, void *ptop) { _gc.addRange(pbot, ptop); }
+void removeRange(void *pbot)	      { _gc.removeRange(pbot); }
+void fullCollect()		      { _gc.fullCollect(); }
+void fullCollectNoStack()	      { _gc.fullCollectNoStack(); }
+void genCollect()		      { _gc.genCollect(); }
+void minimize()			      { _gc.minimize(); }
+void disable()			      { _gc.disable(); }
+void enable()			      { _gc.enable(); }
+void getStats(out GCStats stats)      { _gc.getStats(stats); }
+void hasPointers(void* p)	      { _gc.hasPointers(p); }
+void hasNoPointers(void* p)	      { _gc.hasNoPointers(p); }
+void setV1_0()			      { _gc.setV1_0(); }
+
+void[] malloc(size_t nbytes)
+{
+    void* p = _gc.malloc(nbytes);
+    return p[0 .. nbytes];
+}
+
+void[] realloc(void* p, size_t nbytes)
+{
+    void* q = _gc.realloc(p, nbytes);
+    return q[0 .. nbytes];
+}
+
+size_t extend(void* p, size_t minbytes, size_t maxbytes)
+{
+    return _gc.extend(p, minbytes, maxbytes);
+}
+
+size_t capacity(void* p)
+{
+    return _gc.capacity(p);
+}
+
+void setTypeInfo(TypeInfo ti, void* p)
+{
+    if (ti.flags() & 1)
+	hasNoPointers(p);
+    else
+	hasPointers(p);
+}
+
+void* getGCHandle()
+{
+    return cast(void*)_gc;
+}
+
+void setGCHandle(void* p)
+{
+    void* oldp = getGCHandle();
+    gc_t g = cast(gc_t)p;
+    if (g.gcversion != gcx.GCVERSION)
+	throw new Error("incompatible gc versions");
+
+    // Add our static data to the new gc
+    GC.scanStaticData(g);
+
+    _gc = g;
+//    return oldp;
+}
+
+void endGCHandle()
+{
+    GC.unscanStaticData(_gc);
+}
+
+extern (C)
+{
+
+void _d_monitorexit(Object h);
+
+
+void gc_init()
+{
+    version (GCCLASS)
+    {	void* p;
+	ClassInfo ci = GC.classinfo;
+
+	p = std.c.stdlib.malloc(ci.init.length);
+	(cast(byte*)p)[0 .. ci.init.length] = ci.init[];
+	_gc = cast(GC)p;
+    }
+    else
+    {
+	_gc = cast(GC *) std.c.stdlib.calloc(1, GC.sizeof);
+    }
+    _gc.initialize();
+    GC.scanStaticData(_gc);
+    std.thread.Thread.thread_init();
+}
+
+void gc_term()
+{
+    _gc.fullCollectNoStack();
+    _gc.Dtor();
+}
+
+Object _d_newclass(ClassInfo ci)
+{
+    void *p;
+
+    debug(PRINTF) printf("_d_newclass(ci = %p, %s)\n", ci, cast(char *)ci.name);
+    if (ci.flags & 1)			// if COM object
+    {
+	p = std.c.stdlib.malloc(ci.init.length);
+	if (!p)
+	    _d_OutOfMemory();
+	debug(PRINTF) printf(" COM object p = %p\n", p);
+    }
+    else
+    {
+	p = _gc.malloc(ci.init.length);
+	debug(PRINTF) printf(" p = %p\n", p);
+	_gc.setFinalizer(p, &new_finalizer);
+	if (ci.flags & 2)
+	    _gc.hasNoPointers(p);
+    }
+
+    debug (PRINTF)
+    {
+	printf("p = %p\n", p);
+	printf("ci = %p, ci.init = %p, len = %d\n", ci, ci.init, ci.init.length);
+	printf("vptr = %p\n", *cast(void **)ci.init);
+	printf("vtbl[0] = %p\n", (*cast(void ***)ci.init)[0]);
+	printf("vtbl[1] = %p\n", (*cast(void ***)ci.init)[1]);
+	printf("init[0] = %x\n", (cast(uint *)ci.init)[0]);
+	printf("init[1] = %x\n", (cast(uint *)ci.init)[1]);
+	printf("init[2] = %x\n", (cast(uint *)ci.init)[2]);
+	printf("init[3] = %x\n", (cast(uint *)ci.init)[3]);
+	printf("init[4] = %x\n", (cast(uint *)ci.init)[4]);
+    }
+
+
+    // Initialize it
+    (cast(byte*)p)[0 .. ci.init.length] = ci.init[];
+
+    //printf("initialization done\n");
+    return cast(Object)p;
+}
+
+extern (D) alias void (*fp_t)(Object);		// generic function pointer
+
+void _d_delinterface(void** p)
+{
+    if (*p)
+    {
+	Interface *pi = **cast(Interface ***)*p;
+	Object o;
+
+	o = cast(Object)(*p - pi.offset);
+	_d_delclass(&o);
+	*p = null;
+    }
+}
+
+void _d_delclass(Object *p)
+{
+    if (*p)
+    {
+	debug (PRINTF) printf("_d_delclass(%p)\n", *p);
+	version(0)
+	{
+	    ClassInfo **pc = cast(ClassInfo **)*p;
+	    if (*pc)
+	    {
+		ClassInfo c = **pc;
+
+		if (c.deallocator)
+		{
+		    _d_callfinalizer(cast(void *)(*p));
+		    fp_t fp = cast(fp_t)c.deallocator;
+		    (*fp)(*p);			// call deallocator
+		    *p = null;
+		    return;
+		}
+	    }
+	}
+	_gc.free(cast(void*)(*p));
+	*p = null;
+    }
+}
+
+/******************************************
+ * Allocate a new array of length elements.
+ * ti is the type of the resulting array, or pointer to element.
+ */
+
+/* For when the array is initialized to 0 */
+void* _d_newarrayT(TypeInfo ti, size_t length)
+{
+    void* result;
+    auto size = ti.next.tsize();		// array element size
+
+    debug(PRINTF) printf("_d_newarrayT(length = x%x, size = %d)\n", length, size);
+    if (length && size)
+    {
+	/*version (D_InlineAsm_X86)
+	{
+	    asm
+	    {
+		mov	EAX,size	;
+		mul	EAX,length	;
+		mov	size,EAX	;
+		jc	Loverflow	;
+	    }
+	}
+	else*/
+	    size *= length;
+	result = cast(byte*) _gc.malloc(size + 1);
+	if (!(ti.next.flags() & 1))
+	    _gc.hasNoPointers(result);
+	memset(result, 0, size);
+    }
+    return result;
+
+Loverflow:
+    _d_OutOfMemory();
+}
+
+/* For when the array has a non-zero initializer.
+ */
+void* _d_newarrayiT(TypeInfo ti, size_t length)
+{
+    void* result;
+    auto size = ti.next.tsize();		// array element size
+
+    debug(PRINTF)
+	 printf("_d_newarrayiT(length = %d, size = %d)\n", length, size);
+    if (length == 0 || size == 0)
+	{ }
+    else
+    {
+	auto initializer = ti.next.init();
+	auto isize = initializer.length;
+	auto q = initializer.ptr;
+	/*version (D_InlineAsm_X86)
+	{
+	    asm
+	    {
+		mov	EAX,size	;
+		mul	EAX,length	;
+		mov	size,EAX	;
+		jc	Loverflow	;
+	    }
+	}
+	else*/
+	    size *= length;
+	auto p = _gc.malloc(size + 1);
+	debug(PRINTF) printf(" p = %p\n", p);
+	if (!(ti.next.flags() & 1))
+	    _gc.hasNoPointers(p);
+	if (isize == 1)
+	    memset(p, *cast(ubyte*)q, size);
+	else if (isize == int.sizeof)
+	{
+	    int init = *cast(int*)q;
+	    size /= int.sizeof;
+	    for (size_t u = 0; u < size; u++)
+	    {
+		(cast(int*)p)[u] = init;
+	    }
+	}
+	else
+	{
+	    for (size_t u = 0; u < size; u += isize)
+	    {
+		memcpy(p + u, q, isize);
+	    }
+	}
+	result = cast(byte*) p
;
+    }
+    return result;
+
+Loverflow:
+    _d_OutOfMemory();
+}
+
+void[] _d_newarraymTp(TypeInfo ti, int ndims, size_t* pdim)
+{
+    void[] result = void;
+
+    //debug(PRINTF)
+	//printf("_d_newarraymT(ndims = %d)\n", ndims);
+    if (ndims == 0)
+	result = null;
+    else
+    {
+
+	void[] foo(TypeInfo ti, size_t* pdim, int ndims)
+	{
+	    size_t dim = *pdim;
+	    void[] p;
+
+	    //printf("foo(ti = %p, ti.next = %p, dim = %d, ndims = %d\n", ti, ti.next, dim, ndims);
+	    if (ndims == 1)
+	    {
+		auto r = _d_newarrayT(ti, dim);
+		p = *cast(void[]*)(&r);
+	    }
+	    else
+	    {
+		p = _gc.malloc(dim * (void[]).sizeof + 1)[0 .. dim];
+		for (int i = 0; i < dim; i++)
+		{
+		    (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1);
+		}
+	    }
+	    return p;
+	}
+
+	result = foo(ti, pdim, ndims);
+	//printf("result = %llx\n", result);
+
+	version (none)
+	{
+	    for (int i = 0; i < ndims; i++)
+	    {
+		printf("index %d: %d\n", i, pdim[i]);
+	    }
+	}
+    }
+    return result;
+}
+
+void[] _d_newarraymiTp(TypeInfo ti, int ndims, size_t* pdim)
+{
+    void[] result = void;
+
+    //debug(PRINTF)
+	//printf("_d_newarraymi(size = %d, ndims = %d)\n", size, ndims);
+    if (ndims == 0)
+	result = null;
+    else
+    {
+
+	void[] foo(TypeInfo ti, size_t* pdim, int ndims)
+	{
+	    size_t dim = *pdim;
+	    void[] p;
+
+	    if (ndims == 1)
+	    {
+		auto r = _d_newarrayiT(ti, dim);
+		p = *cast(void[]*)(&r);
+	    }
+	    else
+	    {
+		p = _gc.malloc(dim * (void[]).sizeof + 1)[0 .. dim];
+		for (int i = 0; i < dim; i++)
+		{
+		    (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1);
+		}
+	    }
+	    return p;
+	}
+
+	result = foo(ti, pdim, ndims);
+	//printf("result = %llx\n", result);
+
+	version (none)
+	{
+	    for (int i = 0; i < ndims; i++)
+	    {
+		printf("index %d: %d\n", i, pdim[i]);
+		printf("init = %d\n", *cast(int*)pinit);
+	    }
+	}
+    }
+    return result;
+}
+
+struct Array
+{
+    size_t length;
+    byte *data;
+};
+
+// Perhaps we should get a a size argument like _d_new(), so we
+// can zero out the array?
+
+void _d_delarray(size_t plength, void* pdata)
+{
+    assert(!plength || pdata);
+    if (pdata) _gc.free(pdata);
+}
+
+
+void _d_delmemory(void* *p)
+{
+    if (*p)
+    {
+	_gc.free(*p);
+	*p = null;
+    }
+}
+
+
+}
+
+void new_finalizer(void *p, bool dummy)
+{
+    //printf("new_finalizer(p = %p)\n", p);
+    _d_callfinalizer(p);
+}
+
+extern (C)
+void _d_callinterfacefinalizer(void *p)
+{
+    //printf("_d_callinterfacefinalizer(p = %p)\n", p);
+    if (p)
+    {
+	Interface *pi = **cast(Interface ***)p;
+	Object o = cast(Object)(p - pi.offset);
+	_d_callfinalizer(cast(void*)o);
+    }
+}
+
+extern (C)
+void _d_callfinalizer(void *p)
+{
+    //printf("_d_callfinalizer(p = %p)\n", p);
+    if (p)	// not necessary if called from gc
+    {
+	ClassInfo **pc = cast(ClassInfo **)p;
+	if (*pc)
+	{
+	    ClassInfo c = **pc;
+
+	    try
+	    {
+		do
+		{
+		    if (c.destructor)
+		    {
+			fp_t fp = cast(fp_t)c.destructor;
+			(*fp)(cast(Object)p);		// call destructor
+		    }
+		    c = c.base;
+		} while (c);
+		if ((cast(void**)p)[1])	// if monitor is not null
+		    _d_monitorexit(cast(Object)p);
+	    }
+	    finally
+	    {
+		*pc = null;			// zero vptr
+	    }
+	}
+    }
+}
+
+/+ ------------------------------------------------ +/
+
+
+/******************************
+ * Resize dynamic arrays with 0 initializers.
+ */
+
+extern (C)
+byte* _d_arraysetlengthT(TypeInfo ti, size_t newlength, size_t plength, byte* pdata)
+in
+{
+    assert(ti);
+}
+body
+{
+    byte* newdata;
+    size_t sizeelem = ti.next.tsize();
+
+    debug(PRINTF)
+    {
+	printf("_d_arraysetlengthT(p = %p, sizeelem = %d, newlength = %d)\n", p, sizeelem, newlength);
+	if (p)
+	    printf("\tpdata = %p, plength = %d\n", pdata, plength);
+    }
+
+    if (newlength)
+    {
+	version (GNU)
+	{
+	    // required to output the label;
+	    static char x = 0;
+	    if (x)
+		goto Loverflow;
+	}
+
+	version (D_InlineAsm_X86)
+	{
+	    size_t newsize = void;
+
+	    asm
+	    {
+		mov	EAX,newlength	;
+		mul	EAX,sizeelem	;
+		mov	newsize,EAX	;
+		jc	Loverflow	;
+	    }
+	}
+	else
+	{
+	    size_t newsize = sizeelem * newlength;
+
+	    if (newsize / newlength != sizeelem)
+		goto Loverflow;
+	}
+	//printf("newsize = %x, newlength = %x\n", newsize, newlength);
+
+	if (pdata)
+	{
+	    newdata = pdata;
+	    if (newlength > plength)
+	    {
+		size_t size = plength * sizeelem;
+		size_t cap = _gc.capacity(pdata);
+
+		if (cap <= newsize)
+		{
+		    if (cap >= 4096)
+		    {	// Try to extend in-place
+			auto u = _gc.extend(pdata, (newsize + 1) - cap, (newsize + 1) - cap);
+			if (u)
+			{
+			    goto L1;
+			}
+		    }
+		    newdata = cast(byte *)_gc.malloc(newsize + 1);
+		    newdata[0 .. size] = pdata[0 .. size];
+		    if (!(ti.next.flags() & 1))
+			_gc.hasNoPointers(newdata);
+		}
+	     L1:
+		newdata[size .. newsize] = 0;
+	    }
+	}
+	else
+	{
+	    newdata = cast(byte *)_gc.calloc(newsize + 1, 1);
+	    if (!(ti.next.flags() & 1))
+		_gc.hasNoPointers(newdata);
+	}
+    }
+    else
+    {
+	newdata = pdata;
+    }
+
+    pdata = newdata;
+    plength = newlength;
+    return newdata;
+
+Loverflow:
+    _d_OutOfMemory();
+}
+
+/**
+ * Resize arrays for non-zero initializers.
+ *	p		pointer to array lvalue to be updated
+ *	newlength	new .length property of array
+ *	sizeelem	size of each element of array
+ *	initsize	size of initializer
+ *	...		initializer
+ */
+extern (C)
+byte* _d_arraysetlengthiT(TypeInfo ti, size_t newlength, size_t plength, byte* pdata)
+in
+{
+    assert(!plength || pdata);
+}
+body
+{
+    byte* newdata;
+    size_t sizeelem = ti.next.tsize();
+    void[] initializer = ti.next.init();
+    size_t initsize = initializer.length;
+
+    assert(sizeelem);
+    assert(initsize);
+    assert(initsize <= sizeelem);
+    assert((sizeelem / initsize) * initsize == sizeelem);
+
+    debug(PRINTF)
+    {
+	printf("_d_arraysetlengthiT(p = %p, sizeelem = %d, newlength = %d, initsize = %d)\n", p, sizeelem, newlength, initsize);
+	if (p)
+	    printf("\tpdata = %p, plength = %d\n", pdata, plength);
+    }
+
+    if (newlength)
+    {
+	version (GNU)
+	{
+	    // required to output the label;
+	    static char x = 0;
+	    if (x)
+		goto Loverflow;
+	}
+
+	version (D_InlineAsm_X86)
+	{
+	    size_t newsize = void;
+
+	    asm
+	    {
+		mov	EAX,newlength	;
+		mul	EAX,sizeelem	;
+		mov	newsize,EAX	;
+		jc	Loverflow	;
+	    }
+	}
+	else
+	{
+	    size_t newsize = sizeelem * newlength;
+
+	    if (newsize / newlength != sizeelem)
+		goto Loverflow;
+	}
+	//printf("newsize = %x, newlength = %x\n", newsize, newlength);
+
+	size_t size = plength * sizeelem;
+	if (pdata)
+	{
+	    newdata = pdata;
+	    if (newlength > plength)
+	    {
+		size_t cap = _gc.capacity(pdata);
+
+		if (cap <= newsize)
+		{
+		    if (cap >= 4096)
+		    {	// Try to extend in-place
+			auto u = _gc.extend(pdata, (newsize + 1) - cap, (newsize + 1) - cap);
+			if (u)
+			{
+			    goto L1;
+			}
+		    }
+		    newdata = cast(byte *)_gc.malloc(newsize + 1);
+		    newdata[0 .. size] = pdata[0 .. size];
+		L1: ;
+		}
+	    }
+	}
+	else
+	{
+	    newdata = cast(byte *)_gc.malloc(newsize + 1);
+	    if (!(ti.next.flags() & 1))
+		_gc.hasNoPointers(newdata);
+	}
+
+	auto q = initializer.ptr;	// pointer to initializer
+
+	if (newsize > size)
+	{
+	    if (initsize == 1)
+	    {
+		//printf("newdata = %p, size = %d, newsize = %d, *q = %d\n", newdata, size, newsize, *cast(byte*)q);
+		newdata[size .. newsize] = *(cast(byte*)q);
+	    }
+	    else
+	    {
+		for (size_t u = size; u < newsize; u += initsize)
+		{
+		    memcpy(newdata + u, q, initsize);
+		}
+	    }
+	}
+    }
+    else
+    {
+	newdata = pdata;
+    }
+
+    pdata = newdata;
+    plength = newlength;
+    return newdata;
+
+Loverflow:
+    _d_OutOfMemory();
+}
+
+/****************************************
+ * Append y[] to array x[].
+ * size is size of each array element.
+ */
+
+extern (C)
+Array _d_arrayappendT(TypeInfo ti, Array *px, byte[] y)
+{
+    auto sizeelem = ti.next.tsize();		// array element size
+    auto cap = _gc.capacity(px.data);
+    auto length = px.length;
+    auto newlength = length + y.length;
+    auto newsize = newlength * sizeelem;
+    if (newsize > cap)
+    {   byte* newdata;
+
+	if (cap >= 4096)
+	{   // Try to extend in-place
+	    auto u = _gc.extend(px.data, (newsize + 1) - cap, (newsize + 1) - cap);
+	    if (u)
+	    {
+		goto L1;
+	    }
+	}
+
+	newdata = cast(byte *)_gc.malloc(newCapacity(newlength, sizeelem) + 1);
+	if (!(ti.next.flags() & 1))
+	    _gc.hasNoPointers(newdata);
+	memcpy(newdata, px.data, length * sizeelem);
+	px.data = newdata;
+    }
+  L1:
+    px.length = newlength;
+    memcpy(px.data + length * sizeelem, y.ptr, y.length * sizeelem);
+    return *px;
+}
+
+size_t newCapacity(size_t newlength, size_t size)
+{
+    version(none)
+    {
+	size_t newcap = newlength * size;
+    }
+    else
+    {
+	/*
+	 * Better version by Dave Fladebo:
+	 * This uses an inverse logorithmic algorithm to pre-allocate a bit more
+	 * space for larger arrays.
+	 * - Arrays smaller than 4096 bytes are left as-is, so for the most
+	 * common cases, memory allocation is 1 to 1. The small overhead added
+	 * doesn't effect small array perf. (it's virtually the same as
+	 * current).
+	 * - Larger arrays have some space pre-allocated.
+	 * - As the arrays grow, the relative pre-allocated space shrinks.
+	 * - The logorithmic algorithm allocates relatively more space for
+	 * mid-size arrays, making it very fast for medium arrays (for
+	 * mid-to-large arrays, this turns out to be quite a bit faster than the
+	 * equivalent realloc() code in C, on Linux at least. Small arrays are
+	 * just as fast as GCC).
+	 * - Perhaps most importantly, overall memory usage and stress on the GC
+	 * is decreased significantly for demanding environments.
+	 */
+	size_t newcap = newlength * size;
+	size_t newext = 0;
+
+	if (newcap > 4096)
+	{
+	    //double mult2 = 1.0 + (size / log10(pow(newcap * 2.0,2.0)));
+
+	    // Redo above line using only integer math
+
+	    static int log2plus1(size_t c)
+	    {   int i;
+
+		if (c == 0)
+		    i = -1;
+		else
+		    for (i = 1; c >>= 1; i++)
+			{   }
+		return i;
+	    }
+
+	    /* The following setting for mult sets how much bigger
+	     * the new size will be over what is actually needed.
+	     * 100 means the same size, more means proportionally more.
+	     * More means faster but more memory consumption.
+	     */
+	    //long mult = 100 + (1000L * size) / (6 * log2plus1(newcap));
+	    long mult = 100 + (1000L * size) / log2plus1(newcap);
+
+	    // testing shows 1.02 for large arrays is about the point of diminishing return
+	    if (mult < 102)
+		mult = 102;
+	    newext = cast(size_t)((newcap * mult) / 100);
+	    newext -= newext % size;
+	    //printf("mult: %2.2f, mult2: %2.2f, alloc: %2.2f\n",mult/100.0,mult2,newext / cast(double)size);
+	}
+	newcap = newext > newcap ? newext : newcap;
+	//printf("newcap = %d, newlength = %d, size = %d\n", newcap, newlength, size);
+    }
+    return newcap;
+}
+
+extern (C)
+byte[] _d_arrayappendcTp(TypeInfo ti, inout byte[] x, byte *argp)
+{
+    auto sizeelem = ti.next.tsize();		// array element size
+    auto cap = _gc.capacity(x.ptr);
+    auto length = x.length;
+    auto newlength = length + 1;
+    auto newsize = newlength * sizeelem;
+
+    assert(cap == 0 || length * sizeelem <= cap);
+
+    //printf("_d_arrayappendc(sizeelem = %d, ptr = %p, length = %d, cap = %d)\n", sizeelem, x.ptr, x.length, cap);
+
+    if (newsize >= cap)
+    {   byte* newdata;
+
+	if (cap >= 4096)
+	{   // Try to extend in-place
+	    auto u = _gc.extend(x.ptr, (newsize + 1) - cap, (newsize + 1) - cap);
+	    if (u)
+	    {
+		goto L1;
+	    }
+	}
+
+	//printf("_d_arrayappendc(sizeelem = %d, newlength = %d, cap = %d)\n", sizeelem, newlength, cap);
+	cap = newCapacity(newlength, sizeelem);
+	assert(cap >= newlength * sizeelem);
+	newdata = cast(byte *)_gc.malloc(cap + 1);
+	if (!(ti.next.flags() & 1))
+	    _gc.hasNoPointers(newdata);
+	memcpy(newdata, x.ptr, length * sizeelem);
+	(cast(void **)(&x))[1] = newdata;
+    }
+  L1:
+
+    *cast(size_t *)&x = newlength;
+    x.ptr[length * sizeelem .. newsize] = argp[0 .. sizeelem];
+    assert((cast(size_t)x.ptr & 15) == 0);
+    assert(_gc.capacity(x.ptr) >= x.length * sizeelem);
+    return x;
+}
+
+extern (C)
+byte[] _d_arraycatT(TypeInfo ti, byte[] x, byte[] y)
+out (result)
+{
+    auto sizeelem = ti.next.tsize();		// array element size
+    //printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d => %d,%p)\n", x.length, x.ptr, y.length, y.ptr, sizeelem, result.length, result.ptr);
+    assert(result.length == x.length + y.length);
+    for (size_t i = 0; i < x.length * sizeelem; i++)
+	assert((cast(byte*)result)[i] == (cast(byte*)x)[i]);
+    for (size_t i = 0; i < y.length * sizeelem; i++)
+	assert((cast(byte*)result)[x.length * sizeelem + i] == (cast(byte*)y)[i]);
+
+    size_t cap = _gc.capacity(result.ptr);
+    assert(!cap || cap > result.length * sizeelem);
+}
+body
+{
+    version (none)
+    {
+	/* Cannot use this optimization because:
+	 *  char[] a, b;
+	 *  char c = 'a';
+	 *	b = a ~ c;
+	 *	c = 'b';
+	 * will change the contents of b.
+	 */
+	if (!y.length)
+	    return x;
+	if (!x.length)
+	    return y;
+    }
+
+    //printf("_d_arraycatT(%d,%p ~ %d,%p)\n", x.length, x.ptr, y.length, y.ptr);
+    auto sizeelem = ti.next.tsize();		// array element size
+    //printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d)\n", x.length, x.ptr, y.length, y.ptr, sizeelem);
+    size_t xlen = x.length * sizeelem;
+    size_t ylen = y.length * sizeelem;
+    size_t len = xlen + ylen;
+    if (!len)
+	return null;
+
+    byte* p = cast(byte*)_gc.malloc(len + 1);
+    if (!(ti.next.flags() & 1))
+	_gc.hasNoPointers(p);
+    memcpy(p, x.ptr, xlen);
+    memcpy(p + xlen, y.ptr, ylen);
+    p[len] = 0;
+
+    return p[0 .. x.length + y.length];
+}
+
+
+extern (C)
+byte[] _d_arraycatnT(TypeInfo ti, uint n, ...)
+{   void* a;
+    size_t length;
+    byte[]* p;
+    uint i;
+    byte[] b;
+    va_list va;
+    auto sizeelem = ti.next.tsize();		// array element size
+
+    va_start!(typeof(n))(va, n);
+
+    for (i = 0; i < n; i++)
+    {
+	b = va_arg!(typeof(b))(va);
+	length += b.length;
+    }
+    if (!length)
+	return null;
+
+    a = _gc.malloc(length * sizeelem);
+    if (!(ti.next.flags() & 1))
+	_gc.hasNoPointers(a);
+    va_start!(typeof(n))(va, n);
+
+    uint j = 0;
+    for (i = 0; i < n; i++)
+    {
+	b = va_arg!(typeof(b))(va);
+	if (b.length)
+	{
+	    memcpy(a + j, b.ptr, b.length * sizeelem);
+	    j += b.length * sizeelem;
+	}
+    }
+
+    return (cast(byte*)a)[0..length];
+}
+
+version (GNU) { } else
+extern (C)
+void* _d_arrayliteralT(TypeInfo ti, size_t length, ...)
+{
+    auto sizeelem = ti.next.tsize();		// array element size
+    void* result;
+
+    //printf("_d_arrayliteralT(sizeelem = %d, length = %d)\n", sizeelem, length);
+    if (length == 0 || sizeelem == 0)
+	result = null;
+    else
+    {
+	result = _gc.malloc(length * sizeelem);
+	if (!(ti.next.flags() & 1))
+	{
+	    _gc.hasNoPointers(result);
+	}
+
+	va_list q;
+	va_start!(size_t)(q, length);
+
+	size_t stacksize = (sizeelem + int.sizeof - 1) & ~(int.sizeof - 1);
+
+	if (stacksize == sizeelem)
+	{
+	    memcpy(result, q, length * sizeelem);
+	}
+	else
+	{
+	    for (size_t i = 0; i < length; i++)
+	    {
+		memcpy(result + i * sizeelem, q, sizeelem);
+		q += stacksize;
+	    }
+	}
+
+	va_end(q);
+    }
+    return result;
+}
+
+/**********************************
+ * Support for array.dup property.
+ */
+
+/*struct Array2
+{
+    size_t length;
+    void* ptr;
+}*/
+
+extern(C) void* _d_allocmemoryT(size_t foo) { return malloc(foo).ptr; }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/gc/gc_guess_stack.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,3 @@
+module gcc.gc_guess_stack;
+void * stackOriginGuess;
+
--- a/lphobos/gc/gcbits.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/gc/gcbits.d	Mon Aug 04 19:28:49 2008 +0200
@@ -4,13 +4,24 @@
 // www.digitalmars.com
 // Written by Walter Bright
 
+/* NOTE: This file has been patched from the original DMD distribution to
+   work with the GDC compiler.
+
+   Modified by David Friedman, September 2004
+*/
+
 import std.c.string;
 import std.c.stdlib;
 import std.outofmemory;
 import std.intrinsic;
 
 //version = Asm86;
-version = bitops;
+version (GNU) {
+    // bitop intrinsics not implemented yet
+} else {
+    version = bitops;
+}
+
 
 struct GCBits
 {
--- a/lphobos/gc/gcx.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/gc/gcx.d	Mon Aug 04 19:28:49 2008 +0200
@@ -1,14 +1,17 @@
-/*
- *  Copyright (C) 2004 by Digital Mars, www.digitalmars.com
- *  Written by Walter Bright
+/**
+ * This module contains the garbage collector implementation.
  *
+ * Copyright: Copyright (C) 2001-2007 Digital Mars, www.digitalmars.com.
+ *            All rights reserved.
+ * License:
  *  This software is provided 'as-is', without any express or implied
  *  warranty. In no event will the authors be held liable for any damages
  *  arising from the use of this software.
  *
  *  Permission is granted to anyone to use this software for any purpose,
  *  including commercial applications, and to alter it and redistribute it
- *  freely, subject to the following restrictions:
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
  *
  *  o  The origin of this software must not be misrepresented; you must not
  *     claim that you wrote the original software. If you use this software
@@ -18,226 +21,2661 @@
  *     be misrepresented as being the original software.
  *  o  This notice may not be removed or altered from any source
  *     distribution.
+ * Authors:   Walter Bright, David Friedman, Sean Kelly
  */
 
-// D Garbage Collector stub to prevent linking in gc
-
-/*
- * Modified for use as the preliminary GC for LLVMDC (LLVM D Compiler)
- * by Tomas Lindquist Olsen, Dec 2007
- */
+/* NOTE: This file has been patched from the original DMD distribution to
+   work with the GDC compiler.
+
+   Modified by David Friedman, July 2006
+*/
 
 module gcx;
 
-debug=PRINTF;
+// D Garbage Collector implementation
+
+/************** Debugging ***************************/
+
+//debug = PRINTF;			// turn on printf's
+//debug = COLLECT_PRINTF;		// turn on printf's
+//debug = THREADINVARIANT;	// check thread integrity
+//debug = LOGGING;		// log allocations / frees
+//debug = MEMSTOMP;		// stomp on memory
+//debug = SENTINEL;		// add underrun/overrrun protection
+//debug = PTRCHECK;		// more pointer checking
+//debug = PTRCHECK2;		// thorough but slow pointer checking
+
+/*************** Configuration *********************/
+
+version = STACKGROWSDOWN;	// growing the stack means subtracting from the stack pointer
+				// (use for Intel X86 CPUs)
+				// else growing the stack means adding to the stack pointer
+version = MULTI_THREADED;	// produce multithreaded version
 
 /***************************************************/
 
+private import gcbits;
+private import gcstats;
+
+private import cstdlib = std.c.stdlib : calloc, free, malloc, realloc;
+private import cstring = std.c.string : memcpy, memmove, memset;
+
+debug private import std.c.stdio;
+
+import std.outofmemory;
+import std.gc;
+
+version (GNU)
+{
+    private import gcc.builtins;
+}
 
 version (Win32)
 {
     import win32;
+    import std.c.windows.windows;
 }
-
-version (linux)
+else version (GNU)
+{
+    private import gcgcc;
+}
+else version (linux)
 {
     import gclinux;
 }
 
-import gcstats;
-import stdc = std.c.stdlib;
-
-
-//alias GC* gc_t;
+/*version (BigEndian)
+  private import std.intrinsic;*/
+
+
+
+version (MULTI_THREADED)
+{
+    import std.thread;
+}
+
+
+private void onOutOfMemoryError()
+{
+    _d_OutOfMemory();
+}
+
+private void* rt_stackBottom()
+{
+    version (Win32)
+    {
+        return win32.os_query_stackBottom();
+    }
+    else version (GNU)
+    {
+	return gcgcc.os_query_stackBottom();
+    }
+    else version (linux)
+    {
+        return gclinux.os_query_stackBottom();
+    }
+}
+
+private bool thread_needLock()
+{
+    return std.thread.Thread.nthreads != 1;
+}
+
+
 alias GC gc_t;
 
-//struct GCStats { }
+version (X86) version (D_InlineAsm) { version = Asm86; }
+
+
+/* ======================= Leak Detector =========================== */
+
+
+debug (LOGGING)
+{
+    struct Log
+    {
+	void*  p;
+	size_t size;
+	uint   line;
+	char*  file;
+	void*  parent;
+
+	void print()
+	{
+	    printf("    p = %x, size = %d, parent = %x ", p, size, parent);
+	    if (file)
+	    {
+		printf("%s(%u)", file, line);
+	    }
+	    printf("\n");
+	}
+    }
+
+
+    struct LogArray
+    {
+	size_t dim;
+	size_t allocdim;
+	Log *data;
+
+	void Dtor()
+	{
+	    if (data)
+		cstdlib.free(data);
+	    data = null;
+	}
+
+	void reserve(size_t nentries)
+	{
+	    assert(dim <= allocdim);
+	    if (allocdim - dim < nentries)
+	    {
+		allocdim = (dim + nentries) * 2;
+		assert(dim + nentries <= allocdim);
+		if (!data)
+		{
+		    data = cast(Log *)cstdlib.malloc(allocdim * Log.sizeof);
+		    if (!data && allocdim)
+			onOutOfMemoryError();
+		}
+		else
+		{   Log *newdata;
+
+		    newdata = cast(Log *)cstdlib.malloc(allocdim * Log.sizeof);
+		    if (!newdata && allocdim)
+			onOutOfMemoryError();
+		    cstring.memcpy(newdata, data, dim * Log.sizeof);
+		    cstdlib.free(data);
+		    data = newdata;
+		}
+	    }
+	}
+
+
+	void push(Log log)
+	{
+	    reserve(1);
+	    data[dim++] = log;
+	}
+
+	void remove(size_t i)
+	{
+	    cstring.memmove(data + i, data + i + 1, (dim - i) * Log.sizeof);
+	    dim--;
+	}
+
+
+	size_t find(void *p)
+	{
+	    for (size_t i = 0; i < dim; i++)
+	    {
+		if (data[i].p == p)
+		    return i;
+	    }
+	    return ~0u;		// not found
+	}
+
+
+	void copy(LogArray *from)
+	{
+	    reserve(from.dim - dim);
+	    assert(from.dim <= allocdim);
+	    cstring.memcpy(data, from.data, from.dim * Log.sizeof);
+	    dim = from.dim;
+	}
+    }
+}
+
 
 /* ============================ GC =============================== */
 
 
-//alias int size_t;
 alias void (*GC_FINALIZER)(void *p, bool dummy);
 
-const uint GCVERSION = 1;   // increment every time we change interface
-                // to GC.
+class GCLock { }		// just a dummy so we can get a global lock
+
+
+const uint GCVERSION = 1;	// increment every time we change interface
+				// to GC.
 
 class GC
 {
+    // For passing to debug code
+    static size_t line;
+    static char*  file;
+
     uint gcversion = GCVERSION;
 
-    void *gcx;          // implementation
+    Gcx *gcx;			// implementation
+    static ClassInfo gcLock;	// global lock
+
 
     void initialize()
     {
-    debug(PRINTF) printf("GC initialize()\n");
+	gcLock = GCLock.classinfo;
+	gcx = cast(Gcx *)cstdlib.calloc(1, Gcx.sizeof);
+	if (!gcx)
+	    onOutOfMemoryError();
+        printf("GCX set to %p\n", gcx);
+	gcx.initialize();
+        setStackBottom(rt_stackBottom());
+    }
+
+
+    void Dtor()
+    {
+	version (linux)
+	{
+	    //debug(PRINTF) printf("Thread %x ", pthread_self());
+	    //debug(PRINTF) printf("GC.Dtor()\n");
+	}
+
+	if (gcx)
+	{
+	    gcx.Dtor();
+	    cstdlib.free(gcx);
+	    gcx = null;
+	}
+    }
+
+
+    invariant()
+    {
+	if (gcx)
+        {
+	    gcx.thread_Invariant();
+        }
+    }
+
+
+    /**
+     *
+     */
+    void enable()
+    {
+        if (!thread_needLock())
+        {
+	    assert(gcx.disabled > 0);
+	    gcx.disabled--;
+        }
+        else synchronized (gcLock)
+	{
+	    assert(gcx.disabled > 0);
+	    gcx.disabled--;
+	}
+    }
+
+
+    /**
+     *
+     */
+    void disable()
+    {
+        if (!thread_needLock())
+        {
+	    gcx.disabled++;
+        }
+        else synchronized (gcLock)
+	{
+	    gcx.disabled++;
+	}
+    }
+
+
+    /**
+     *
+     */
+    void *malloc(size_t size)
+    {
+        if (!size)
+        {
+            return null;
+        }
+
+	if (!thread_needLock())
+	{
+	    return mallocNoSync(size);
+	}
+	else synchronized (gcLock)
+	{
+	    return mallocNoSync(size);
+	}
+    }
+
+
+    //
+    //
+    //
+    private void *mallocNoSync(size_t size)
+    {
+        assert(size != 0);
+
+        void *p = null;
+	Bins bin;
+
+	//debug(PRINTF) printf("GC::malloc(size = %d, gcx = %p)\n", size, gcx);
+	assert(gcx);
+	//debug(PRINTF) printf("gcx.self = %x, pthread_self() = %x\n", gcx.self, pthread_self());
+        size += SENTINEL_EXTRA;
+
+        // Compute size bin
+        // Cache previous binsize lookup - Dave Fladebo.
+        static size_t lastsize = -1;
+        static Bins lastbin;
+        if (size == lastsize)
+            bin = lastbin;
+        else
+        {
+            bin = gcx.findBin(size);
+            lastsize = size;
+            lastbin = bin;
+        }
+
+        if (bin < B_PAGE)
+        {
+            p = gcx.bucket[bin];
+            if (p == null)
+            {
+                if (!gcx.allocPage(bin) && !gcx.disabled)	// try to find a new page
+                {
+                    if (!thread_needLock())
+                    {
+                        /* Then we haven't locked it yet. Be sure
+                         * and lock for a collection, since a finalizer
+                         * may start a new thread.
+                         */
+                        synchronized (gcLock)
+                        {
+                            gcx.fullcollectshell();
+                        }
+                    }
+                    else if (!gcx.fullcollectshell())	// collect to find a new page
+                    {
+                        //gcx.newPool(1);
+                    }
+                }
+                if (!gcx.bucket[bin] && !gcx.allocPage(bin))
+                {   int result;
+
+                    gcx.newPool(1);		// allocate new pool to find a new page
+                    result = gcx.allocPage(bin);
+                    if (!result)
+                        return null;
+                }
+                p = gcx.bucket[bin];
+            }
+
+            // Return next item from free list
+            gcx.bucket[bin] = (cast(List *)p).next;
+            cstring.memset(p + size, 0, binsize[bin] - size);
+            //debug(PRINTF) printf("\tmalloc => %x\n", p);
+            debug (MEMSTOMP) cstring.memset(p, 0xF0, size);
+        }
+        else
+        {
+            p = gcx.bigAlloc(size);
+            if (!p)
+                return null;
+        }
+        size -= SENTINEL_EXTRA;
+        p = sentinel_add(p);
+        sentinel_init(p, size);
+        gcx.log_malloc(p, size);
+	return p;
+    }
+
+
+    /**
+     *
+     */
+    void *calloc(size_t size, size_t n)
+    {
+        size_t len = size * n;
+
+        if (!len)
+        {
+            return null;
+        }
+
+        if (!thread_needLock())
+        {
+            return callocNoSync(len);
+        }
+        else synchronized (gcLock)
+        {
+            return callocNoSync(len);
+        }
+    }
+
+
+    //
+    //
+    //
+    private void *callocNoSync(size_t size)
+    {
+        assert(size != 0);
+
+	void *p = mallocNoSync(size);
+	if (p)
+	{   //debug(PRINTF) printf("calloc: %x len %d\n", p, len);
+	    cstring.memset(p, 0, size);
+	}
+	return p;
+    }
+
+
+    /**
+     *
+     */
+    void *realloc(void *p, size_t size)
+    {
+        if (!thread_needLock())
+        {
+            return reallocNoSync(p, size);
+        }
+        else synchronized (gcLock)
+        {
+            return reallocNoSync(p, size);
+        }
+    }
+
+
+    //
+    //
+    //
+    private void *reallocNoSync(void *p, size_t size)
+    {
+	gcx.p_cache = null;
+	if (!size)
+	{   if (p)
+	    {   freeNoSync(p);
+		p = null;
+	    }
+	}
+	else if (!p)
+	{
+	    p = mallocNoSync(size);
+	}
+	else
+	{   void *p2;
+	    size_t psize;
+
+	    //debug(PRINTF) printf("GC::realloc(p = %x, size = %u)\n", p, size);
+	    version (SENTINEL)
+	    {
+		sentinel_Invariant(p);
+		psize = *sentinel_size(p);
+		if (psize != size)
+		{
+		    p2 = mallocNoSync(size);
+		    if (psize < size)
+			size = psize;
+		    //debug(PRINTF) printf("\tcopying %d bytes\n",size);
+		    cstring.memcpy(p2, p, size);
+		    p = p2;
+		}
+	    }
+	    else
+	    {
+		psize = gcx.findSize(p);	// find allocated size
+		if (psize >= PAGESIZE && size >= PAGESIZE)
+		{
+		    auto psz = psize / PAGESIZE;
+		    auto newsz = (size + PAGESIZE - 1) / PAGESIZE;
+		    if (newsz == psz)
+			return p;
+
+		    auto pool = gcx.findPool(p);
+		    auto pagenum = (p - pool.baseAddr) / PAGESIZE;
+
+		    if (newsz < psz)
+		    {	// Shrink in place
+			synchronized (gcLock)
+			{
+			    debug (MEMSTOMP) cstring.memset(p + size, 0xF2, psize - size);
+			    pool.freePages(pagenum + newsz, psz - newsz);
+			}
+			return p;
+		    }
+		    else if (pagenum + newsz <= pool.npages)
+		    {
+			// Attempt to expand in place
+			synchronized (gcLock)
+			{
+			    for (size_t i = pagenum + psz; 1;)
+			    {
+				if (i == pagenum + newsz)
+				{
+				    debug (MEMSTOMP) cstring.memset(p + psize, 0xF0, size - psize);
+				    cstring.memset(&pool.pagetable[pagenum + psz], B_PAGEPLUS, newsz - psz);
+				    return p;
+				}
+				if (i == pool.ncommitted)
+				{
+				    auto u = pool.extendPages(pagenum + newsz - pool.ncommitted);
+				    if (u == ~0u)
+					break;
+				    i = pagenum + newsz;
+				    continue;
+				}
+				if (pool.pagetable[i] != B_FREE)
+				    break;
+				i++;
+			    }
+			}
+		    }
+		}
+		if (psize < size ||		// if new size is bigger
+		    psize > size * 2)		// or less than half
+		{
+		    p2 = mallocNoSync(size);
+		    if (psize < size)
+			size = psize;
+		    //debug(PRINTF) printf("\tcopying %d bytes\n",size);
+		    cstring.memcpy(p2, p, size);
+		    p = p2;
+		}
+	    }
+	}
+	return p;
+    }
+
+
+    /**
+     * Attempt to in-place enlarge the memory block pointed to by p by at least
+     * minbytes beyond its current capacity, up to a maximum of maxsize.  This
+     * does not attempt to move the memory block (like realloc() does).
+     *
+     * Returns:
+     *	0 if could not extend p,
+     *	total size of entire memory block if successful.
+     */
+    size_t extend(void* p, size_t minsize, size_t maxsize)
+    {
+        if (!thread_needLock())
+        {
+            return extendNoSync(p, minsize, maxsize);
+        }
+        else synchronized (gcLock)
+        {
+            return extendNoSync(p, minsize, maxsize);
+        }
+    }
+
+
+    //
+    //
+    //
+    private size_t extendNoSync(void* p, size_t minsize, size_t maxsize)
+    in
+    {
+        assert( minsize <= maxsize );
+    }
+    body
+    {
+	//debug(PRINTF) printf("GC::extend(p = %x, minsize = %u, maxsize = %u)\n", p, minsize, maxsize);
+	version (SENTINEL)
+	{
+	    return 0;
+	}
+	auto psize = gcx.findSize(p);	// find allocated size
+	if (psize < PAGESIZE)
+	    return 0;			// cannot extend buckets
+
+	auto psz = psize / PAGESIZE;
+	auto minsz = (minsize + PAGESIZE - 1) / PAGESIZE;
+	auto maxsz = (maxsize + PAGESIZE - 1) / PAGESIZE;
+
+	auto pool = gcx.findPool(p);
+	auto pagenum = (p - pool.baseAddr) / PAGESIZE;
+
+        size_t sz;
+        for (sz = 0; sz < maxsz; sz++)
+        {
+            auto i = pagenum + psz + sz;
+            if (i == pool.ncommitted)
+                break;
+            if (pool.pagetable[i] != B_FREE)
+            {   if (sz < minsz)
+                    return 0;
+                break;
+            }
+        }
+        if (sz >= minsz)
+        {
+        }
+        else if (pagenum + psz + sz == pool.ncommitted)
+        {
+            auto u = pool.extendPages(minsz - sz);
+            if (u == ~0u)
+                return 0;
+            sz = minsz;
+        }
+        else
+            return 0;
+        debug (MEMSTOMP) cstring.memset(p + psize, 0xF0, (psz + sz) * PAGESIZE - psize);
+        cstring.memset(pool.pagetable + pagenum + psz, B_PAGEPLUS, sz);
+        gcx.p_cache = null;
+        gcx.size_cache = 0;
+        return (psz + sz) * PAGESIZE;
+    }
+
+
+    /**
+     *
+     */
+    void free(void *p)
+    {
+	if (!p)
+        {
+	    return;
+        }
+
+        if (!thread_needLock())
+        {
+            return freeNoSync(p);
+        }
+        else synchronized (gcLock)
+        {
+            return freeNoSync(p);
+        }
+    }
+
+
+    //
+    //
+    //
+    private void freeNoSync(void *p)
+    {
+        assert (p);
+
+	Pool *pool;
+	uint pagenum;
+	Bins bin;
+	uint biti;
+
+	// Find which page it is in
+	pool = gcx.findPool(p);
+	if (!pool)				// if not one of ours
+	    return;				// ignore
+	sentinel_Invariant(p);
+	p = sentinel_sub(p);
+	pagenum = (p - pool.baseAddr) / PAGESIZE;
+	biti = cast(uint)(p - pool.baseAddr) / 16;
+	pool.noscan.clear(biti);
+	if (pool.finals.nbits && pool.finals.testClear(biti))
+	    gcx.rt_finalize(sentinel_add(p), false);
+
+	gcx.p_cache = null;
+	bin = cast(Bins)pool.pagetable[pagenum];
+	if (bin == B_PAGE)		// if large alloc
+	{   int npages;
+	    uint n;
+
+	    // Free pages
+	    npages = 1;
+	    n = pagenum;
+	    while (++n < pool.ncommitted && pool.pagetable[n] == B_PAGEPLUS)
+		npages++;
+	    debug (MEMSTOMP) cstring.memset(p, 0xF2, npages * PAGESIZE);
+	    pool.freePages(pagenum, npages);
+	}
+	else
+	{   // Add to free list
+	    List *list = cast(List *)p;
+
+	    debug (MEMSTOMP) cstring.memset(p, 0xF2, binsize[bin]);
+
+	    list.next = gcx.bucket[bin];
+	    gcx.bucket[bin] = list;
+	}
+	gcx.log_free(sentinel_add(p));
+    }
+
+
+    /**
+     * Determine the allocated size of pointer p.  If p is an interior pointer
+     * or not a gc allocated pointer, return 0.
+     */
+    size_t capacity(void *p)
+    {
+        if (!p)
+        {
+            return 0;
+        }
+
+        if (!thread_needLock())
+        {
+            return sizeOfNoSync(p);
+        }
+        else synchronized (gcLock)
+        {
+            return sizeOfNoSync(p);
+        }
+    }
+
+
+    //
+    //
+    //
+    private size_t sizeOfNoSync(void *p)
+    {
+        assert (p);
+
+	version (SENTINEL)
+	{
+	    p = sentinel_sub(p);
+	    size_t size = gcx.findSize(p);
+
+	    // Check for interior pointer
+	    // This depends on:
+	    // 1) size is a power of 2 for less than PAGESIZE values
+	    // 2) base of memory pool is aligned on PAGESIZE boundary
+	    if (cast(size_t)p & (size - 1) & (PAGESIZE - 1))
+		size = 0;
+	    return size ? size - SENTINAL_EXTRA : 0;
+	}
+	else
+	{
+	    if (p !is null && p == gcx.p_cache)
+		return gcx.size_cache;
+
+	    size_t size = gcx.findSize(p);
+
+	    // Check for interior pointer
+	    // This depends on:
+	    // 1) size is a power of 2 for less than PAGESIZE values
+	    // 2) base of memory pool is aligned on PAGESIZE boundary
+	    if (cast(size_t)p & (size - 1) & (PAGESIZE - 1))
+		size = 0;
+	    else
+	    {
+		gcx.p_cache = p;
+		gcx.size_cache = size;
+	    }
+
+	    return size;
+	}
+    }
+
+
+    /**
+     * Verify that pointer p:
+     *	1) belongs to this memory pool
+     *	2) points to the start of an allocated piece of memory
+     *	3) is not on a free list
+     */
+    void check(void *p)
+    {
+        if (!p)
+        {
+            return;
+        }
+
+        if (!thread_needLock())
+        {
+            checkNoSync(p);
+        }
+        else synchronized (gcLock)
+        {
+            checkNoSync(p);
+        }
+    }
+
+    //
+    //
+    //
+    private void checkNoSync(void *p)
+    {
+        assert(p);
+
+        sentinel_Invariant(p);
+        debug (PTRCHECK)
+        {
+            Pool* pool;
+            uint pagenum;
+            Bins bin;
+            size_t size;
+
+            p = sentinel_sub(p);
+            pool = gcx.findPool(p);
+            assert(pool);
+            pagenum = (p - pool.baseAddr) / PAGESIZE;
+            bin = cast(Bins)pool.pagetable[pagenum];
+            assert(bin <= B_PAGE);
+            size = binsize[bin];
+            assert((cast(size_t)p & (size - 1)) == 0);
+
+            debug (PTRCHECK2)
+            {
+                if (bin < B_PAGE)
+                {
+                    // Check that p is not on a free list
+                    List *list;
+
+                    for (list = gcx.bucket[bin]; list; list = list.next)
+                    {
+                        assert(cast(void *)list != p);
+                    }
+                }
+            }
+        }
+    }
+
+
+    //
+    //
+    //
+    private void setStackBottom(void *p)
+    {
+	version (STACKGROWSDOWN)
+	{
+	    //p = (void *)((uint *)p + 4);
+	    if (p > gcx.stackBottom)
+	    {
+		//debug(PRINTF) printf("setStackBottom(%x)\n", p);
+		gcx.stackBottom = p;
+	    }
+	}
+	else
+	{
+	    //p = (void *)((uint *)p - 4);
+	    if (p < gcx.stackBottom)
+	    {
+		//debug(PRINTF) printf("setStackBottom(%x)\n", p);
+		gcx.stackBottom = cast(char *)p;
+	    }
+	}
+    }
+
+
+    static void scanStaticData(gc_t g)
+    {
+	void *pbot;
+	void *ptop;
+	size_t nbytes;
+
+	//debug(PRINTF) printf("+GC.scanStaticData()\n");
+	os_query_staticdataseg(&pbot, &nbytes);
+	ptop = pbot + nbytes;
+	version (GNU) {
+	    if (pbot) {
+		g.addRange(pbot, ptop);
+	    }
+	} else {
+	    g.addRange(pbot, ptop);
+	}
+	//debug(PRINTF) printf("-GC.scanStaticData()\n");
+    }
+
+    static void unscanStaticData(gc_t g)
+    {
+	void *pbot;
+	size_t nbytes;
+
+	os_query_staticdataseg(&pbot, &nbytes);
+	version (GNU) {
+	    if (pbot) {
+		g.removeRange(pbot);
+	    }
+	} else {
+	    g.removeRange(pbot);
+	}
+    }
+
+
+    /**
+     * add p to list of roots
+     */
+    void addRoot(void *p)
+    {
+        if (!p)
+        {
+            return;
+        }
+
+        if (!thread_needLock())
+        {
+	    gcx.addRoot(p);
+        }
+        else synchronized (gcLock)
+	{
+	    gcx.addRoot(p);
+	}
+    }
+
+
+    /**
+     * remove p from list of roots
+     */
+    void removeRoot(void *p)
+    {
+        if (!p)
+        {
+            return;
+        }
+
+        if (!thread_needLock())
+        {
+	    gcx.removeRoot(p);
+        }
+        else synchronized (gcLock)
+	{
+	    gcx.removeRoot(p);
+	}
+    }
+
+
+    /**
+     * add range to scan for roots
+     */
+    void addRange(void *pbot, void *ptop)
+    {
+        if (!pbot || !ptop)
+        {
+            return;
+        }
+
+	//debug(PRINTF) printf("+GC.addRange(pbot = x%x, ptop = x%x)\n", pbot, ptop);
+        if (!thread_needLock())
+        {
+	    gcx.addRange(pbot, ptop);
+        }
+        else synchronized (gcLock)
+	{
+	    gcx.addRange(pbot, ptop);
+	}
+	//debug(PRINTF) printf("-GC.addRange()\n");
+    }
+
+
+    /**
+     * remove range
+     */
+    void removeRange(void *p)
+    {
+        if (!p)
+        {
+            return;
+        }
+
+        if (!thread_needLock())
+        {
+	    gcx.removeRange(p);
+        }
+        else synchronized (gcLock)
+	{
+	    gcx.removeRange(p);
+	}
+    }
+
+
+    /**
+     * do full garbage collection
+     */
+    void fullCollect()
+    {
+	debug(PRINTF) printf("GC.fullCollect()\n");
+
+        if (!thread_needLock())
+        {
+	    gcx.fullcollectshell();
+        }
+        else synchronized (gcLock)
+	{
+	    gcx.fullcollectshell();
+	}
+
+	version (none)
+	{
+	    GCStats stats;
+
+	    getStats(stats);
+	    debug(PRINTF) printf("poolsize = %x, usedsize = %x, freelistsize = %x\n",
+		    stats.poolsize, stats.usedsize, stats.freelistsize);
+	}
+
+	gcx.log_collect();
+    }
+
+
+    /**
+     * do full garbage collection ignoring roots
+     */
+    void fullCollectNoStack()
+    {
+        if (!thread_needLock())
+        {
+            gcx.noStack++;
+            gcx.fullcollectshell();
+            gcx.noStack--;
+        }
+        else synchronized (gcLock)
+        {
+            gcx.noStack++;
+            gcx.fullcollectshell();
+            gcx.noStack--;
+        }
+    }
+
+
+    /**
+     * do generational garbage collection
+     */
+    void genCollect()
+    {
+	synchronized (gcLock)
+	{
+	    gcx.fullcollectshell();
+	}
+    }
+
+    void minimize()	// minimize physical memory usage
+    {
+	// Not implemented, ignore
+    }
+
+    void setFinalizer(void *p, GC_FINALIZER pFn)
+    {
+	synchronized (gcLock)
+	{
+	    gcx.finalizer = pFn;
+	    gcx.doFinalize(p);
+	}
+    }
+
+
+    void hasPointers(void *p)
+    {
+	synchronized (gcLock)
+	{
+	    gcx.HasPointers(p);
+	}
+    }
+
+
+    void hasNoPointers(void *p)
+    {
+	if (!gcx.conservative)
+	{   synchronized (gcLock)
+	    {
+		gcx.HasNoPointers(p);
+	    }
+	}
+    }
+
+
+    void setV1_0()
+    {
+	gcx.conservative = 1;
+    }
+
+    /**
+     * Retrieve statistics about garbage collection.
+     * Useful for debugging and tuning.
+     */
+    void getStats(out GCStats stats)
+    {
+        if (!thread_needLock())
+        {
+            getStatsNoSync(stats);
+        }
+        else synchronized (gcLock)
+        {
+            getStatsNoSync(stats);
+        }
+    }
+
+    //
+    //
+    //
+    private void getStatsNoSync(out GCStats stats)
+    {
+	size_t psize = 0;
+	size_t usize = 0;
+	size_t flsize = 0;
+
+	size_t n;
+	size_t bsize = 0;
+
+	//debug(PRINTF) printf("getStats()\n");
+	cstring.memset(&stats, 0, GCStats.sizeof);
+
+        for (n = 0; n < gcx.npools; n++)
+        {   Pool *pool = gcx.pooltable[n];
+
+            psize += pool.ncommitted * PAGESIZE;
+            for (uint j = 0; j < pool.ncommitted; j++)
+            {
+                Bins bin = cast(Bins)pool.pagetable[j];
+                if (bin == B_FREE)
+                    stats.freeblocks++;
+                else if (bin == B_PAGE)
+                    stats.pageblocks++;
+                else if (bin < B_PAGE)
+                    bsize += PAGESIZE;
+            }
+        }
+
+        for (n = 0; n < B_PAGE; n++)
+        {
+            //debug(PRINTF) printf("bin %d\n", n);
+            for (List *list = gcx.bucket[n]; list; list = list.next)
+            {
+                //debug(PRINTF) printf("\tlist %x\n", list);
+                flsize += binsize[n];
+            }
+        }
+
+	usize = bsize - flsize;
+
+	stats.poolsize = psize;
+	stats.usedsize = bsize - flsize;
+	stats.freelistsize = flsize;
+    }
+}
+
+
+/* ============================ Gcx =============================== */
+
+enum
+{   PAGESIZE =	  4096,
+    COMMITSIZE = (4096*16),
+    POOLSIZE =   (4096*256),
+}
+
+
+enum
+{
+    B_16,
+    B_32,
+    B_64,
+    B_128,
+    B_256,
+    B_512,
+    B_1024,
+    B_2048,
+    B_PAGE,		// start of large alloc
+    B_PAGEPLUS,		// continuation of large alloc
+    B_FREE,		// free page
+    B_UNCOMMITTED,	// memory not committed for this page
+    B_MAX
+}
+
+
+alias ubyte Bins;
+
+
+struct List
+{
+    List *next;
+}
+
+
+struct Range
+{
+    void *pbot;
+    void *ptop;
+}
+
+
+const uint binsize[B_MAX] = [ 16,32,64,128,256,512,1024,2048,4096 ];
+const uint notbinsize[B_MAX] = [ ~(16u-1),~(32u-1),~(64u-1),~(128u-1),~(256u-1),
+				~(512u-1),~(1024u-1),~(2048u-1),~(4096u-1) ];
+
+/* ============================ Gcx =============================== */
+
+
+struct Gcx
+{
+    debug (THREADINVARIANT)
+    {
+	pthread_t self;
+	void thread_Invariant()
+	{
+	    if (self != pthread_self())
+		printf("thread_Invariant(): gcx = %x, self = %x, pthread_self() = %x\n", this, self, pthread_self());
+	    assert(self == pthread_self());
+	}
+    }
+    else
+    {
+	void thread_Invariant() { }
+    }
+
+    void *p_cache;
+    size_t size_cache;
+
+    size_t nroots;
+    size_t rootdim;
+    void **roots;
+
+    size_t nranges;
+    size_t rangedim;
+    Range *ranges;
+
+    uint conservative;	// !=0 means conservative behavior
+    uint noStack;	// !=0 means don't scan stack
+    uint log;		// turn on logging
+    uint anychanges;
+    void *stackBottom;
+    uint inited;
+    int disabled;	// turn off collections if >0
+
+    byte *minAddr;	// min(baseAddr)
+    byte *maxAddr;	// max(topAddr)
+
+    uint npools;
+    Pool **pooltable;
+
+    List *bucket[B_MAX];	// free list for each size
+
+    GC_FINALIZER finalizer;	// finalizer function (one per GC)
+
+    private void rt_finalize( void* p, bool dummy )
+    {
+        if (finalizer)
+            (*finalizer)(p, dummy);
+    }
+
+
+    void initialize()
+    {   int dummy;
+
+	(cast(byte *)this)[0 .. Gcx.sizeof] = 0;
+	stackBottom = cast(char *)&dummy;
+	log_init();
+	debug (THREADINVARIANT)
+	    self = pthread_self();
+	//printf("gcx = %p, self = %x\n", this, self);
+	inited = 1;
     }
 
 
     void Dtor()
     {
-    debug(PRINTF) printf("GC Dtor()\n");
-    }
-
-    invariant
-    {
-    debug(PRINTF) printf("GC invariant()\n");
+	inited = 0;
+
+	for (uint i = 0; i < npools; i++)
+	{   Pool *pool = pooltable[i];
+
+	    pool.Dtor();
+	    cstdlib.free(pool);
+	}
+	if (pooltable)
+	    cstdlib.free(pooltable);
+
+	if (roots)
+	    cstdlib.free(roots);
+
+	if (ranges)
+	    cstdlib.free(ranges);
     }
 
-    void *malloc(size_t size)
+
+    void Invariant() { }
+
+
+    invariant()
     {
-    debug(PRINTF) printf("GC malloc()\n");
-    return malloc(size);
+	if (inited)
+	{
+	//printf("Gcx.invariant(): this = %p\n", this);
+	    uint i;
+
+	    // Assure we're called on the right thread
+	    debug (THREADINVARIANT) assert(self == pthread_self());
+
+	    for (i = 0; i < npools; i++)
+	    {   Pool *pool = pooltable[i];
+
+		pool.Invariant();
+		if (i == 0)
+		{
+		    assert(minAddr == pool.baseAddr);
+		}
+		if (i + 1 < npools)
+		{
+		    assert(pool.opCmp(pooltable[i + 1]) < 0);
+		}
+		else if (i + 1 == npools)
+		{
+		    assert(maxAddr == pool.topAddr);
+		}
+	    }
+
+	    if (roots)
+	    {
+		assert(rootdim != 0);
+		assert(nroots <= rootdim);
+	    }
+
+	    if (ranges)
+	    {
+		assert(rangedim != 0);
+		assert(nranges <= rangedim);
+
+		for (i = 0; i < nranges; i++)
+		{
+		    assert(ranges[i].pbot);
+		    assert(ranges[i].ptop);
+		    assert(ranges[i].pbot <= ranges[i].ptop);
+		}
+	    }
+
+	    for (i = 0; i < B_PAGE; i++)
+	    {
+		for (List *list = bucket[i]; list; list = list.next)
+		{
+		}
+	    }
+	}
     }
 
-    void *mallocNoSync(size_t size)
+
+    /**
+     *
+     */
+
+    void addRoot(void *p)
     {
-    debug(PRINTF) printf("GC mallocNoSync()\n");
-    return malloc(size);
+	if (nroots == rootdim)
+	{
+	    size_t newdim = rootdim * 2 + 16;
+	    void** newroots;
+
+	    newroots = cast(void **)cstdlib.malloc(newdim * newroots[0].sizeof);
+	    if (!newroots)
+		onOutOfMemoryError();
+	    if (roots)
+	    {   cstring.memcpy(newroots, roots, nroots * newroots[0].sizeof);
+		cstdlib.free(roots);
+	    }
+	    roots = newroots;
+	    rootdim = newdim;
+	}
+	roots[nroots] = p;
+	nroots++;
     }
 
 
-    void *calloc(size_t size, size_t n)
+    /**
+     *
+     */
+    void removeRoot(void *p)
+    {
+	for (size_t i = nroots; i--;)
+	{
+	    if (roots[i] == p)
+	    {
+		nroots--;
+		cstring.memmove(roots + i, roots + i + 1, (nroots - i) * roots[0].sizeof);
+		return;
+	    }
+	}
+	assert(0);
+    }
+
+
+    /**
+     *
+     */
+    void addRange(void *pbot, void *ptop)
     {
-    debug(PRINTF) printf("GC calloc()\n");
-    return calloc(n, size);
+	debug(THREADINVARIANT) { debug(PRINTF) printf("Thread %x ", pthread_self()); }
+	debug(PRINTF) printf("%x.Gcx::addRange(%x, %x), nranges = %d\n", this, pbot, ptop, nranges);
+	if (nranges == rangedim)
+	{
+	    size_t newdim = rangedim * 2 + 16;
+	    Range *newranges;
+
+	    newranges = cast(Range *)cstdlib.malloc(newdim * newranges[0].sizeof);
+	    if (!newranges)
+		onOutOfMemoryError();
+	    if (ranges)
+	    {   cstring.memcpy(newranges, ranges, nranges * newranges[0].sizeof);
+		cstdlib.free(ranges);
+	    }
+	    ranges = newranges;
+	    rangedim = newdim;
+	}
+	ranges[nranges].pbot = pbot;
+	ranges[nranges].ptop = ptop;
+	nranges++;
     }
 
 
-    void *realloc(void *p, size_t size)
+    /**
+     *
+     */
+    void removeRange(void *pbot)
     {
-    debug(PRINTF) printf("GC realloc()\n");
-    return realloc(p, size);
+	debug(THREADINVARIANT) { debug(PRINTF) printf("Thread %x ", pthread_self()); }
+	debug(PRINTF) printf("%x.Gcx.removeRange(%x), nranges = %d\n", this, pbot, nranges);
+	for (size_t i = nranges; i--;)
+	{
+	    if (ranges[i].pbot == pbot)
+	    {
+		nranges--;
+		cstring.memmove(ranges + i, ranges + i + 1, (nranges - i) * ranges[0].sizeof);
+		return;
+	    }
+	}
+	debug(PRINTF) printf("Wrong thread\n");
+
+	// This is a fatal error, but ignore it.
+	// The problem is that we can get a Close() call on a thread
+	// other than the one the range was allocated on.
+	//assert(zero);
     }
 
 
-    void free(void *p)
+    /**
+     * Find Pool that pointer is in.
+     * Return null if not in a Pool.
+     * Assume pooltable[] is sorted.
+     */
+    Pool *findPool(void *p)
     {
-    debug(PRINTF) printf("GC free()\n");
-    stdc.free(p);
+	if (p >= minAddr && p < maxAddr)
+	{
+	    if (npools == 1)
+	    {
+		return pooltable[0];
+	    }
+
+	    for (uint i = 0; i < npools; i++)
+	    {   Pool *pool;
+
+		pool = pooltable[i];
+		if (p < pool.topAddr)
+		{   if (pool.baseAddr <= p)
+			return pool;
+		    break;
+		}
+	    }
+	}
+	return null;
+    }
+
+
+    /**
+     * Find size of pointer p.
+     * Returns 0 if not a gc'd pointer
+     */
+    size_t findSize(void *p)
+    {
+	Pool *pool;
+	size_t size = 0;
+
+	pool = findPool(p);
+	if (pool)
+	{
+	    uint pagenum;
+	    Bins bin;
+
+	    pagenum = (cast(uint)(p - pool.baseAddr)) / PAGESIZE;
+	    bin = cast(Bins)pool.pagetable[pagenum];
+	    size = binsize[bin];
+	    if (bin == B_PAGE)
+	    {   uint npages = pool.ncommitted;
+		ubyte* pt;
+		uint i;
+
+		pt = &pool.pagetable[0];
+		for (i = pagenum + 1; i < npages; i++)
+		{
+		    if (pt[i] != B_PAGEPLUS)
+			break;
+		}
+		size = (i - pagenum) * PAGESIZE;
+	    }
+	}
+	return size;
     }
 
-    size_t capacity(void *p)
-    {
-    debug(PRINTF) printf("GC capacity()\n");
-    return 0;
+
+    /**
+     * Compute bin for size.
+     */
+    static Bins findBin(size_t size)
+    {   Bins bin;
+
+	if (size <= 256)
+	{
+	    if (size <= 64)
+	    {
+		if (size <= 16)
+		    bin = B_16;
+		else if (size <= 32)
+		    bin = B_32;
+		else
+		    bin = B_64;
+	    }
+	    else
+	    {
+		if (size <= 128)
+		    bin = B_128;
+		else
+		    bin = B_256;
+	    }
+	}
+	else
+	{
+	    if (size <= 1024)
+	    {
+		if (size <= 512)
+		    bin = B_512;
+		else
+		    bin = B_1024;
+	    }
+	    else
+	    {
+		if (size <= 2048)
+		    bin = B_2048;
+		else
+		    bin = B_PAGE;
+	    }
+	}
+	return bin;
     }
 
-    void check(void *p)
+
+    /**
+     * Allocate a chunk of memory that is larger than a page.
+     * Return null if out of memory.
+     */
+    void *bigAlloc(size_t size)
     {
-    debug(PRINTF) printf("GC check()\n");
+	Pool *pool;
+	uint npages;
+	uint n;
+	uint pn;
+	uint freedpages;
+	void *p;
+	int state;
+
+	npages = (size + PAGESIZE - 1) / PAGESIZE;
+
+	for (state = 0; ; )
+	{
+	    // This code could use some refinement when repeatedly
+	    // allocating very large arrays.
+
+	    for (n = 0; n < npools; n++)
+	    {
+		pool = pooltable[n];
+		pn = pool.allocPages(npages);
+		if (pn != ~0u)
+		    goto L1;
+	    }
+
+	    // Failed
+	    switch (state)
+	    {
+		case 0:
+		    if (disabled)
+		    {	state = 1;
+			continue;
+		    }
+		    // Try collecting
+		    freedpages = fullcollectshell();
+		    if (freedpages >= npools * ((POOLSIZE / PAGESIZE) / 4))
+		    {   state = 1;
+			continue;
+		    }
+		    // Allocate new pool
+		    pool = newPool(npages);
+		    if (!pool)
+		    {   state = 2;
+			continue;
+		    }
+		    pn = pool.allocPages(npages);
+		    assert(pn != ~0u);
+		    goto L1;
+
+		case 1:
+		    // Allocate new pool
+		    pool = newPool(npages);
+		    if (!pool)
+			goto Lnomemory;
+		    pn = pool.allocPages(npages);
+		    assert(pn != ~0u);
+		    goto L1;
+
+		case 2:
+		    goto Lnomemory;
+	    }
+	}
+
+      L1:
+	pool.pagetable[pn] = B_PAGE;
+	if (npages > 1)
+	    cstring.memset(&pool.pagetable[pn + 1], B_PAGEPLUS, npages - 1);
+	p = pool.baseAddr + pn * PAGESIZE;
+	cstring.memset(cast(char *)p + size, 0, npages * PAGESIZE - size);
+	debug (MEMSTOMP) cstring.memset(p, 0xF1, size);
+	//debug(PRINTF) printf("\tp = %x\n", p);
+	return p;
+
+      Lnomemory:
+	onOutOfMemoryError();
+	return null;
     }
 
 
-    void setStackBottom(void *p)
-    {
-    debug(PRINTF) printf("GC setStackBottom()\n");
-    }
-
-    static void scanStaticData(gc_t g)
+    /**
+     * Allocate a new pool with at least npages in it.
+     * Sort it into pooltable[].
+     * Return null if failed.
+     */
+    Pool *newPool(uint npages)
     {
-    void *pbot;
-    void *ptop;
-    uint nbytes;
-
-    debug(PRINTF) printf("GC scanStaticData()\n");
-    //debug(PRINTF) printf("+GC.scanStaticData()\n");
-    os_query_staticdataseg(&pbot, &nbytes);
-    ptop = pbot + nbytes;
-    g.addRange(pbot, ptop);
-    //debug(PRINTF) printf("-GC.scanStaticData()\n");
+	Pool *pool;
+	Pool **newpooltable;
+	uint newnpools;
+	uint i;
+
+	//debug(PRINTF) printf("************Gcx::newPool(npages = %d)****************\n", npages);
+
+	// Round up to COMMITSIZE pages
+	npages = (npages + (COMMITSIZE/PAGESIZE) - 1) & ~(COMMITSIZE/PAGESIZE - 1);
+
+	// Minimum of POOLSIZE
+	if (npages < POOLSIZE/PAGESIZE)
+	    npages = POOLSIZE/PAGESIZE;
+	else if (npages > POOLSIZE/PAGESIZE)
+	{   // Give us 150% of requested size, so there's room to extend
+	    auto n = npages + (npages >> 1);
+	    if (n < size_t.max/PAGESIZE)
+		npages = n;
+	}
+
+	// Allocate successively larger pools up to 8 megs
+	if (npools)
+	{   uint n;
+
+	    n = npools;
+	    if (n > 8)
+		n = 8;			// cap pool size at 8 megs
+	    n *= (POOLSIZE / PAGESIZE);
+	    if (npages < n)
+		npages = n;
+	}
+
+	pool = cast(Pool *)cstdlib.calloc(1, Pool.sizeof);
+	if (pool)
+	{
+	    pool.initialize(npages);
+	    if (!pool.baseAddr)
+		goto Lerr;
+
+	    newnpools = npools + 1;
+	    newpooltable = cast(Pool **)cstdlib.realloc(pooltable, newnpools * (Pool *).sizeof);
+	    if (!newpooltable)
+		goto Lerr;
+
+	    // Sort pool into newpooltable[]
+	    for (i = 0; i < npools; i++)
+	    {
+		if (pool.opCmp(newpooltable[i]) < 0)
+		     break;
+	    }
+	    cstring.memmove(newpooltable + i + 1, newpooltable + i, (npools - i) * (Pool *).sizeof);
+	    newpooltable[i] = pool;
+
+	    pooltable = newpooltable;
+	    npools = newnpools;
+
+	    minAddr = pooltable[0].baseAddr;
+	    maxAddr = pooltable[npools - 1].topAddr;
+	}
+	return pool;
+
+      Lerr:
+	pool.Dtor();
+	cstdlib.free(pool);
+	return null;
     }
 
-    static void unscanStaticData(gc_t g)
+
+    /**
+     * Allocate a page of bin's.
+     * Returns:
+     *	0	failed
+     */
+    int allocPage(Bins bin)
+    {
+	Pool *pool;
+	uint n;
+	uint pn;
+	byte *p;
+	byte *ptop;
+
+	//debug(PRINTF) printf("Gcx::allocPage(bin = %d)\n", bin);
+	for (n = 0; n < npools; n++)
+	{
+	    pool = pooltable[n];
+	    pn = pool.allocPages(1);
+	    if (pn != ~0u)
+		goto L1;
+	}
+	return 0;		// failed
+
+      L1:
+	pool.pagetable[pn] = cast(ubyte)bin;
+
+	// Convert page to free list
+	size_t size = binsize[bin];
+	List **b = &bucket[bin];
+
+	p = pool.baseAddr + pn * PAGESIZE;
+	ptop = p + PAGESIZE;
+	for (; p < ptop; p += size)
+	{
+	    (cast(List *)p).next = *b;
+	    *b = cast(List *)p;
+	}
+	return 1;
+    }
+
+
+    /**
+     * Search a range of memory values and mark any pointers into the GC pool.
+     */
+    void mark(void *pbot, void *ptop)
     {
-    void *pbot;
-    uint nbytes;
-
-    debug(PRINTF) printf("GC unscanStaticData()\n");
-    os_query_staticdataseg(&pbot, &nbytes);
-    g.removeRange(pbot);
+	void **p1 = cast(void **)pbot;
+	void **p2 = cast(void **)ptop;
+	uint changes = 0;
+
+        //printf("marking range: %p -> %p\n", pbot, ptop);
+	for (; p1 < p2; p1++)
+	{
+	    Pool *pool;
+	    byte *p = cast(byte *)(*p1);
+
+	    //if (log) debug(PRINTF) printf("\tmark %x\n", p);
+	    if (p >= minAddr)
+	    {
+		pool = findPool(p);
+		if (pool)
+		{
+		    size_t offset = cast(size_t)(p - pool.baseAddr);
+		    uint biti;
+		    uint pn = offset / PAGESIZE;
+		    Bins bin = cast(Bins)pool.pagetable[pn];
+
+		    //debug(PRINTF) printf("\t\tfound pool %x, base=%x, pn = %d, bin = %d, biti = x%x\n", pool, pool.baseAddr, pn, bin, biti);
+
+		    // Adjust bit to be at start of allocated memory block
+		    if (bin <= B_PAGE)
+		    {
+			biti = (offset & notbinsize[bin]) >> 4;
+			//debug(PRINTF) printf("\t\tbiti = x%x\n", biti);
+		    }
+		    else if (bin == B_PAGEPLUS)
+		    {
+			do
+			{   --pn;
+			} while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS);
+			biti = pn * (PAGESIZE / 16);
+		    }
+		    else
+		    {
+			// Don't mark bits in B_FREE or B_UNCOMMITTED pages
+			continue;
+		    }
+
+		    //debug(PRINTF) printf("\t\tmark(x%x) = %d\n", biti, pool.mark.test(biti));
+		    if (!pool.mark.test(biti))
+		    {
+			//if (log) debug(PRINTF) printf("\t\tmarking %x\n", p);
+			pool.mark.set(biti);
+			if (!pool.noscan.test(biti))
+			{
+                            pool.scan.set(biti);
+			    changes = 1;
+			}
+			log_parent(sentinel_add(pool.baseAddr + biti * 16), sentinel_add(pbot));
+		    }
+		}
+	    }
+	}
+	anychanges |= changes;
     }
 
 
-    void addRoot(void *p)   // add p to list of roots
-    {
-    debug(PRINTF) printf("GC addRoot()\n");
-    }
-
-    void removeRoot(void *p)    // remove p from list of roots
+    /**
+     * Return number of full pages free'd.
+     */
+    size_t fullcollectshell()
     {
-    debug(PRINTF) printf("GC removeRoot()\n");
-    }
-
-    void addRange(void *pbot, void *ptop)   // add range to scan for roots
-    {
-    debug(PRINTF) printf("GC addRange()\n");
-    }
-
-    void removeRange(void *pbot)        // remove range
-    {
-    debug(PRINTF) printf("GC removeRange()\n");
+	// The purpose of the 'shell' is to ensure all the registers
+	// get put on the stack so they'll be scanned
+	void *sp;
+	size_t result;
+	version (GNU)
+	{
+	    __builtin_unwind_init();
+	    sp = & sp;
+	}
+	else
+	{
+	    /*asm
+	    {
+		pushad		;
+		mov	sp[EBP],ESP	;
+	    }*/
+	}
+	result = fullcollect(sp);
+	version (GNU)
+	{
+	    // nothing to do
+	}
+	else
+	{
+	    /*asm
+	    {
+		popad		;
+	    }*/
+	}
+	return result;
     }
 
-    void fullCollect()      // do full garbage collection
-    {
-    debug(PRINTF) printf("GC fullCollect()\n");
-    }
-
-    void fullCollectNoStack()       // do full garbage collection
+
+    /**
+     *
+     */
+    size_t fullcollect(void *stackTop)
     {
-    debug(PRINTF) printf("GC fullCollectNoStack()\n");
-    }
-
-    void genCollect()   // do generational garbage collection
+	uint n;
+	Pool *pool;
+
+	debug(COLLECT_PRINTF) printf("Gcx.fullcollect()\n");
+
+	Thread.pauseAll();
+
+	p_cache = null;
+	size_cache = 0;
+
+	anychanges = 0;
+	for (n = 0; n < npools; n++)
+	{
+	    pool = pooltable[n];
+	    pool.mark.zero();
+	    pool.scan.zero();
+	    pool.freebits.zero();
+	}
+
+	// Mark each free entry, so it doesn't get scanned
+	for (n = 0; n < B_PAGE; n++)
+	{
+	    for (List *list = bucket[n]; list; list = list.next)
+	    {
+		pool = findPool(list);
+		assert(pool);
+		pool.freebits.set(cast(uint)(cast(byte *)list - pool.baseAddr) / 16);
+	    }
+	}
+
+	for (n = 0; n < npools; n++)
+	{
+	    pool = pooltable[n];
+	    pool.mark.copy(&pool.freebits);
+	}
+
+	version (MULTI_THREADED)
+	{
+	    // Scan stacks and registers for each paused thread
+	    Thread[] threads = Thread.getAll();
+	    //thread_id id = cast(thread_id) GetCurrentThread();
+	    for (n = 0; n < threads.length; n++)
+	    {   Thread t = threads[n];
+
+		if (t && t.getState() == Thread.TS.RUNNING)
+		{
+		    if (noStack && threads.length == 1)
+			break;
+
+		    version (Win32)
+		    {
+			CONTEXT context;
+
+			context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
+			if (!GetThreadContext(t.hdl, &context))
+			{
+			    assert(0);
+			}
+			debug (PRINTF) printf("mt scan stack bot = %x, top = %x\n", context.Esp, t.stackBottom);
+			mark(cast(void *)context.Esp, t.stackBottom);
+			mark(&context.Edi, &context.Eip);
+		    }
+		    else version (GNU)
+		    {
+			if (t.isSelf())
+			    t.stackTop = Thread.getESP();
+
+			//%%fry printf("top=%08x bot=%08x ext=%08x\n", t.stackTop, t.stackBottom, Thread.getESP());//%%try
+			version (STACKGROWSDOWN)
+			    mark(t.stackTop, t.stackBottom);
+			else
+			    mark(t.stackBottom, t.stackTop);
+		    }
+		    else version (linux)
+		    {
+			// The registers are already stored in the stack
+			//printf("Thread: ESP = x%x, stackBottom = x%x, isSelf = %d\n", Thread.getESP(), t.stackBottom, t.isSelf());
+			if (t.isSelf())
+			    t.stackTop = Thread.getESP();
+
+			version (STACKGROWSDOWN)
+			    mark(t.stackTop, t.stackBottom);
+			else
+			    mark(t.stackBottom, t.stackTop);
+		    }
+		}
+	    }
+	}
+	else
+	{
+	    if (!noStack)
+	    {
+		// Scan stack for main thread
+		debug(PRINTF) printf(" scan stack bot = %x, top = %x\n", stackTop, stackBottom);
+		version (STACKGROWSDOWN)
+		    mark(stackTop, stackBottom);
+		else
+		    mark(stackBottom, stackTop);
+	    }
+	}
+
+	// Scan roots[]
+	debug(COLLECT_PRINTF) printf("scan roots[]\n");
+	mark(roots, roots + nroots);
+
+	// Scan ranges[]
+	debug(COLLECT_PRINTF) printf("scan ranges[]\n");
+	//log++;
+	for (n = 0; n < nranges; n++)
+	{
+	    debug(COLLECT_PRINTF) printf("\t%x .. %x\n", ranges[n].pbot, ranges[n].ptop);
+	    mark(ranges[n].pbot, ranges[n].ptop);
+	}
+	//log--;
+
+	debug(COLLECT_PRINTF) printf("\tscan heap\n");
+	while (anychanges)
+	{
+	    anychanges = 0;
+	    for (n = 0; n < npools; n++)
+	    {
+		uint *bbase;
+		uint *b;
+		uint *btop;
+
+		pool = pooltable[n];
+
+		bbase = pool.scan.base();
+		btop = bbase + pool.scan.nwords;
+		for (b = bbase; b < btop;)
+		{   Bins bin;
+		    uint pn;
+		    uint u;
+		    uint bitm;
+		    byte *o;
+
+		    bitm = *b;
+		    if (!bitm)
+		    {   b++;
+			continue;
+		    }
+		    *b = 0;
+
+		    o = pool.baseAddr + (b - bbase) * 32 * 16;
+		    /*		    version (BigEndian)
+			bitm = bswap(bitm);
+		    */
+		    if (!(bitm & 0xFFFF))
+		    {
+			bitm >>= 16;
+			o += 16 * 16;
+		    }
+		    for (; bitm; o += 16, bitm >>= 1)
+		    {
+			if (!(bitm & 1))
+			    continue;
+
+			pn = (o - pool.baseAddr) / PAGESIZE;
+			bin = cast(Bins)pool.pagetable[pn];
+			if (bin < B_PAGE)
+			{
+			    mark(o, o + binsize[bin]);
+			}
+			else if (bin == B_PAGE || bin == B_PAGEPLUS)
+			{
+			    if (bin == B_PAGEPLUS)
+			    {
+				while (pool.pagetable[pn - 1] != B_PAGE)
+				    pn--;
+			    }
+			    u = 1;
+			    while (pn + u < pool.ncommitted && pool.pagetable[pn + u] == B_PAGEPLUS)
+				u++;
+			    mark(o, o + u * PAGESIZE);
+			}
+		    }
+		}
+	    }
+	}
+
+	// Free up everything not marked
+	debug(COLLECT_PRINTF) printf("\tfree'ing\n");
+	size_t freedpages = 0;
+	size_t freed = 0;
+	for (n = 0; n < npools; n++)
+	{   uint pn;
+	    uint ncommitted;
+	    uint *bbase;
+
+	    pool = pooltable[n];
+	    bbase = pool.mark.base();
+	    ncommitted = pool.ncommitted;
+	    for (pn = 0; pn < ncommitted; pn++, bbase += PAGESIZE / (32 * 16))
+	    {
+		Bins bin = cast(Bins)pool.pagetable[pn];
+
+		if (bin < B_PAGE)
+		{   byte *p;
+		    byte *ptop;
+		    uint biti;
+		    uint bitstride;
+		    uint size = binsize[bin];
+
+		    p = pool.baseAddr + pn * PAGESIZE;
+		    ptop = p + PAGESIZE;
+		    biti = pn * (PAGESIZE/16);
+		    bitstride = size / 16;
+
+    version(none) // BUG: doesn't work because freebits() must also be cleared
     {
-    debug(PRINTF) printf("GC genCollect()\n");
-    }
-
-    void minimize() // minimize physical memory usage
-    {
-    debug(PRINTF) printf("GC minimize()\n");
+		    // If free'd entire page
+		    if (bbase[0] == 0 && bbase[1] == 0 && bbase[2] == 0 && bbase[3] == 0 &&
+			bbase[4] == 0 && bbase[5] == 0 && bbase[6] == 0 && bbase[7] == 0)
+		    {
+			for (; p < ptop; p += size, biti += bitstride)
+			{
+			    if (pool.finals.nbits && pool.finals.testClear(biti))
+				rt_finalize(cast(List *)sentinel_add(p), false);
+
+			    List *list = cast(List *)p;
+			    //debug(PRINTF) printf("\tcollecting %x\n", list);
+			    log_free(sentinel_add(list));
+
+			    debug (MEMSTOMP) cstring.memset(p, 0xF3, size);
+			}
+			pool.pagetable[pn] = B_FREE;
+			freed += PAGESIZE;
+			//debug(PRINTF) printf("freeing entire page %d\n", pn);
+			continue;
+		    }
     }
-
-    void setFinalizer(void *p, GC_FINALIZER pFn)
-    {
-    debug(PRINTF) printf("GC setFinalizer()\n");
-    }
-
-    void enable()
-    {
-    debug(PRINTF) printf("GC enable()\n");
+		    for (; p < ptop; p += size, biti += bitstride)
+		    {
+			if (!pool.mark.test(biti))
+			{
+			    sentinel_Invariant(sentinel_add(p));
+
+			    pool.freebits.set(biti);
+			    pool.noscan.clear(biti);
+			    if (pool.finals.nbits && pool.finals.testClear(biti))
+				rt_finalize(cast(List *)sentinel_add(p), false);
+
+			    List *list = cast(List *)p;
+			    debug(PRINTF) printf("\tcollecting %x\n", list);
+			    log_free(sentinel_add(list));
+
+			    debug (MEMSTOMP) cstring.memset(p, 0xF3, size);
+
+			    freed += size;
+			}
+		    }
+		}
+		else if (bin == B_PAGE)
+		{   uint biti = pn * (PAGESIZE / 16);
+
+		    if (!pool.mark.test(biti))
+		    {   byte *p = pool.baseAddr + pn * PAGESIZE;
+
+			sentinel_Invariant(sentinel_add(p));
+			pool.noscan.clear(biti);
+			if (pool.finals.nbits && pool.finals.testClear(biti))
+			    rt_finalize(sentinel_add(p), false);
+
+			debug(COLLECT_PRINTF) printf("\tcollecting big %x\n", p);
+			log_free(sentinel_add(p));
+			pool.pagetable[pn] = B_FREE;
+			freedpages++;
+			debug (MEMSTOMP) cstring.memset(p, 0xF3, PAGESIZE);
+			while (pn + 1 < ncommitted && pool.pagetable[pn + 1] == B_PAGEPLUS)
+			{
+			    pn++;
+			    pool.pagetable[pn] = B_FREE;
+			    freedpages++;
+
+			    debug (MEMSTOMP)
+			    {   p += PAGESIZE;
+				cstring.memset(p, 0xF3, PAGESIZE);
+			    }
+			}
+		    }
+		}
+	    }
+	}
+
+	// Zero buckets
+	bucket[] = null;
+
+	// Free complete pages, rebuild free list
+	debug(COLLECT_PRINTF) printf("\tfree complete pages\n");
+	size_t recoveredpages = 0;
+	for (n = 0; n < npools; n++)
+	{   uint pn;
+	    uint ncommitted;
+
+	    pool = pooltable[n];
+	    ncommitted = pool.ncommitted;
+	    for (pn = 0; pn < ncommitted; pn++)
+	    {
+		Bins bin = cast(Bins)pool.pagetable[pn];
+		uint biti;
+		uint u;
+
+		if (bin < B_PAGE)
+		{
+		    uint size = binsize[bin];
+		    uint bitstride = size / 16;
+		    uint bitbase = pn * (PAGESIZE / 16);
+		    uint bittop = bitbase + (PAGESIZE / 16);
+		    byte *p;
+
+		    biti = bitbase;
+		    for (biti = bitbase; biti < bittop; biti += bitstride)
+		    {   if (!pool.freebits.test(biti))
+			    goto Lnotfree;
+		    }
+		    pool.pagetable[pn] = B_FREE;
+		    recoveredpages++;
+		    continue;
+
+		 Lnotfree:
+		    p = pool.baseAddr + pn * PAGESIZE;
+		    for (u = 0; u < PAGESIZE; u += size)
+		    {   biti = bitbase + u / 16;
+			if (pool.freebits.test(biti))
+			{   List *list;
+
+			    list = cast(List *)(p + u);
+			    if (list.next != bucket[bin])	// avoid unnecessary writes
+				list.next = bucket[bin];
+			    bucket[bin] = list;
+			}
+		    }
+		}
+	    }
+	}
+
+	debug(COLLECT_PRINTF) printf("recovered pages = %d\n", recoveredpages);
+	debug(COLLECT_PRINTF) printf("\tfree'd %u bytes, %u pages from %u pools\n", freed, freedpages, npools);
+
+	Thread.resumeAll();
+
+	return freedpages + recoveredpages;
     }
 
-    void disable()
+
+    /**
+     * Run finalizer on p when it is free'd.
+     */
+    void doFinalize(void *p)
     {
-    debug(PRINTF) printf("GC disable()\n");
+	Pool *pool = findPool(p);
+	assert(pool);
+
+	// Only allocate finals[] if we actually need it
+	if (!pool.finals.nbits)
+	    pool.finals.alloc(pool.mark.nbits);
+
+	pool.finals.set((p - pool.baseAddr) / 16);
     }
 
-    void getStats(out GCStats stats)
+
+    /**
+     * Indicate that block pointed to by p has possible pointers
+     * to GC allocated memory in it.
+     */
+
+    void HasPointers(void *p)
     {
-    debug(PRINTF) printf("GC getStats()\n");
+	Pool *pool = findPool(p);
+	assert(pool);
+
+	pool.noscan.clear((p - pool.baseAddr) / 16);
     }
 
-    void hasPointers(void* p)
+
+    /**
+     * Indicate that block pointed to by p has no possible pointers
+     * to GC allocated memory in it.
+     */
+    void HasNoPointers(void *p)
     {
-    debug(PRINTF) printf("GC hasPointers()\n");
-    }
-
-    void hasNoPointers(void* p)
-    {
-    debug(PRINTF) printf("GC hasNoPointers()\n");
+	//printf("HasNoPointers(%p)\n", p);
+	Pool *pool = findPool(p);
+	assert(pool);
+
+	pool.noscan.set((p - pool.baseAddr) / 16);
     }
 
-    void setV1_0()
+
+    /***** Leak Detector ******/
+
+
+    debug (LOGGING)
     {
-    debug(PRINTF) printf("GC setV1_0()\n");
-    assert(0);
+	LogArray current;
+	LogArray prev;
+
+
+	void log_init()
+	{
+	    //debug(PRINTF) printf("+log_init()\n");
+	    current.reserve(1000);
+	    prev.reserve(1000);
+	    //debug(PRINTF) printf("-log_init()\n");
+	}
+
+
+	void log_malloc(void *p, size_t size)
+	{
+	    //debug(PRINTF) printf("+log_malloc(p = %x, size = %d)\n", p, size);
+	    Log log;
+
+	    log.p = p;
+	    log.size = size;
+	    log.line = GC.line;
+	    log.file = GC.file;
+	    log.parent = null;
+
+	    GC.line = 0;
+	    GC.file = null;
+
+	    current.push(log);
+	    //debug(PRINTF) printf("-log_malloc()\n");
+	}
+
+
+	void log_free(void *p)
+	{
+	    //debug(PRINTF) printf("+log_free(%x)\n", p);
+	    size_t i;
+
+	    i = current.find(p);
+	    if (i == ~0u)
+	    {
+		debug(PRINTF) printf("free'ing unallocated memory %x\n", p);
+	    }
+	    else
+		current.remove(i);
+	    //debug(PRINTF) printf("-log_free()\n");
+	}
+
+	void log_collect()
+	{
+	    //debug(PRINTF) printf("+log_collect()\n");
+	    // Print everything in current that is not in prev
+
+	    debug(PRINTF) printf("New pointers this cycle: --------------------------------\n");
+	    size_t used = 0;
+	    for (size_t i = 0; i < current.dim; i++)
+	    {
+		size_t j;
+
+		j = prev.find(current.data[i].p);
+		if (j == ~0u)
+		    current.data[i].print();
+		else
+		    used++;
+	    }
+
+	    debug(PRINTF) printf("All roots this cycle: --------------------------------\n");
+	    for (size_t i = 0; i < current.dim; i++)
+	    {
+		void *p;
+		size_t j;
+
+		p = current.data[i].p;
+		if (!findPool(current.data[i].parent))
+		{
+		    j = prev.find(current.data[i].p);
+		    if (j == ~0u)
+			debug(PRINTF) printf("N");
+		    else
+			debug(PRINTF) printf(" ");;
+		    current.data[i].print();
+		}
+	    }
+
+	    debug(PRINTF) printf("Used = %d-------------------------------------------------\n", used);
+	    prev.copy(&current);
+
+	    debug(PRINTF) printf("-log_collect()\n");
+	}
+
+
+	void log_parent(void *p, void *parent)
+	{
+	    //debug(PRINTF) printf("+log_parent()\n");
+	    size_t i;
+
+	    i = current.find(p);
+	    if (i == ~0u)
+	    {
+		debug(PRINTF) printf("parent'ing unallocated memory %x, parent = %x\n", p, parent);
+		Pool *pool;
+		pool = findPool(p);
+		assert(pool);
+		size_t offset = cast(uint)(p - pool.baseAddr);
+		size_t biti;
+		uint pn = offset / PAGESIZE;
+		Bins bin = cast(Bins)pool.pagetable[pn];
+		biti = (offset & notbinsize[bin]);
+		debug(PRINTF) printf("\tbin = %d, offset = x%x, biti = x%x\n", bin, offset, biti);
+	    }
+	    else
+	    {
+		current.data[i].parent = parent;
+	    }
+	    //debug(PRINTF) printf("-log_parent()\n");
+	}
+
     }
-
-    size_t extend(void* p, size_t minsize, size_t maxsize)
+    else
     {
-    debug(PRINTF) printf("GC extend()\n");
-    assert(0);
+	void log_init() { }
+	void log_malloc(void *p, size_t size) { }
+	void log_free(void *p) { }
+	void log_collect() { }
+	void log_parent(void *p, void *parent) { }
     }
 }
+
+
+/* ============================ Pool  =============================== */
+
+
+struct Pool
+{
+    byte* baseAddr;
+    byte* topAddr;
+    GCBits mark;	// entries already scanned, or should not be scanned
+    GCBits scan;	// entries that need to be scanned
+    GCBits freebits;	// entries that are on the free list
+    GCBits finals;	// entries that need finalizer run on them
+    GCBits noscan;	// entries that should not be scanned
+
+    uint npages;
+    uint ncommitted;	// ncommitted <= npages
+    ubyte* pagetable;
+
+
+    void initialize(uint npages)
+    {
+	size_t poolsize;
+
+	//debug(PRINTF) printf("Pool::Pool(%u)\n", npages);
+	poolsize = npages * PAGESIZE;
+	assert(poolsize >= POOLSIZE);
+	baseAddr = cast(byte *)os_mem_map(poolsize);
+
+	// Some of the code depends on page alignment of memory pools
+	assert((cast(uint)baseAddr & (PAGESIZE - 1)) == 0);
+
+	if (!baseAddr)
+	{
+	    //debug(PRINTF) printf("GC fail: poolsize = x%x, errno = %d\n", poolsize, errno);
+	    //debug(PRINTF) printf("message = '%s'\n", sys_errlist[errno]);
+
+	    npages = 0;
+	    poolsize = 0;
+	}
+	//assert(baseAddr);
+	topAddr = baseAddr + poolsize;
+
+	mark.alloc(poolsize / 16);
+	scan.alloc(poolsize / 16);
+	freebits.alloc(poolsize / 16);
+	noscan.alloc(poolsize / 16);
+
+	pagetable = cast(ubyte*)cstdlib.malloc(npages);
+	if (!pagetable)
+	    onOutOfMemoryError();
+	cstring.memset(pagetable, B_UNCOMMITTED, npages);
+
+	this.npages = npages;
+	ncommitted = 0;
+    }
+
+
+    void Dtor()
+    {
+	if (baseAddr)
+	{
+	    int result;
+
+	    if (ncommitted)
+	    {
+		result = os_mem_decommit(baseAddr, 0, ncommitted * PAGESIZE);
+		assert(result == 0);
+		ncommitted = 0;
+	    }
+
+	    if (npages)
+	    {
+		result = os_mem_unmap(baseAddr, npages * PAGESIZE);
+		assert(result == 0);
+		npages = 0;
+	    }
+
+	    baseAddr = null;
+	    topAddr = null;
+	}
+	if (pagetable)
+	    cstdlib.free(pagetable);
+
+	mark.Dtor();
+	scan.Dtor();
+	freebits.Dtor();
+	finals.Dtor();
+        noscan.Dtor();
+    }
+
+
+    void Invariant() { }
+
+
+    invariant()
+    {
+	//mark.Invariant();
+	//scan.Invariant();
+	//freebits.Invariant();
+	//finals.Invariant();
+	//noscan.Invariant();
+
+	if (baseAddr)
+	{
+	    //if (baseAddr + npages * PAGESIZE != topAddr)
+		//printf("baseAddr = %p, npages = %d, topAddr = %p\n", baseAddr, npages, topAddr);
+	    assert(baseAddr + npages * PAGESIZE == topAddr);
+	    assert(ncommitted <= npages);
+	}
+
+	for (uint i = 0; i < npages; i++)
+	{   Bins bin = cast(Bins)pagetable[i];
+
+	    assert(bin < B_MAX);
+	}
+    }
+
+
+    /**
+     * Allocate n pages from Pool.
+     * Returns ~0u on failure.
+     */
+    uint allocPages(uint n)
+    {
+	uint i;
+	uint n2;
+
+	//debug(PRINTF) printf("Pool::allocPages(n = %d)\n", n);
+	n2 = n;
+	for (i = 0; i < ncommitted; i++)
+	{
+	    if (pagetable[i] == B_FREE)
+	    {
+		if (--n2 == 0)
+		{   //debug(PRINTF) printf("\texisting pn = %d\n", i - n + 1);
+		    return i - n + 1;
+		}
+	    }
+	    else
+		n2 = n;
+	}
+	return extendPages(n);
+    }
+
+    /**
+     * Extend Pool by n pages.
+     * Returns ~0u on failure.
+     */
+    uint extendPages(uint n)
+    {
+	//debug(PRINTF) printf("Pool::extendPages(n = %d)\n", n);
+	if (ncommitted + n <= npages)
+	{
+	    uint tocommit;
+
+	    tocommit = (n + (COMMITSIZE/PAGESIZE) - 1) & ~(COMMITSIZE/PAGESIZE - 1);
+	    if (ncommitted + tocommit > npages)
+		tocommit = npages - ncommitted;
+	    //debug(PRINTF) printf("\tlooking to commit %d more pages\n", tocommit);
+	    //fflush(stdout);
+	    if (os_mem_commit(baseAddr, ncommitted * PAGESIZE, tocommit * PAGESIZE) == 0)
+	    {
+		cstring.memset(pagetable + ncommitted, B_FREE, tocommit);
+		auto i = ncommitted;
+		ncommitted += tocommit;
+
+		while (i && pagetable[i - 1] == B_FREE)
+		    i--;
+
+		return i;
+	    }
+	    //debug(PRINTF) printf("\tfailed to commit %d pages\n", tocommit);
+	}
+
+	return ~0u;
+    }
+
+
+    /**
+     * Free npages pages starting with pagenum.
+     */
+    void freePages(uint pagenum, uint npages)
+    {
+	cstring.memset(&pagetable[pagenum], B_FREE, npages);
+    }
+
+
+    /**
+     * Used for sorting pooltable[]
+     */
+    int opCmp(Pool *p2)
+    {
+	if (baseAddr < p2.baseAddr)
+	    return -1;
+	else
+	    return cast(int)(baseAddr > p2.baseAddr);
+    }
+}
+
+
+/* ============================ SENTINEL =============================== */
+
+
+version (SENTINEL)
+{
+    const size_t SENTINEL_PRE = cast(size_t) 0xF4F4F4F4F4F4F4F4UL;	// 32 or 64 bits
+    const ubyte SENTINEL_POST = 0xF5;		// 8 bits
+    const uint SENTINEL_EXTRA = 2 * size_t.sizeof + 1;
+
+
+    size_t* sentinel_size(void *p)  { return &(cast(size_t *)p)[-2]; }
+    size_t* sentinel_pre(void *p)   { return &(cast(size_t *)p)[-1]; }
+    ubyte* sentinel_post(void *p) { return &(cast(ubyte *)p)[sentinel_size(p)]; }
+
+
+    void sentinel_init(void *p, size_t size)
+    {
+	*sentinel_size(p) = size;
+	*sentinel_pre(p) = SENTINEL_PRE;
+	*sentinel_post(p) = SENTINEL_POST;
+    }
+
+
+    void sentinel_Invariant(void *p)
+    {
+	assert(*sentinel_pre(p) == SENTINEL_PRE);
+	assert(*sentinel_post(p) == SENTINEL_POST);
+    }
+
+
+    void *sentinel_add(void *p)
+    {
+	return p + 2 * size_t.sizeof;
+    }
+
+
+    void *sentinel_sub(void *p)
+    {
+	return p - 2 * size_t.sizeof;
+    }
+}
+else
+{
+    const uint SENTINEL_EXTRA = 0;
+
+
+    void sentinel_init(void *p, size_t size)
+    {
+    }
+
+
+    void sentinel_Invariant(void *p)
+    {
+    }
+
+
+    void *sentinel_add(void *p)
+    {
+	return p;
+    }
+
+
+    void *sentinel_sub(void *p)
+    {
+	return p;
+    }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/gc/win32.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,168 @@
+
+// Copyright (C) 2001-2002 by Digital Mars
+// All Rights Reserved
+// www.digitalmars.com
+// Written by Walter Bright
+
+import std.c.windows.windows;
+
+alias int pthread_t;
+
+/***********************************
+ * Map memory.
+ */
+
+void *os_mem_map(uint nbytes)
+{
+    return VirtualAlloc(null, nbytes, MEM_RESERVE, PAGE_READWRITE);
+}
+
+/***********************************
+ * Commit memory.
+ * Returns:
+ *	0	success
+ *	!=0	failure
+ */
+
+int os_mem_commit(void *base, uint offset, uint nbytes)
+{
+    void *p;
+
+    p = VirtualAlloc(base + offset, nbytes, MEM_COMMIT, PAGE_READWRITE);
+    return cast(int)(p == null);
+}
+
+
+/***********************************
+ * Decommit memory.
+ * Returns:
+ *	0	success
+ *	!=0	failure
+ */
+
+int os_mem_decommit(void *base, uint offset, uint nbytes)
+{
+    return cast(int)VirtualFree(base + offset, nbytes, MEM_DECOMMIT) == 0; 
+}
+
+/***********************************
+ * Unmap memory allocated with os_mem_map().
+ * Memory must have already been decommitted.
+ * Returns:
+ *	0	success
+ *	!=0	failure
+ */
+
+int os_mem_unmap(void *base, uint nbytes)
+{
+    return cast(int)VirtualFree(base, 0, MEM_RELEASE) == 0; 
+}
+
+
+/********************************************
+ */
+
+pthread_t pthread_self()
+{
+    //printf("pthread_self() = %x\n", GetCurrentThreadId());
+    return cast(pthread_t) GetCurrentThreadId();
+}
+
+/**********************************************
+ * Determine "bottom" of stack (actually the top on Win32 systems).
+ */
+
+void *os_query_stackBottom()
+{
+    asm
+    {
+	naked			;
+	mov	EAX,FS:4	;
+	ret			;
+    }
+}
+
+/**********************************************
+ * Determine base address and size of static data segment.
+ */
+
+version (GNU)
+{
+// This is MinGW specific
+extern (C)
+{
+    // TODO: skip the .rdata between .data and .bss?
+    extern int _data_start__;
+    extern int _bss_end__;
+}
+
+void os_query_staticdataseg(void **base, uint *nbytes)
+{
+    *base = cast(void *)&_data_start__;
+    *nbytes = cast(uint)(cast(char *)&_bss_end__ - cast(char *)&_data_start__);
+}
+
+}
+else
+{
+    
+extern (C)
+{
+    extern int _xi_a;	// &_xi_a just happens to be start of data segment
+    extern int _edata;	// &_edata is start of BSS segment
+    extern int _end;	// &_end is past end of BSS
+}
+
+void os_query_staticdataseg(void **base, uint *nbytes)
+{
+    *base = cast(void *)&_xi_a;
+    *nbytes = cast(uint)(cast(char *)&_end - cast(char *)&_xi_a);
+}
+
+}
+/++++
+
+void os_query_staticdataseg(void **base, uint *nbytes)
+{
+    static char dummy = 6;
+    SYSTEM_INFO si;
+    MEMORY_BASIC_INFORMATION mbi;
+    char *p;
+    void *bottom = null;
+    uint size = 0;
+
+    // Tests show the following does not work reliably.
+    // The reason is that the data segment is arbitrarily divided
+    // up into PAGE_READWRITE and PAGE_WRITECOPY.
+    // This means there are multiple regions to query, and
+    // can even wind up including the code segment.
+    assert(0);				// fix implementation
+
+    GetSystemInfo(&si);
+    p = (char *)((uint)(&dummy) & ~(si.dwPageSize - 1));
+    while (VirtualQuery(p, &mbi, sizeof(mbi)) == sizeof(mbi) &&
+        mbi.Protect & (PAGE_READWRITE | PAGE_WRITECOPY) &&
+        !(mbi.Protect & PAGE_GUARD) &&
+        mbi.AllocationBase != 0)
+    {
+	bottom = (void *)mbi.BaseAddress;
+	size = (uint)mbi.RegionSize;
+
+	printf("dwPageSize        = x%x\n", si.dwPageSize);
+	printf("&dummy            = %p\n", &dummy);
+	printf("BaseAddress       = %p\n", mbi.BaseAddress);
+	printf("AllocationBase    = %p\n", mbi.AllocationBase);
+	printf("AllocationProtect = x%x\n", mbi.AllocationProtect);
+	printf("RegionSize        = x%x\n", mbi.RegionSize);
+	printf("State             = x%x\n", mbi.State);
+	printf("Protect           = x%x\n", mbi.Protect);
+	printf("Type              = x%x\n\n", mbi.Type);
+
+	p -= si.dwPageSize;
+    }
+
+    *base = bottom;
+    *nbytes = size;
+}
+
+++++/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/hello.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,5 @@
+module hello;
+
+import std.stdio;
+
+void main() { writefln("Hello World"); }
--- a/lphobos/internal/aaA.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/internal/aaA.d	Mon Aug 04 19:28:49 2008 +0200
@@ -60,14 +60,14 @@
  */
 alias Array ArrayRet_t;
 
-pragma(LLVM_internal, "notypeinfo")
+pragma(no_typeinfo)
 struct Array
 {
     size_t length;
     void* ptr;
 }
 
-pragma(LLVM_internal, "notypeinfo")
+pragma(no_typeinfo)
 struct aaA
 {
     aaA *left;
@@ -77,7 +77,7 @@
     /* value */
 }
 
-pragma(LLVM_internal, "notypeinfo")
+pragma(no_typeinfo)
 struct BB
 {
     aaA*[] b;
@@ -226,7 +226,7 @@
  * Add entry for key if it is not already there.
  */
 
-void* _aaGet(AA* aa, TypeInfo keyti, void* pkey, size_t valuesize)
+void* _aaGet(AA* aa, TypeInfo keyti, size_t valuesize, void* pkey)
     in
     {
 	assert(aa);
--- a/lphobos/internal/adi.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/internal/adi.d	Mon Aug 04 19:28:49 2008 +0200
@@ -38,7 +38,7 @@
 import std.outofmemory;
 import std.utf;
 
-pragma(LLVM_internal, "notypeinfo")
+pragma(no_typeinfo)
 struct Array
 {
     size_t length;
@@ -462,13 +462,13 @@
 
 extern (C) int _adEq(Array a1, Array a2, TypeInfo ti)
 {
-    //printf("_adEq(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
+    // printf("_adEq(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
     if (a1.length != a2.length)
     return 0;       // not equal
-    auto sz = ti.tsize();
+    auto sz = ti.next.tsize();
     auto p1 = a1.ptr;
     auto p2 = a2.ptr;
-
+    
 /+
     for (int i = 0; i < a1.length; i++)
     {
@@ -480,10 +480,10 @@
     if (sz == 1)
     // We should really have a ti.isPOD() check for this
     return (memcmp(p1, p2, a1.length) == 0);
-
+    
     for (size_t i = 0; i < a1.length; i++)
     {
-    if (!ti.equals(p1 + i * sz, p2 + i * sz))
+    if (!ti.next.equals(p1 + i * sz, p2 + i * sz))
         return 0;       // not equal
     }
     return 1;           // equal
--- a/lphobos/internal/contract.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/internal/contract.d	Mon Aug 04 19:28:49 2008 +0200
@@ -1,13 +1,21 @@
 module internal.contract;
 
+import std.string: toString;
 extern(C):
 
 void exit(int);
 
-void _d_assert(bool cond, uint line, char[] msg)
+/*void _d_assert(bool cond, uint line, char[] msg)
 {
     if (!cond) {
         printf("Aborted(%u): %.*s\n", line, msg.length, msg.ptr);
         exit(1);
     }
+}*/
+void _d_assert(string file, uint line) {
+  throw new Exception(file~":"~.toString(line)~": Assertion failed!");
 }
+
+void _d_assert_msg(string msg, string file, uint line) {
+  throw new Exception(file~": "~.toString(line)~": Assertion failed: \""~msg~"\"");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/internal/critical.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,49 @@
+module internal.critical;
+extern(C):
+
+import std.c.linux.linux, std.c.stdlib:ccalloc=calloc, cmalloc=malloc, cfree=free;
+
+struct CritSec {
+  pthread_mutex_t* p;
+}
+
+const PTHREAD_MUTEX_RECURSIVE = 1, PTHREAD_MUTEX_ERRORCHECK=2;
+
+extern(C) int pthread_self();
+
+void _d_criticalenter(CritSec* cs) {
+  if (!cs.p) {
+    auto newp = cast(pthread_mutex_t*) cmalloc(pthread_mutex_t.sizeof);
+    auto cspp = &cs.p;
+    pthread_mutexattr_t mt; pthread_mutexattr_init(&mt);
+    pthread_mutexattr_settype(&mt, PTHREAD_MUTEX_RECURSIVE);
+    printf("Create -> %i\n", pthread_mutex_init(newp, &mt));
+    asm { xor EAX, EAX; mov ECX, newp; mov EDX, cspp; lock; cmpxchg int ptr [EDX], ECX; }
+    if (cs.p != newp) pthread_mutex_destroy(newp);
+  }
+  auto count = (cast(uint*) cs.p)[1];
+  // printf("%i ::%u\n", pthread_self(), count);
+  //printf("%i: Lock %p -> %i\n", pthread_self(), cs.p,
+    pthread_mutex_lock(cs.p);//);
+}
+
+void _d_criticalexit(CritSec* cs) {
+  //printf("%i: Unlock %p -> %i\n", pthread_self(), cs.p,
+    pthread_mutex_unlock(cs.p);//);
+}
+
+void _d_monitorenter(Object h)
+{
+    _d_criticalenter(cast(CritSec*) &h.__monitor);
+}
+
+void _d_monitorexit(Object h)
+{
+    _d_criticalexit(cast(CritSec*) &h.__monitor);
+}
+
+void _STI_monitor_staticctor() { }
+void _STI_critical_init() { }
+void _STI_critical_term() { }
+void _STD_monitor_staticdtor() { }
+void _STD_critical_term() { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/internal/dmain2.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,122 @@
+/*
+ * Placed into the Public Domain.
+ * written by Walter Bright
+ * www.digitalmars.com
+ */
+
+module internal.dmain2;
+import object;
+import std.c.stdio;
+import std.c.string;
+import std.c.stdlib;
+import std.string;
+
+extern (C) void _STI_monitor_staticctor();
+extern (C) void _STD_monitor_staticdtor();
+extern (C) void _STI_critical_init();
+extern (C) void _STD_critical_term();
+extern (C) void gc_init();
+extern (C) void gc_term();
+extern (C) void _minit();
+extern (C) void _moduleCtor();
+extern (C) void _moduleDtor();
+extern (C) void _moduleUnitTests();
+
+extern (C) bool no_catch_exceptions;
+
+/***********************************
+ * The D main() function supplied by the user's program
+ */
+int main(char[][] args);
+
+/***********************************
+ * Substitutes for the C main() function.
+ * It's purpose is to wrap the call to the D main()
+ * function and catch any unhandled exceptions.
+ */
+
+extern (C) int main(size_t argc, char **argv)
+{
+    char[] *am;
+    char[][] args;
+    int result;
+    int myesp;
+    int myebx;
+
+    version (linux)
+    {
+	_STI_monitor_staticctor();
+	_STI_critical_init();
+	gc_init();
+	am = cast(char[] *) malloc(argc * (char[]).sizeof);
+	// BUG: alloca() conflicts with try-catch-finally stack unwinding
+	//am = (char[] *) alloca(argc * (char[]).sizeof);
+    }
+    version (Win32)
+    {
+	gc_init();
+	_minit();
+	am = cast(char[] *) alloca(argc * (char[]).sizeof);
+    }
+
+    if (no_catch_exceptions)
+    {
+	_moduleCtor();
+	_moduleUnitTests();
+
+	for (size_t i = 0; i < argc; i++)
+	{
+	    auto len = strlen(argv[i]);
+	    am[i] = argv[i][0 .. len];
+	}
+
+	args = am[0 .. argc];
+
+	result = main(args);
+	_moduleDtor();
+	gc_term();
+    }
+    else
+    {
+	try
+	{
+	    _moduleCtor();
+	    _moduleUnitTests();
+
+	    for (size_t i = 0; i < argc; i++)
+	    {
+		auto len = strlen(argv[i]);
+		am[i] = argv[i][0 .. len];
+	    }
+
+	    args = am[0 .. argc];
+
+	    result = main(args);
+	    _moduleDtor();
+	    gc_term();
+	}
+	catch (Object o)
+	{
+	    version (none)
+	    {
+		printf("Error: ");
+		o.print();
+	    }
+	    else
+	    {
+		auto foo = o.toString();
+		fprintf(stderr, "Error: %.*s\n", foo.length, foo.ptr);
+	    }
+	    exit(EXIT_FAILURE);
+	}
+    }
+
+    version (linux)
+    {
+	free(am);
+	_STD_critical_term();
+	_STD_monitor_staticdtor();
+    }
+    return result;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/internal/eh.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,374 @@
+/**
+ * This module contains functions and structures required for
+ * exception handling.
+ */
+module eh;
+
+// debug = EH_personality;
+// debug = EH_personality_verbose;
+
+// current EH implementation works on x86 linux only
+version(X86) version(linux) version=X86_LINUX;
+
+private extern(C) void abort();
+private extern(C) int printf(char*, ...);
+
+// D runtime functions
+extern(C) {
+    int _d_isbaseof(ClassInfo oc, ClassInfo c);
+}
+
+// libunwind headers
+extern(C)
+{
+    enum _Unwind_Reason_Code
+    {
+        NO_REASON = 0,
+        FOREIGN_EXCEPTION_CAUGHT = 1,
+        FATAL_PHASE2_ERROR = 2,
+        FATAL_PHASE1_ERROR = 3,
+        NORMAL_STOP = 4,
+        END_OF_STACK = 5,
+        HANDLER_FOUND = 6,
+        INSTALL_CONTEXT = 7,
+        CONTINUE_UNWIND = 8
+    }
+
+    enum _Unwind_Action
+    {
+        SEARCH_PHASE = 1,
+        CLEANUP_PHASE = 2,
+        HANDLER_PHASE = 3,
+        FORCE_UNWIND = 4
+    }
+
+    alias void* _Unwind_Context_Ptr;
+
+    alias void function(_Unwind_Reason_Code, _Unwind_Exception*) _Unwind_Exception_Cleanup_Fn;
+
+    struct _Unwind_Exception
+    {
+        char[8] exception_class;
+        _Unwind_Exception_Cleanup_Fn exception_cleanup;
+        int private_1;
+        int private_2;
+    }
+
+version(X86_LINUX) 
+{
+    void _Unwind_Resume(_Unwind_Exception*);
+    _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception*);
+    ulong _Unwind_GetLanguageSpecificData(_Unwind_Context_Ptr context);
+    ulong _Unwind_GetIP(_Unwind_Context_Ptr context);
+    ulong _Unwind_SetIP(_Unwind_Context_Ptr context, ulong new_value);
+    ulong _Unwind_SetGR(_Unwind_Context_Ptr context, int index, ulong new_value);
+    ulong _Unwind_GetRegionStart(_Unwind_Context_Ptr context);
+}
+else
+{
+    // runtime calls these directly
+    void _Unwind_Resume(_Unwind_Exception*)
+    {
+        printf("_Unwind_Resume is not implemented on this platform.\n");
+    }
+    _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception*)
+    {
+        printf("_Unwind_RaiseException is not implemented on this platform.\n");
+        return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
+    }
+}
+
+}
+
+
+// helpers for reading certain DWARF data
+//TODO: It may not be a good idea to use exceptions for error handling within exception handling code
+private ubyte* get_uleb128(ubyte* addr, ref size_t res)
+{
+  res = 0;
+  size_t bitsize = 0;
+
+  // read as long as high bit is set
+  while(*addr & 0x80) {
+    res |= (*addr & 0x7f) << bitsize;
+    bitsize += 7;
+    addr += 1;
+    if(bitsize >= size_t.sizeof*8)
+       throw new Exception("tried to read uleb128 that exceeded size of size_t");
+  }
+  // read last
+  if(bitsize != 0 && *addr >= 1 << size_t.sizeof*8 - bitsize)
+    throw new Exception("tried to read uleb128 that exceeded size of size_t");
+  res |= (*addr) << bitsize;
+
+  return addr + 1;
+}
+
+private ubyte* get_sleb128(ubyte* addr, ref ptrdiff_t res)
+{
+  res = 0;
+  size_t bitsize = 0;
+
+  // read as long as high bit is set
+  while(*addr & 0x80) {
+    res |= (*addr & 0x7f) << bitsize;
+    bitsize += 7;
+    addr += 1;
+    if(bitsize >= size_t.sizeof*8)
+       throw new Exception("tried to read sleb128 that exceeded size of size_t");
+  }
+  // read last
+  if(bitsize != 0 && *addr >= 1 << size_t.sizeof*8 - bitsize)
+    throw new Exception("tried to read sleb128 that exceeded size of size_t");
+  res |= (*addr) << bitsize;
+
+  // take care of sign
+  if(bitsize < size_t.sizeof*8 && ((*addr) & 0x40))
+    res |= cast(ptrdiff_t)(-1) ^ ((1 << (bitsize+7)) - 1);
+
+  return addr + 1;
+}
+
+
+// exception struct used by the runtime.
+// _d_throw allocates a new instance and passes the address of its
+// _Unwind_Exception member to the unwind call. The personality
+// routine is then able to get the whole struct by looking at the data
+// surrounding the unwind info.
+struct _d_exception
+{
+  Object exception_object;
+  _Unwind_Exception unwind_info;
+}
+
+// the 8-byte string identifying the type of exception
+// the first 4 are for vendor, the second 4 for language
+//TODO: This may be the wrong way around
+char[8] _d_exception_class = "LLDCD1\0\0";
+
+
+//
+// x86 Linux specific implementation of personality function
+// and helpers
+//
+version(X86_LINUX) 
+{
+
+// the personality routine gets called by the unwind handler and is responsible for
+// reading the EH tables and deciding what to do
+extern(C) _Unwind_Reason_Code _d_eh_personality(int ver, _Unwind_Action actions, ulong exception_class, _Unwind_Exception* exception_info, _Unwind_Context_Ptr context)
+{
+  printf("eh_personality is running\n");
+  // check ver: the C++ Itanium ABI only allows ver == 1
+  if(ver != 1) {
+    printf("Fatal Phase1 #1\n");
+    return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
+  }
+  
+  // check exceptionClass
+  //TODO: Treat foreign exceptions with more respect
+  if((cast(char*)&exception_class)[0..8] != _d_exception_class) {
+    printf("Fatal Phase1 #2: %s != %s\n", cast(char*)&exception_class, cast(char*) _d_exception_class);
+    return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
+  }
+
+  // find call site table, action table and classinfo table
+  // Note: callsite and action tables do not contain static-length
+  // data and will be parsed as needed
+  // Note: classinfo_table points past the end of the table
+  ubyte* callsite_table;
+  ubyte* action_table;
+  ClassInfo* classinfo_table;
+  _d_getLanguageSpecificTables(context, callsite_table, action_table, classinfo_table);
+
+
+  /*
+    find landing pad and action table index belonging to ip by walking
+    the callsite_table
+  */
+  ubyte* callsite_walker = callsite_table;
+
+  // get the instruction pointer
+  // will be used to find the right entry in the callsite_table
+  // -1 because it will point past the last instruction
+  ulong ip = _Unwind_GetIP(context) - 1;
+    
+  // address block_start is relative to
+  ulong region_start = _Unwind_GetRegionStart(context);
+
+  // table entries
+  uint block_start_offset, block_size;
+  ulong landing_pad;
+  size_t action_offset;
+
+  while(true) {
+    // if we've gone through the list and found nothing...
+    if(callsite_walker >= action_table) {
+      printf("Continue unwind #3\n");
+      return _Unwind_Reason_Code.CONTINUE_UNWIND;
+    }
+
+    block_start_offset = *cast(uint*)callsite_walker;
+    block_size = *(cast(uint*)callsite_walker + 1);
+    landing_pad = *(cast(uint*)callsite_walker + 2);
+    if(landing_pad)
+      landing_pad += region_start;
+    callsite_walker = get_uleb128(callsite_walker + 3*uint.sizeof, action_offset);
+
+    /*debug(EH_personality_verbose) */printf("%d %d %d\n", block_start_offset, block_size, landing_pad);
+
+    // since the list is sorted, as soon as we're past the ip
+    // there's no handler to be found
+    if(ip < region_start + block_start_offset) {
+      printf("Continue unwind #4\n");
+      return _Unwind_Reason_Code.CONTINUE_UNWIND;
+    }
+
+    // if we've found our block, exit
+    if(ip < region_start + block_start_offset + block_size)
+      break;
+  }
+
+  /*debug(EH_personality) */printf("Found correct landing pad and actionOffset %d\n", action_offset);
+
+  // now we need the exception's classinfo to find a handler
+  // the exception_info is actually a member of a larger _d_exception struct
+  // the runtime allocated. get that now
+  _d_exception* exception_struct = cast(_d_exception*)(cast(ubyte*)exception_info - _d_exception.unwind_info.offsetof);
+
+  // if there's no action offset and no landing pad, continue unwinding
+  if(!action_offset && !landing_pad) {
+    printf("Continue unwind #5\n");
+    return _Unwind_Reason_Code.CONTINUE_UNWIND;
+  }
+
+  // if there's no action offset but a landing pad, this is a cleanup handler
+  else if(!action_offset && landing_pad) {
+    printf("Install cleanup handler #6\n");
+    return _d_eh_install_finally_context(actions, landing_pad, exception_struct, context);
+  }
+
+  /*
+   walk action table chain, comparing classinfos using _d_isbaseof
+  */
+  ubyte* action_walker = action_table + action_offset - 1;
+
+  ptrdiff_t ti_offset, next_action_offset;
+  while(true) {
+    action_walker = get_sleb128(action_walker, ti_offset);
+    // it is intentional that we not modify action_walker here
+    // next_action_offset is from current action_walker position
+    get_sleb128(action_walker, next_action_offset);
+
+    // negative are 'filters' which we don't use
+    assert(ti_offset >= 0 && "Filter actions are unsupported");
+
+    // zero means cleanup, which we require to be the last action
+    if(ti_offset == 0) {
+      assert(next_action_offset == 0 && "Cleanup action must be last in chain");
+      printf("Cleanup handler #7\n");
+      return _d_eh_install_finally_context(actions, landing_pad, exception_struct, context);
+    }
+
+    // get classinfo for action and check if the one in the
+    // exception structure is a base
+    ClassInfo catch_ci = classinfo_table[-ti_offset];
+    /*debug(EH_personality) */printf("Comparing catch %s to exception %s\n", catch_ci.name.ptr, exception_struct.exception_object.classinfo.name.ptr);
+    if(_d_isbaseof(exception_struct.exception_object.classinfo, catch_ci)) {
+      printf("Install catch context #8\n");
+      return _d_eh_install_catch_context(actions, ti_offset, landing_pad, exception_struct, context);
+    }
+
+    // we've walked through all actions and found nothing...
+    if(next_action_offset == 0) {
+      printf("Continue unwind #9\n");
+      return _Unwind_Reason_Code.CONTINUE_UNWIND;
+    } else
+      action_walker += next_action_offset;
+  }
+  
+  printf("Assertion failure ;_;\n");
+  assert(false);
+}
+
+// These are the register numbers for SetGR that
+// llvm's eh.exception and eh.selector intrinsics
+// will pick up.
+// Found by trial-and-error and probably platform dependent!
+private int eh_exception_regno = 0;
+private int eh_selector_regno = 2;
+
+private _Unwind_Reason_Code _d_eh_install_catch_context(_Unwind_Action actions, ptrdiff_t switchval, ulong landing_pad, _d_exception* exception_struct, _Unwind_Context_Ptr context)
+{
+  debug(EH_personality) printf("Found catch clause!\n");
+
+  if(actions & _Unwind_Action.SEARCH_PHASE)
+    return _Unwind_Reason_Code.HANDLER_FOUND;
+
+  else if(actions & _Unwind_Action.HANDLER_PHASE)
+  {
+    debug(EH_personality) printf("Setting switch value to: %d!\n", switchval);
+    _Unwind_SetGR(context, eh_exception_regno, cast(ulong)cast(void*)(exception_struct.exception_object));
+    _Unwind_SetGR(context, eh_selector_regno, switchval);
+    _Unwind_SetIP(context, landing_pad);
+    return _Unwind_Reason_Code.INSTALL_CONTEXT;
+  }
+
+  assert(false);
+}
+
+private _Unwind_Reason_Code _d_eh_install_finally_context(_Unwind_Action actions, ulong landing_pad, _d_exception* exception_struct, _Unwind_Context_Ptr context)
+{
+  // if we're merely in search phase, continue
+  if(actions & _Unwind_Action.SEARCH_PHASE)
+    return _Unwind_Reason_Code.CONTINUE_UNWIND;
+
+  debug(EH_personality) printf("Calling cleanup routine...\n");
+
+  _Unwind_SetGR(context, eh_exception_regno, cast(ulong)exception_struct);
+  _Unwind_SetGR(context, eh_selector_regno, 0);
+  _Unwind_SetIP(context, landing_pad);
+  return _Unwind_Reason_Code.INSTALL_CONTEXT;
+}
+
+private void _d_getLanguageSpecificTables(_Unwind_Context_Ptr context, ref ubyte* callsite, ref ubyte* action, ref ClassInfo* ci)
+{
+  ubyte* data = cast(ubyte*)_Unwind_GetLanguageSpecificData(context);
+
+  //TODO: Do proper DWARF reading here
+  assert(*data++ == 0xff);
+
+  assert(*data++ == 0x00);
+  size_t cioffset;
+  data = get_uleb128(data, cioffset);
+  ci = cast(ClassInfo*)(data + cioffset);
+
+  assert(*data++ == 0x03);
+  size_t callsitelength;
+  data = get_uleb128(data, callsitelength);
+  action = data + callsitelength;
+
+  callsite = data;
+}
+
+} // end of x86 Linux specific implementation
+
+
+extern(C) void _d_throw_exception(Object e)
+{
+    if (e !is null)
+    {
+        _d_exception* exc_struct = new _d_exception;
+        exc_struct.unwind_info.exception_class[] = _d_exception_class;
+        exc_struct.exception_object = e;
+        printf("Raising exception\n");
+        _Unwind_Reason_Code ret = _Unwind_RaiseException(&exc_struct.unwind_info);
+        printf("_Unwind_RaiseException failed with reason code: %i\n", ret);
+    }
+    abort();
+}
+
+extern(C) void _d_eh_resume_unwind(_d_exception* exception_struct)
+{
+  _Unwind_Resume(&exception_struct.unwind_info);
+}
--- a/lphobos/internal/objectimpl.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/internal/objectimpl.d	Mon Aug 04 19:28:49 2008 +0200
@@ -1132,16 +1132,27 @@
     void function() ctor;
     void function() dtor;
     void function() unitTest;
+    
+    void* xgetMembers;
+    void function() ictor;
 
     /******************
      * Return collection of all modules in the program.
      */
-    static ModuleInfo[] modules()
-    {
-    return std.moduleinit._moduleinfo_array;
+    static int opApply(int delegate(ref ModuleInfo) dg) {
+      foreach (ref mod; std.moduleinit._moduleinfo_array)
+        if (auto i = dg(mod)) return i;
+      return 0;
     }
 }
 
+struct ModuleReference
+{
+    ModuleReference* next;
+    ModuleInfo mod;
+}
+extern(C) ModuleReference* _Dmodule_ref;
+
 /**
  * All recoverable exceptions should be derived from class Exception.
  */
@@ -1189,4 +1200,3 @@
 }
 
 //extern (C) int nullext = 0;
-
--- a/lphobos/internal/qsort2.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/internal/qsort2.d	Mon Aug 04 19:28:49 2008 +0200
@@ -14,7 +14,7 @@
 
 import std.c.stdlib;
 
-pragma(LLVM_internal, "notypeinfo")
+pragma(no_typeinfo)
 struct Array
 {
     size_t length;
--- a/lphobos/internal/switch.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/internal/switch.d	Mon Aug 04 19:28:49 2008 +0200
@@ -422,5 +422,7 @@
     }
 }
 
-
-
+void _d_switch_error(string fn, int line)
+{
+    throw new Exception(fn~toString(line)~": switch missing default");
+}
--- a/lphobos/llvm/intrinsic.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/llvm/intrinsic.d	Mon Aug 04 19:28:49 2008 +0200
@@ -2,110 +2,110 @@
 
 // code generator intrinsics
 /*
-pragma(LLVM_internal, "intrinsic", "llvm.returnaddress")
+pragma(intrinsic, "llvm.returnaddress")
     void* llvm_returnaddress(uint level);
 */
-pragma(LLVM_internal, "intrinsic", "llvm.frameaddress")
+pragma(intrinsic, "llvm.frameaddress")
     void* llvm_frameaddress(uint level);
 /*
-pragma(LLVM_internal, "intrinsic", "llvm.stacksave")
+pragma(intrinsic, "llvm.stacksave")
     void* llvm_stacksave();
 
-pragma(LLVM_internal, "intrinsic", "llvm.stackrestore")
+pragma(intrinsic, "llvm.stackrestore")
     void llvm_stackrestore(void* ptr);
 
-pragma(LLVM_internal, "intrinsic", "llvm.pcmarker")
+pragma(intrinsic, "llvm.pcmarker")
     void llvm_pcmarker(uint id);
 
-pragma(LLVM_internal, "intrinsic", "llvm.prefetch")
+pragma(intrinsic, "llvm.prefetch")
     void llvm_prefetch(void* ptr, uint rw, uint locality);
 */
 
-pragma(LLVM_internal, "intrinsic", "llvm.readcyclecounter")
+pragma(intrinsic, "llvm.readcyclecounter")
     ulong readcyclecounter();
 
 // standard C intrinsics
-pragma(LLVM_internal, "intrinsic", "llvm.memcpy.i32")
+pragma(intrinsic, "llvm.memcpy.i32")
     void llvm_memcpy_i32(void* dst, void* src, uint len, uint alignment);
 
-pragma(LLVM_internal, "intrinsic", "llvm.memcpy.i64")
+pragma(intrinsic, "llvm.memcpy.i64")
     void llvm_memcpy_i64(void* dst, void* src, ulong len, uint alignment);
 
-pragma(LLVM_internal, "intrinsic", "llvm.memmove.i32")
+pragma(intrinsic, "llvm.memmove.i32")
     void llvm_memmove_i32(void* dst, void* src, uint len, uint alignment);
 
-pragma(LLVM_internal, "intrinsic", "llvm.memmove.i64")
+pragma(intrinsic, "llvm.memmove.i64")
     void llvm_memmove_i64(void* dst, void* src, ulong len, int alignment);
 
-pragma(LLVM_internal, "intrinsic", "llvm.memset.i32")
+pragma(intrinsic, "llvm.memset.i32")
     void llvm_memset_i32(void* dst, ubyte val, uint len, uint alignment);
 
-pragma(LLVM_internal, "intrinsic", "llvm.memset.i64")
+pragma(intrinsic, "llvm.memset.i64")
     void llvm_memset_i64(void* dst, ubyte val, ulong len, uint alignment);
 
-pragma(LLVM_internal, "intrinsic", "llvm.sqrt.f32")
+pragma(intrinsic, "llvm.sqrt.f32")
     float llvm_sqrt(float val);
 
-pragma(LLVM_internal, "intrinsic", "llvm.sqrt.f64")
+pragma(intrinsic, "llvm.sqrt.f64")
 {
     double llvm_sqrt(double val);
-    real llvm_sqrt(real val);
+    // real llvm_sqrt(real val);
 }
 
-pragma(LLVM_internal, "intrinsic", "llvm.powi.f32")
+pragma(intrinsic, "llvm.powi.f32")
     float llvm_powi(float val, int power);
 
-pragma(LLVM_internal, "intrinsic", "llvm.powi.f64")
+pragma(intrinsic, "llvm.powi.f64")
 {
     double llvm_powi(double val, int power);
-    real llvm_powi(real val, int power);
+    // real llvm_powi(real val, int power);
 }
 
 // bit manipulation intrinsics
-pragma(LLVM_internal, "intrinsic", "llvm.bswap.i16.i16")
+pragma(intrinsic, "llvm.bswap.i16.i16")
     ushort llvm_bswap(ushort val);
 
-pragma(LLVM_internal, "intrinsic", "llvm.bswap.i32.i32")
+pragma(intrinsic, "llvm.bswap.i32.i32")
     uint llvm_bswap(uint val);
 
-pragma(LLVM_internal, "intrinsic", "llvm.bswap.i64.i64")
+pragma(intrinsic, "llvm.bswap.i64.i64")
     ulong llvm_bswap(ulong val);
 
 /*
-pragma(LLVM_internal, "intrinsic", "llvm.ctpop.i8")
+pragma(intrinsic, "llvm.ctpop.i8")
     uint llvm_ctpop_i8(ubyte src);
 
-pragma(LLVM_internal, "intrinsic", "llvm.ctpop.i16")
+pragma(intrinsic, "llvm.ctpop.i16")
     uint llvm_ctpop_i16(ushort src);
 
-pragma(LLVM_internal, "intrinsic", "llvm.ctpop.i32")
+pragma(intrinsic, "llvm.ctpop.i32")
     uint llvm_ctpop_i32(uint src);
 
-pragma(LLVM_internal, "intrinsic", "llvm.ctpop.i64")
+pragma(intrinsic, "llvm.ctpop.i64")
     uint llvm_ctpop_i64(ulong src);
 
-pragma(LLVM_internal, "intrinsic", "llvm.ctlz.i8")
+pragma(intrinsic, "llvm.ctlz.i8")
     uint llvm_ctlz_i8(ubyte src);
 
-pragma(LLVM_internal, "intrinsic", "llvm.ctlz.i16")
+pragma(intrinsic, "llvm.ctlz.i16")
     uint llvm_ctlz_i16(ushort src);
 
-pragma(LLVM_internal, "intrinsic", "llvm.ctlz.i32")
+pragma(intrinsic, "llvm.ctlz.i32")
     uint llvm_ctlz_i32(uint src);
 
-pragma(LLVM_internal, "intrinsic", "llvm.ctlz.i64")
+pragma(intrinsic, "llvm.ctlz.i64")
     uint llvm_ctlz_i64(ulong src);
 
-pragma(LLVM_internal, "intrinsic", "llvm.cttz.i8")
+pragma(intrinsic, "llvm.cttz.i8")
     uint llvm_cttz_i8(ubyte src);
 
-pragma(LLVM_internal, "intrinsic", "llvm.cttz.i16")
+pragma(intrinsic, "llvm.cttz.i16")
     uint llvm_cttz_i16(ushort src);
 
-pragma(LLVM_internal, "intrinsic", "llvm.cttz.i32")
+pragma(intrinsic, "llvm.cttz.i32")
     uint llvm_cttz_i32(uint src);
 
-pragma(LLVM_internal, "intrinsic", "llvm.cttz.i64")
+pragma(intrinsic, "llvm.cttz.i64")
     uint llvm_cttz_i64(ulong src);
 */
 
@@ -114,7 +114,7 @@
 /*
 
 //declare i8 @llvm.atomic.lcs.i8.i8p.i8.i8( i8* <ptr>, i8 <cmp>, i8 <val> )
-pragma(LLVM_internal, "intrinsic", "llvm.atomic.lcs.i8.i8p.i8.i8")
+pragma(intrinsic, "llvm.atomic.lcs.i8.i8p.i8.i8")
     ubyte llvm_atomic_lcs_i8(void* ptr, ubyte cmp, ubyte val);
 
 declare i16 @llvm.atomic.lcs.i16.i16p.i16.i16( i16* <ptr>, i16 <cmp>, i16 <val> )
--- a/lphobos/object.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/object.d	Mon Aug 04 19:28:49 2008 +0200
@@ -1,4 +1,3 @@
-
 // Implementation is in internal\object.d
 
 module object;
@@ -173,11 +172,19 @@
     void function() ctor;
     void function() dtor;
     void function() unitTest;
+    void* xgetMembers;
+    void function() ictor;
 
     // Return collection of all modules in the program.
-    static ModuleInfo[] modules();
+    static int opApply(int delegate(ref ModuleInfo));
 }
 
+struct ModuleReference {
+    ModuleReference* next;
+    ModuleInfo mod;
+}
+extern(C) extern ModuleReference* _Dmodule_ref;
+
 // Recoverable errors
 
 class Exception : Object
@@ -198,4 +205,3 @@
     this(string msg);
     this(string msg, Error next);
 }
-
--- a/lphobos/phobos.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/phobos.d	Mon Aug 04 19:28:49 2008 +0200
@@ -27,7 +27,12 @@
 std.c.stdio,
 std.c.stdlib,
 std.c.string,
-std.c.time;
+std.c.time,
+std.file,
+std.date,
+std.socket,
+std.zlib,
+std.cstream;
 
 version(linux) {
     import
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/bitarray.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,955 @@
+/***********************
+ * Macros:
+ *	WIKI = StdBitarray
+ */
+
+module std.bitarray;
+
+//debug = bitarray;		// uncomment to turn on debugging printf's
+
+private import std.intrinsic;
+
+/**
+ * An array of bits.
+ */
+
+struct BitArray
+{
+    size_t len;
+    uint* ptr;
+
+    size_t dim()
+    {
+	return (len + 31) / 32;
+    }
+
+    size_t length()
+    {
+	return len;
+    }
+
+    void length(size_t newlen)
+    {
+	if (newlen != len)
+	{
+	    size_t olddim = dim();
+	    size_t newdim = (newlen + 31) / 32;
+
+	    if (newdim != olddim)
+	    {
+		// Create a fake array so we can use D's realloc machinery
+		uint[] b = ptr[0 .. olddim];
+		b.length = newdim;		// realloc
+		ptr = b.ptr;
+		if (newdim & 31)
+		{   // Set any pad bits to 0
+		    ptr[newdim - 1] &= ~(~0 << (newdim & 31));
+		}
+	    }
+
+	    len = newlen;
+	}
+    }
+
+    /**********************************************
+     * Support for [$(I index)] operation for BitArray.
+     */
+    bool opIndex(size_t i)
+    in
+    {
+	assert(i < len);
+    }
+    body
+    {
+	return cast(bool)bt(ptr, i);
+    }
+
+    /** ditto */
+    bool opIndexAssign(bool b, size_t i)
+    in
+    {
+	assert(i < len);
+    }
+    body
+    {
+	if (b)
+	    bts(ptr, i);
+	else
+	    btr(ptr, i);
+	return b;
+    }
+
+    /**********************************************
+     * Support for array.dup property for BitArray.
+     */
+    BitArray dup()
+    {
+	BitArray ba;
+
+	uint[] b = ptr[0 .. dim].dup;
+	ba.len = len;
+	ba.ptr = b.ptr;
+	return ba;
+    }
+
+    unittest
+    {
+	BitArray a;
+	BitArray b;
+	int i;
+
+	debug(bitarray) printf("BitArray.dup.unittest\n");
+
+	a.length = 3;
+	a[0] = 1; a[1] = 0; a[2] = 1;
+	b = a.dup;
+	assert(b.length == 3);
+	for (i = 0; i < 3; i++)
+	{   debug(bitarray) printf("b[%d] = %d\n", i, b[i]);
+	    assert(b[i] == (((i ^ 1) & 1) ? true : false));
+	}
+    }
+
+    /**********************************************
+     * Support for foreach loops for BitArray.
+     */
+    int opApply(int delegate(inout bool) dg)
+    {
+	int result;
+
+	for (size_t i = 0; i < len; i++)
+	{   bool b = opIndex(i);
+	    result = dg(b);
+	    (*this)[i] = b;
+	    if (result)
+		break;
+	}
+	return result;
+    }
+
+    /** ditto */
+    int opApply(int delegate(inout size_t, inout bool) dg)
+    {
+	int result;
+
+	for (size_t i = 0; i < len; i++)
+	{   bool b = opIndex(i);
+	    result = dg(i, b);
+	    (*this)[i] = b;
+	    if (result)
+		break;
+	}
+	return result;
+    }
+
+    unittest
+    {
+	debug(bitarray) printf("BitArray.opApply unittest\n");
+
+	static bool[] ba = [1,0,1];
+
+	BitArray a; a.init(ba);
+
+	int i;
+	foreach (b;a)
+	{
+	    switch (i)
+	    {	case 0: assert(b == true); break;
+		case 1: assert(b == false); break;
+		case 2: assert(b == true); break;
+		default: assert(0);
+	    }
+	    i++;
+	}
+
+	foreach (j,b;a)
+	{
+	    switch (j)
+	    {	case 0: assert(b == true); break;
+		case 1: assert(b == false); break;
+		case 2: assert(b == true); break;
+		default: assert(0);
+	    }
+	}
+    }
+
+
+    /**********************************************
+     * Support for array.reverse property for BitArray.
+     */
+
+    BitArray reverse()
+	out (result)
+	{
+	    assert(result == *this);
+	}
+	body
+	{
+	    if (len >= 2)
+	    {
+		bool t;
+		size_t lo, hi;
+
+		lo = 0;
+		hi = len - 1;
+		for (; lo < hi; lo++, hi--)
+		{
+		    t = (*this)[lo];
+		    (*this)[lo] = (*this)[hi];
+		    (*this)[hi] = t;
+		}
+	    }
+	    return *this;
+	}
+
+    unittest
+    {
+	debug(bitarray) printf("BitArray.reverse.unittest\n");
+
+	BitArray b;
+	static bool[5] data = [1,0,1,1,0];
+	int i;
+
+	b.init(data);
+	b.reverse;
+	for (i = 0; i < data.length; i++)
+	{
+	    assert(b[i] == data[4 - i]);
+	}
+    }
+
+
+    /**********************************************
+     * Support for array.sort property for BitArray.
+     */
+
+    BitArray sort()
+	out (result)
+	{
+	    assert(result == *this);
+	}
+	body
+	{
+	    if (len >= 2)
+	    {
+		size_t lo, hi;
+
+		lo = 0;
+		hi = len - 1;
+		while (1)
+		{
+		    while (1)
+		    {
+			if (lo >= hi)
+			    goto Ldone;
+			if ((*this)[lo] == true)
+			    break;
+			lo++;
+		    }
+
+		    while (1)
+		    {
+			if (lo >= hi)
+			    goto Ldone;
+			if ((*this)[hi] == false)
+			    break;
+			hi--;
+		    }
+
+		    (*this)[lo] = false;
+		    (*this)[hi] = true;
+
+		    lo++;
+		    hi--;
+		}
+	    Ldone:
+		;
+	    }
+	    return *this;
+	}
+
+    unittest
+    {
+	debug(bitarray) printf("BitArray.sort.unittest\n");
+
+	static uint x = 0b1100011000;
+	static BitArray ba = { 10, &x };
+	ba.sort;
+	for (size_t i = 0; i < 6; i++)
+	    assert(ba[i] == false);
+	for (size_t i = 6; i < 10; i++)
+	    assert(ba[i] == true);
+    }
+
+
+    /***************************************
+     * Support for operators == and != for bit arrays.
+     */
+
+    int opEquals(BitArray a2)
+    {   size_t i;
+
+	if (this.length != a2.length)
+	    return 0;		// not equal
+	uint *p1 = cast(uint*)this.ptr;
+	uint *p2 = cast(uint*)a2.ptr;
+	size_t n = this.length / (8 * uint.sizeof);
+	for (i = 0; i < n; i++)
+	{
+	    if (p1[i] != p2[i])
+		return 0;		// not equal
+	}
+
+	uint mask;
+
+	n = this.length & ((8 * uint.sizeof) - 1);
+	mask = (1 << n) - 1;
+	//printf("i = %d, n = %d, mask = %x, %x, %x\n", i, n, mask, p1[i], p2[i]);
+	return (mask == 0) || (p1[i] & mask) == (p2[i] & mask);
+    }
+
+    unittest
+    {
+	debug(bitarray) printf("BitArray.opEquals unittest\n");
+
+	static bool[] ba = [1,0,1,0,1];
+	static bool[] bb = [1,0,1];
+	static bool[] bc = [1,0,1,0,1,0,1];
+	static bool[] bd = [1,0,1,1,1];
+	static bool[] be = [1,0,1,0,1];
+
+	BitArray a; a.init(ba);
+	BitArray b; b.init(bb);
+	BitArray c; c.init(bc);
+	BitArray d; d.init(bd);
+	BitArray e; e.init(be);
+
+	assert(a != b);
+	assert(a != c);
+	assert(a != d);
+	assert(a == e);
+    }
+
+    /***************************************
+     * Implement comparison operators.
+     */
+
+    int opCmp(BitArray a2)
+    {
+	size_t len;
+	size_t i;
+
+	len = this.length;
+	if (a2.length < len)
+	    len = a2.length;
+	uint* p1 = cast(uint*)this.ptr;
+	uint* p2 = cast(uint*)a2.ptr;
+	size_t n = len / (8 * uint.sizeof);
+	for (i = 0; i < n; i++)
+	{
+	    if (p1[i] != p2[i])
+		break;		// not equal
+	}
+	/*	
+	for (uint j = i * 8; j < len; j++)
+	{   ubyte mask = cast(ubyte)(1 << j);
+	    int c;
+
+	    c = cast(int)(p1[i] & mask) - cast(int)(p2[i] & mask);
+	    if (c)
+		return c;
+	}
+	*/
+	uint mask = 1;
+	for (size_t j = i * (8 * uint.sizeof); j < len; j++)
+	{   int c;
+
+	    c = cast(int)(p1[i] & mask) - cast(int)(p2[i] & mask);
+	    if (c)
+		return c;
+	    mask <<= 1;
+	}
+	ptrdiff_t c = cast(ptrdiff_t)this.len - cast(ptrdiff_t)a2.length;
+	if (c < 0)
+	    return -1;
+	else if (c > 0)
+	    return 1;
+	return 0;
+    }
+
+    unittest
+    {
+	debug(bitarray) printf("BitArray.opCmp unittest\n");
+
+	static bool[] ba = [1,0,1,0,1];
+	static bool[] bb = [1,0,1];
+	static bool[] bc = [1,0,1,0,1,0,1];
+	static bool[] bd = [1,0,1,1,1];
+	static bool[] be = [1,0,1,0,1];
+
+	BitArray a; a.init(ba);
+	BitArray b; b.init(bb);
+	BitArray c; c.init(bc);
+	BitArray d; d.init(bd);
+	BitArray e; e.init(be);
+
+	assert(a >  b);
+	assert(a >= b);
+	assert(a <  c);
+	assert(a <= c);
+	assert(a <  d);
+	assert(a <= d);
+	assert(a == e);
+	assert(a <= e);
+	assert(a >= e);
+    }
+
+    /***************************************
+     * Set BitArray to contents of ba[]
+     */
+
+    void init(bool[] ba)
+    {
+	length = ba.length;
+	foreach (i, b; ba)
+	{
+	    (*this)[i] = b;
+	}
+    }
+
+
+    /***************************************
+     * Map BitArray onto v[], with numbits being the number of bits
+     * in the array. Does not copy the data.
+     *
+     * This is the inverse of opCast.
+     */
+    void init(void[] v, size_t numbits)
+    in
+    {
+	assert(numbits <= v.length * 8);
+	assert((v.length & 3) == 0);
+    }
+    body
+    {
+	ptr = cast(uint*)v.ptr;
+	len = numbits;
+    }
+
+    unittest
+    {
+	debug(bitarray) printf("BitArray.init unittest\n");
+
+	static bool[] ba = [1,0,1,0,1];
+
+	BitArray a; a.init(ba);
+	BitArray b;
+	void[] v;
+
+	v = cast(void[])a;
+	b.init(v, a.length);
+
+	assert(b[0] == 1);
+	assert(b[1] == 0);
+	assert(b[2] == 1);
+	assert(b[3] == 0);
+	assert(b[4] == 1);
+
+	a[0] = 0;
+	assert(b[0] == 0);
+
+	assert(a == b);
+    }
+
+    /***************************************
+     * Convert to void[].
+     */
+    void[] opCast()
+    {
+	return cast(void[])ptr[0 .. dim];
+    }
+
+    unittest
+    {
+	debug(bitarray) printf("BitArray.opCast unittest\n");
+
+	static bool[] ba = [1,0,1,0,1];
+
+	BitArray a; a.init(ba);
+	void[] v = cast(void[])a;
+
+	assert(v.length == a.dim * uint.sizeof);
+    }
+
+    /***************************************
+     * Support for unary operator ~ for bit arrays.
+     */
+    BitArray opCom()
+    {
+	auto dim = this.dim();
+
+	BitArray result;
+
+	result.length = len;
+	for (size_t i = 0; i < dim; i++)
+	    result.ptr[i] = ~this.ptr[i];
+	if (len & 31)
+	    result.ptr[dim - 1] &= ~(~0 << (len & 31));
+	return result;
+    }
+
+    unittest
+    {
+	debug(bitarray) printf("BitArray.opCom unittest\n");
+
+	static bool[] ba = [1,0,1,0,1];
+
+	BitArray a; a.init(ba);
+	BitArray b = ~a;
+
+	assert(b[0] == 0);
+	assert(b[1] == 1);
+	assert(b[2] == 0);
+	assert(b[3] == 1);
+	assert(b[4] == 0);
+    }
+
+
+    /***************************************
+     * Support for binary operator & for bit arrays.
+     */
+    BitArray opAnd(BitArray e2)
+    in
+    {
+	assert(len == e2.length);
+    }
+    body
+    {
+	auto dim = this.dim();
+
+	BitArray result;
+
+	result.length = len;
+	for (size_t i = 0; i < dim; i++)
+	    result.ptr[i] = this.ptr[i] & e2.ptr[i];
+	return result;
+    }
+
+    unittest
+    {
+	debug(bitarray) printf("BitArray.opAnd unittest\n");
+
+	static bool[] ba = [1,0,1,0,1];
+	static bool[] bb = [1,0,1,1,0];
+
+	BitArray a; a.init(ba);
+	BitArray b; b.init(bb);
+
+	BitArray c = a & b;
+
+	assert(c[0] == 1);
+	assert(c[1] == 0);
+	assert(c[2] == 1);
+	assert(c[3] == 0);
+	assert(c[4] == 0);
+    }
+
+
+    /***************************************
+     * Support for binary operator | for bit arrays.
+     */
+    BitArray opOr(BitArray e2)
+    in
+    {
+	assert(len == e2.length);
+    }
+    body
+    {
+	auto dim = this.dim();
+
+	BitArray result;
+
+	result.length = len;
+	for (size_t i = 0; i < dim; i++)
+	    result.ptr[i] = this.ptr[i] | e2.ptr[i];
+	return result;
+    }
+
+    unittest
+    {
+	debug(bitarray) printf("BitArray.opOr unittest\n");
+
+	static bool[] ba = [1,0,1,0,1];
+	static bool[] bb = [1,0,1,1,0];
+
+	BitArray a; a.init(ba);
+	BitArray b; b.init(bb);
+
+	BitArray c = a | b;
+
+	assert(c[0] == 1);
+	assert(c[1] == 0);
+	assert(c[2] == 1);
+	assert(c[3] == 1);
+	assert(c[4] == 1);
+    }
+
+
+    /***************************************
+     * Support for binary operator ^ for bit arrays.
+     */
+    BitArray opXor(BitArray e2)
+    in
+    {
+	assert(len == e2.length);
+    }
+    body
+    {
+	auto dim = this.dim();
+
+	BitArray result;
+
+	result.length = len;
+	for (size_t i = 0; i < dim; i++)
+	    result.ptr[i] = this.ptr[i] ^ e2.ptr[i];
+	return result;
+    }
+
+    unittest
+    {
+	debug(bitarray) printf("BitArray.opXor unittest\n");
+
+	static bool[] ba = [1,0,1,0,1];
+	static bool[] bb = [1,0,1,1,0];
+
+	BitArray a; a.init(ba);
+	BitArray b; b.init(bb);
+
+	BitArray c = a ^ b;
+
+	assert(c[0] == 0);
+	assert(c[1] == 0);
+	assert(c[2] == 0);
+	assert(c[3] == 1);
+	assert(c[4] == 1);
+    }
+
+
+    /***************************************
+     * Support for binary operator - for bit arrays.
+     *
+     * $(I a - b) for BitArrays means the same thing as $(I a &amp; ~b).
+     */
+    BitArray opSub(BitArray e2)
+    in
+    {
+	assert(len == e2.length);
+    }
+    body
+    {
+	auto dim = this.dim();
+
+	BitArray result;
+
+	result.length = len;
+	for (size_t i = 0; i < dim; i++)
+	    result.ptr[i] = this.ptr[i] & ~e2.ptr[i];
+	return result;
+    }
+
+    unittest
+    {
+	debug(bitarray) printf("BitArray.opSub unittest\n");
+
+	static bool[] ba = [1,0,1,0,1];
+	static bool[] bb = [1,0,1,1,0];
+
+	BitArray a; a.init(ba);
+	BitArray b; b.init(bb);
+
+	BitArray c = a - b;
+
+	assert(c[0] == 0);
+	assert(c[1] == 0);
+	assert(c[2] == 0);
+	assert(c[3] == 0);
+	assert(c[4] == 1);
+    }
+
+
+    /***************************************
+     * Support for operator &= bit arrays.
+     */
+    BitArray opAndAssign(BitArray e2)
+    in
+    {
+	assert(len == e2.length);
+    }
+    body
+    {
+	auto dim = this.dim();
+
+	for (size_t i = 0; i < dim; i++)
+	    ptr[i] &= e2.ptr[i];
+	return *this;
+    }
+
+    unittest
+    {
+	debug(bitarray) printf("BitArray.opAndAssign unittest\n");
+
+	static bool[] ba = [1,0,1,0,1];
+	static bool[] bb = [1,0,1,1,0];
+
+	BitArray a; a.init(ba);
+	BitArray b; b.init(bb);
+
+	a &= b;
+	assert(a[0] == 1);
+	assert(a[1] == 0);
+	assert(a[2] == 1);
+	assert(a[3] == 0);
+	assert(a[4] == 0);
+    }
+
+
+    /***************************************
+     * Support for operator |= for bit arrays.
+     */
+    BitArray opOrAssign(BitArray e2)
+    in
+    {
+	assert(len == e2.length);
+    }
+    body
+    {
+	auto dim = this.dim();
+
+	for (size_t i = 0; i < dim; i++)
+	    ptr[i] |= e2.ptr[i];
+	return *this;
+    }
+
+    unittest
+    {
+	debug(bitarray) printf("BitArray.opOrAssign unittest\n");
+
+	static bool[] ba = [1,0,1,0,1];
+	static bool[] bb = [1,0,1,1,0];
+
+	BitArray a; a.init(ba);
+	BitArray b; b.init(bb);
+
+	a |= b;
+	assert(a[0] == 1);
+	assert(a[1] == 0);
+	assert(a[2] == 1);
+	assert(a[3] == 1);
+	assert(a[4] == 1);
+    }
+
+    /***************************************
+     * Support for operator ^= for bit arrays.
+     */
+    BitArray opXorAssign(BitArray e2)
+    in
+    {
+	assert(len == e2.length);
+    }
+    body
+    {
+	auto dim = this.dim();
+
+	for (size_t i = 0; i < dim; i++)
+	    ptr[i] ^= e2.ptr[i];
+	return *this;
+    }
+
+    unittest
+    {
+	debug(bitarray) printf("BitArray.opXorAssign unittest\n");
+
+	static bool[] ba = [1,0,1,0,1];
+	static bool[] bb = [1,0,1,1,0];
+
+	BitArray a; a.init(ba);
+	BitArray b; b.init(bb);
+
+	a ^= b;
+	assert(a[0] == 0);
+	assert(a[1] == 0);
+	assert(a[2] == 0);
+	assert(a[3] == 1);
+	assert(a[4] == 1);
+    }
+
+    /***************************************
+     * Support for operator -= for bit arrays.
+     *
+     * $(I a -= b) for BitArrays means the same thing as $(I a &amp;= ~b).
+     */
+    BitArray opSubAssign(BitArray e2)
+    in
+    {
+	assert(len == e2.length);
+    }
+    body
+    {
+	auto dim = this.dim();
+
+	for (size_t i = 0; i < dim; i++)
+	    ptr[i] &= ~e2.ptr[i];
+	return *this;
+    }
+
+    unittest
+    {
+	debug(bitarray) printf("BitArray.opSubAssign unittest\n");
+
+	static bool[] ba = [1,0,1,0,1];
+	static bool[] bb = [1,0,1,1,0];
+
+	BitArray a; a.init(ba);
+	BitArray b; b.init(bb);
+
+	a -= b;
+	assert(a[0] == 0);
+	assert(a[1] == 0);
+	assert(a[2] == 0);
+	assert(a[3] == 0);
+	assert(a[4] == 1);
+    }
+
+    /***************************************
+     * Support for operator ~= for bit arrays.
+     */
+
+    BitArray opCatAssign(bool b)
+    {
+	length = len + 1;
+	(*this)[len - 1] = b;
+	return *this;
+    }
+
+    unittest
+    {
+	debug(bitarray) printf("BitArray.opCatAssign unittest\n");
+
+	static bool[] ba = [1,0,1,0,1];
+
+	BitArray a; a.init(ba);
+	BitArray b;
+
+	b = (a ~= true);
+	assert(a[0] == 1);
+	assert(a[1] == 0);
+	assert(a[2] == 1);
+	assert(a[3] == 0);
+	assert(a[4] == 1);
+	assert(a[5] == 1);
+
+	assert(b == a);
+    }
+
+    /***************************************
+     * ditto
+     */
+
+    BitArray opCatAssign(BitArray b)
+    {
+	auto istart = len;
+	length = len + b.length;
+	for (auto i = istart; i < len; i++)
+	    (*this)[i] = b[i - istart];
+	return *this;
+    }
+
+    unittest
+    {
+	debug(bitarray) printf("BitArray.opCatAssign unittest\n");
+
+	static bool[] ba = [1,0];
+	static bool[] bb = [0,1,0];
+
+	BitArray a; a.init(ba);
+	BitArray b; b.init(bb);
+	BitArray c;
+
+	c = (a ~= b);
+	assert(a.length == 5);
+	assert(a[0] == 1);
+	assert(a[1] == 0);
+	assert(a[2] == 0);
+	assert(a[3] == 1);
+	assert(a[4] == 0);
+
+	assert(c == a);
+    }
+
+    /***************************************
+     * Support for binary operator ~ for bit arrays.
+     */
+    BitArray opCat(bool b)
+    {
+	BitArray r;
+
+	r = this.dup;
+	r.length = len + 1;
+	r[len] = b;
+	return r;
+    }
+
+    /** ditto */
+    BitArray opCat_r(bool b)
+    {
+	BitArray r;
+
+	r.length = len + 1;
+	r[0] = b;
+	for (size_t i = 0; i < len; i++)
+	    r[1 + i] = (*this)[i];
+	return r;
+    }
+
+    /** ditto */
+    BitArray opCat(BitArray b)
+    {
+	BitArray r;
+
+	r = this.dup();
+	r ~= b;
+	return r;
+    }
+
+    unittest
+    {
+	debug(bitarray) printf("BitArray.opCat unittest\n");
+
+	static bool[] ba = [1,0];
+	static bool[] bb = [0,1,0];
+
+	BitArray a; a.init(ba);
+	BitArray b; b.init(bb);
+	BitArray c;
+
+	c = (a ~ b);
+	assert(c.length == 5);
+	assert(c[0] == 1);
+	assert(c[1] == 0);
+	assert(c[2] == 0);
+	assert(c[3] == 1);
+	assert(c[4] == 0);
+
+	c = (a ~ true);
+	assert(c.length == 3);
+	assert(c[0] == 1);
+	assert(c[1] == 0);
+	assert(c[2] == 1);
+
+	c = (false ~ a);
+	assert(c.length == 3);
+	assert(c[0] == 0);
+	assert(c[1] == 1);
+	assert(c[2] == 0);
+    }
+}
--- a/lphobos/std/c/stdarg.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/std/c/stdarg.d	Mon Aug 04 19:28:49 2008 +0200
@@ -13,14 +13,14 @@
 
 public import llvm.va_list;
 
-pragma(LLVM_internal, "va_start")
+pragma(va_start)
     void va_start(T)(va_list ap, ref T);
 
-pragma(LLVM_internal, "va_arg")
+pragma(va_arg)
     T va_arg(T)(va_list ap);
 
-pragma(LLVM_internal, "va_intrinsic", "llvm.va_end")
+pragma(va_end)
     void va_end(va_list args);
 
-pragma(LLVM_internal, "va_intrinsic", "llvm.va_copy")
+pragma(va_copy)
     void va_copy(va_list dst, va_list src);
--- a/lphobos/std/c/stdlib.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/std/c/stdlib.d	Mon Aug 04 19:28:49 2008 +0200
@@ -42,7 +42,7 @@
 
     int system(char *);
 
-    pragma(LLVM_internal, "alloca")
+    pragma(alloca)
     void *alloca(uint);	///
 
     void *calloc(size_t, size_t);	///
@@ -64,8 +64,11 @@
     int    random(int num);	/// ditto
     void   randomize();	/// ditto
 
-    int getErrno();	/// ditto
-    int setErrno(int);	/// ditto
+    int* __errno_location();
+    int getErrno() { return *__errno_location(); }
+    int setErrno(int i) { return *__errno_location = i; }
+    //int getErrno();	/// ditto
+    //int setErrno(int);	/// ditto
 
 const int ERANGE = 34;	// on both Windows and linux
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/c/windows/com.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,246 @@
+
+module std.c.windows.com;
+
+private import std.c.windows.windows;
+private import std.string;
+
+alias WCHAR OLECHAR;
+alias OLECHAR *LPOLESTR;
+alias OLECHAR *LPCOLESTR;
+
+enum
+{
+	rmm = 23,	// OLE 2 version number info
+	rup = 639,
+}
+
+enum : int
+{
+	S_OK = 0,
+	S_FALSE = 0x00000001,
+	NOERROR = 0,
+	E_NOTIMPL     = cast(int)0x80004001,
+	E_NOINTERFACE = cast(int)0x80004002,
+	E_POINTER     = cast(int)0x80004003,
+	E_ABORT       = cast(int)0x80004004,
+	E_FAIL        = cast(int)0x80004005,
+	E_HANDLE      = cast(int)0x80070006,
+	CLASS_E_NOAGGREGATION = cast(int)0x80040110,
+	E_OUTOFMEMORY = cast(int)0x8007000E,
+	E_INVALIDARG  = cast(int)0x80070057,
+	E_UNEXPECTED  = cast(int)0x8000FFFF,
+}
+
+struct GUID {          // size is 16
+    align(1):
+	DWORD Data1;
+	WORD  Data2;
+	WORD  Data3;
+	BYTE  Data4[8];
+}
+
+enum
+{
+	CLSCTX_INPROC_SERVER	= 0x1,
+	CLSCTX_INPROC_HANDLER	= 0x2,
+	CLSCTX_LOCAL_SERVER	= 0x4,
+	CLSCTX_INPROC_SERVER16	= 0x8,
+	CLSCTX_REMOTE_SERVER	= 0x10,
+	CLSCTX_INPROC_HANDLER16	= 0x20,
+	CLSCTX_INPROC_SERVERX86	= 0x40,
+	CLSCTX_INPROC_HANDLERX86 = 0x80,
+
+	CLSCTX_INPROC = (CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER),
+	CLSCTX_ALL = (CLSCTX_INPROC_SERVER| CLSCTX_INPROC_HANDLER| CLSCTX_LOCAL_SERVER),
+	CLSCTX_SERVER = (CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER),
+}
+
+alias GUID IID;
+alias GUID CLSID;
+
+extern (C)
+{
+    extern IID IID_IUnknown;
+    extern IID IID_IClassFactory;
+    extern IID IID_IMarshal;
+    extern IID IID_IMallocSpy;
+    extern IID IID_IStdMarshalInfo;
+    extern IID IID_IExternalConnection;
+    extern IID IID_IMultiQI;
+    extern IID IID_IEnumUnknown;
+    extern IID IID_IBindCtx;
+    extern IID IID_IEnumMoniker;
+    extern IID IID_IRunnableObject;
+    extern IID IID_IRunningObjectTable;
+    extern IID IID_IPersist;
+    extern IID IID_IPersistStream;
+    extern IID IID_IMoniker;
+    extern IID IID_IROTData;
+    extern IID IID_IEnumString;
+    extern IID IID_ISequentialStream;
+    extern IID IID_IStream;
+    extern IID IID_IEnumSTATSTG;
+    extern IID IID_IStorage;
+    extern IID IID_IPersistFile;
+    extern IID IID_IPersistStorage;
+    extern IID IID_ILockBytes;
+    extern IID IID_IEnumFORMATETC;
+    extern IID IID_IEnumSTATDATA;
+    extern IID IID_IRootStorage;
+    extern IID IID_IAdviseSink;
+    extern IID IID_IAdviseSink2;
+    extern IID IID_IDataObject;
+    extern IID IID_IDataAdviseHolder;
+    extern IID IID_IMessageFilter;
+    extern IID IID_IRpcChannelBuffer;
+    extern IID IID_IRpcProxyBuffer;
+    extern IID IID_IRpcStubBuffer;
+    extern IID IID_IPSFactoryBuffer;
+    extern IID IID_IPropertyStorage;
+    extern IID IID_IPropertySetStorage;
+    extern IID IID_IEnumSTATPROPSTG;
+    extern IID IID_IEnumSTATPROPSETSTG;
+    extern IID IID_IFillLockBytes;
+    extern IID IID_IProgressNotify;
+    extern IID IID_ILayoutStorage;
+    extern IID GUID_NULL;
+    extern IID IID_IRpcChannel;
+    extern IID IID_IRpcStub;
+    extern IID IID_IStubManager;
+    extern IID IID_IRpcProxy;
+    extern IID IID_IProxyManager;
+    extern IID IID_IPSFactory;
+    extern IID IID_IInternalMoniker;
+    extern IID IID_IDfReserved1;
+    extern IID IID_IDfReserved2;
+    extern IID IID_IDfReserved3;
+    extern IID IID_IStub;
+    extern IID IID_IProxy;
+    extern IID IID_IEnumGeneric;
+    extern IID IID_IEnumHolder;
+    extern IID IID_IEnumCallback;
+    extern IID IID_IOleManager;
+    extern IID IID_IOlePresObj;
+    extern IID IID_IDebug;
+    extern IID IID_IDebugStream;
+    extern IID IID_StdOle;
+    extern IID IID_ICreateTypeInfo;
+    extern IID IID_ICreateTypeInfo2;
+    extern IID IID_ICreateTypeLib;
+    extern IID IID_ICreateTypeLib2;
+    extern IID IID_IDispatch;
+    extern IID IID_IEnumVARIANT;
+    extern IID IID_ITypeComp;
+    extern IID IID_ITypeInfo;
+    extern IID IID_ITypeInfo2;
+    extern IID IID_ITypeLib;
+    extern IID IID_ITypeLib2;
+    extern IID IID_ITypeChangeEvents;
+    extern IID IID_IErrorInfo;
+    extern IID IID_ICreateErrorInfo;
+    extern IID IID_ISupportErrorInfo;
+    extern IID IID_IOleAdviseHolder;
+    extern IID IID_IOleCache;
+    extern IID IID_IOleCache2;
+    extern IID IID_IOleCacheControl;
+    extern IID IID_IParseDisplayName;
+    extern IID IID_IOleContainer;
+    extern IID IID_IOleClientSite;
+    extern IID IID_IOleObject;
+    extern IID IID_IOleWindow;
+    extern IID IID_IOleLink;
+    extern IID IID_IOleItemContainer;
+    extern IID IID_IOleInPlaceUIWindow;
+    extern IID IID_IOleInPlaceActiveObject;
+    extern IID IID_IOleInPlaceFrame;
+    extern IID IID_IOleInPlaceObject;
+    extern IID IID_IOleInPlaceSite;
+    extern IID IID_IContinue;
+    extern IID IID_IViewObject;
+    extern IID IID_IViewObject2;
+    extern IID IID_IDropSource;
+    extern IID IID_IDropTarget;
+    extern IID IID_IEnumOLEVERB;
+}
+
+extern (Windows)
+{
+
+export
+{
+DWORD   CoBuildVersion();
+
+int StringFromGUID2(GUID *rguid, LPOLESTR lpsz, int cbMax);
+
+/* init/uninit */
+
+HRESULT CoInitialize(LPVOID pvReserved);
+void    CoUninitialize();
+DWORD   CoGetCurrentProcess();
+
+
+HRESULT CoCreateInstance(CLSID *rclsid, IUnknown UnkOuter,
+                    DWORD dwClsContext, IID* riid, void* ppv);
+
+//HINSTANCE CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree);
+void    CoFreeLibrary(HINSTANCE hInst);
+void    CoFreeAllLibraries();
+void    CoFreeUnusedLibraries();
+}
+
+interface IUnknown
+{
+    HRESULT QueryInterface(IID* riid, void** pvObject);
+    ULONG AddRef();
+    ULONG Release();
+}
+
+interface IClassFactory : IUnknown
+{
+    HRESULT CreateInstance(IUnknown UnkOuter, IID* riid, void** pvObject);
+    HRESULT LockServer(BOOL fLock);
+}
+
+class ComObject : IUnknown
+{
+extern (Windows):
+    HRESULT QueryInterface(IID* riid, void** ppv)
+    {
+	if (*riid == IID_IUnknown)
+	{
+	    *ppv = cast(void*)cast(IUnknown)this;
+	    AddRef();
+	    return S_OK;
+	}
+	else
+	{   *ppv = null;
+	    return E_NOINTERFACE;
+	}
+    }
+
+    ULONG AddRef()
+    {
+	return InterlockedIncrement(&count);
+    }
+
+    ULONG Release()
+    {
+	LONG lRef = InterlockedDecrement(&count);
+	if (lRef == 0)
+	{
+	    // free object
+
+	    // If we delete this object, then the postinvariant called upon
+	    // return from Release() will fail.
+	    // Just let the GC reap it.
+	    //delete this;
+
+	    return 0;
+	}
+	return cast(ULONG)lRef;
+    }
+
+    LONG count = 0;		// object reference count
+}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/c/windows/stat.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,49 @@
+
+/// Placed into public domain
+/// Author: Walter Bright
+
+module std.c.windows.stat;
+
+extern (C):
+
+// linux version is in std.c.linux.linux
+
+version (Windows)
+{
+const S_IFMT   = 0xF000;
+const S_IFDIR  = 0x4000;
+const S_IFCHR  = 0x2000;
+const S_IFIFO  = 0x1000;
+const S_IFREG  = 0x8000;
+const S_IREAD  = 0x0100;
+const S_IWRITE = 0x0080;
+const S_IEXEC  = 0x0040;
+const S_IFBLK  = 0x6000;
+const S_IFNAM  = 0x5000;
+
+int S_ISREG(int m)  { return (m & S_IFMT) == S_IFREG; }
+int S_ISBLK(int m)  { return (m & S_IFMT) == S_IFBLK; }
+int S_ISNAM(int m)  { return (m & S_IFMT) == S_IFNAM; }
+int S_ISDIR(int m)  { return (m & S_IFMT) == S_IFDIR; }
+int S_ISCHR(int m)  { return (m & S_IFMT) == S_IFCHR; }
+
+struct struct_stat
+{
+    short st_dev;
+    ushort st_ino;
+    ushort st_mode;
+    short st_nlink;
+    ushort st_uid;
+    ushort st_gid;
+    short st_rdev;
+    short dummy;
+    int st_size;
+    int st_atime;
+    int st_mtime;
+    int st_ctime;
+}
+
+int  stat(char *, struct_stat *);
+int  fstat(int, struct_stat *);
+int  _wstat(wchar *, struct_stat *);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/c/windows/windows.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,2722 @@
+
+/* Windows is a registered trademark of Microsoft Corporation in the United
+States and other countries. */
+
+module std.c.windows.windows;
+
+version (Windows)
+{
+}
+else
+{
+    static assert(0);		// Windows only
+}
+
+extern (Windows)
+{
+    alias uint ULONG;
+    alias ULONG *PULONG;
+    alias ushort USHORT;
+    alias USHORT *PUSHORT;
+    alias ubyte UCHAR;
+    alias UCHAR *PUCHAR;
+    alias char *PSZ;
+    alias wchar WCHAR;
+
+    alias void VOID;
+    alias char CHAR;
+    alias short SHORT;
+    alias int LONG;
+    alias CHAR *LPSTR;
+    alias CHAR *PSTR;
+    alias CHAR *LPCSTR;
+    alias CHAR *PCSTR;
+    alias LPSTR LPTCH, PTCH;
+    alias LPSTR PTSTR, LPTSTR;
+    alias LPCSTR LPCTSTR;
+
+    alias WCHAR* LPWSTR, LPCWSTR, PCWSTR;
+
+    alias uint DWORD;
+    alias int BOOL;
+    alias ubyte BYTE;
+    alias ushort WORD;
+    alias float FLOAT;
+    alias FLOAT *PFLOAT;
+    alias BOOL *PBOOL;
+    alias BOOL *LPBOOL;
+    alias BYTE *PBYTE;
+    alias BYTE *LPBYTE;
+    alias int *PINT;
+    alias int *LPINT;
+    alias WORD *PWORD;
+    alias WORD *LPWORD;
+    alias int *LPLONG;
+    alias DWORD *PDWORD;
+    alias DWORD *LPDWORD;
+    alias void *LPVOID;
+    alias void *LPCVOID;
+
+    alias int INT;
+    alias uint UINT;
+    alias uint *PUINT;
+
+    typedef void *HANDLE;
+    alias void *PVOID;
+    alias HANDLE HGLOBAL;
+    alias HANDLE HLOCAL;
+    alias LONG HRESULT;
+    alias LONG SCODE;
+    alias HANDLE HINSTANCE;
+    alias HINSTANCE HMODULE;
+    alias HANDLE HWND;
+
+    alias HANDLE HGDIOBJ;
+    alias HANDLE HACCEL;
+    alias HANDLE HBITMAP;
+    alias HANDLE HBRUSH;
+    alias HANDLE HCOLORSPACE;
+    alias HANDLE HDC;
+    alias HANDLE HGLRC;
+    alias HANDLE HDESK;
+    alias HANDLE HENHMETAFILE;
+    alias HANDLE HFONT;
+    alias HANDLE HICON;
+    alias HANDLE HMENU;
+    alias HANDLE HMETAFILE;
+    alias HANDLE HPALETTE;
+    alias HANDLE HPEN;
+    alias HANDLE HRGN;
+    alias HANDLE HRSRC;
+    alias HANDLE HSTR;
+    alias HANDLE HTASK;
+    alias HANDLE HWINSTA;
+    alias HANDLE HKL;
+    alias HICON HCURSOR;
+
+    alias HANDLE HKEY;
+    alias HKEY *PHKEY;
+    alias DWORD ACCESS_MASK;
+    alias ACCESS_MASK *PACCESS_MASK;
+    alias ACCESS_MASK REGSAM;
+
+    alias int (*FARPROC)();
+
+    alias UINT WPARAM;
+    alias LONG LPARAM;
+    alias LONG LRESULT;
+
+    alias DWORD   COLORREF;
+    alias DWORD   *LPCOLORREF;
+    alias WORD    ATOM;
+
+version (0)
+{   // Properly prototyped versions
+    alias BOOL function(HWND, UINT, WPARAM, LPARAM) DLGPROC;
+    alias VOID function(HWND, UINT, UINT, DWORD) TIMERPROC;
+    alias BOOL function(HDC, LPARAM, int) GRAYSTRINGPROC;
+    alias BOOL function(HWND, LPARAM) WNDENUMPROC;
+    alias LRESULT function(int code, WPARAM wParam, LPARAM lParam) HOOKPROC;
+    alias VOID function(HWND, UINT, DWORD, LRESULT) SENDASYNCPROC;
+    alias BOOL function(HWND, LPCSTR, HANDLE) PROPENUMPROCA;
+    alias BOOL function(HWND, LPCWSTR, HANDLE) PROPENUMPROCW;
+    alias BOOL function(HWND, LPSTR, HANDLE, DWORD) PROPENUMPROCEXA;
+    alias BOOL function(HWND, LPWSTR, HANDLE, DWORD) PROPENUMPROCEXW;
+    alias int function(LPSTR lpch, int ichCurrent, int cch, int code)
+       EDITWORDBREAKPROCA;
+    alias int function(LPWSTR lpch, int ichCurrent, int cch, int code)
+       EDITWORDBREAKPROCW;
+    alias BOOL function(HDC hdc, LPARAM lData, WPARAM wData, int cx, int cy)
+       DRAWSTATEPROC;
+}
+else
+{
+    alias FARPROC DLGPROC;
+    alias FARPROC TIMERPROC;
+    alias FARPROC GRAYSTRINGPROC;
+    alias FARPROC WNDENUMPROC;
+    alias FARPROC HOOKPROC;
+    alias FARPROC SENDASYNCPROC;
+    alias FARPROC EDITWORDBREAKPROCA;
+    alias FARPROC EDITWORDBREAKPROCW;
+    alias FARPROC PROPENUMPROCA;
+    alias FARPROC PROPENUMPROCW;
+    alias FARPROC PROPENUMPROCEXA;
+    alias FARPROC PROPENUMPROCEXW;
+    alias FARPROC DRAWSTATEPROC;
+}
+
+WORD HIWORD(int l) { return cast(WORD)((l >> 16) & 0xFFFF); }
+WORD LOWORD(int l) { return cast(WORD)l; }
+bool FAILED(int status) { return status < 0; }
+bool SUCCEEDED(int Status) { return Status >= 0; }
+
+enum : int
+{
+    FALSE = 0,
+    TRUE = 1,
+}
+
+enum : uint
+{
+    MAX_PATH = 260,
+    HINSTANCE_ERROR = 32,
+}
+
+enum
+{
+	ERROR_SUCCESS =                    0,
+	ERROR_INVALID_FUNCTION =           1,
+	ERROR_FILE_NOT_FOUND =             2,
+	ERROR_PATH_NOT_FOUND =             3,
+	ERROR_TOO_MANY_OPEN_FILES =        4,
+	ERROR_ACCESS_DENIED =              5,
+	ERROR_INVALID_HANDLE =             6,
+	ERROR_NO_MORE_FILES =              18,
+	ERROR_MORE_DATA =		   234,
+	ERROR_NO_MORE_ITEMS =		   259,
+}
+
+enum
+{
+	DLL_PROCESS_ATTACH = 1,
+	DLL_THREAD_ATTACH =  2,
+	DLL_THREAD_DETACH =  3,
+	DLL_PROCESS_DETACH = 0,
+}
+
+enum
+{
+    FILE_BEGIN           = 0,
+    FILE_CURRENT         = 1,
+    FILE_END             = 2,
+}
+
+enum : uint
+{
+    DELETE =                           0x00010000,
+    READ_CONTROL =                     0x00020000,
+    WRITE_DAC =                        0x00040000,
+    WRITE_OWNER =                      0x00080000,
+    SYNCHRONIZE =                      0x00100000,
+
+    STANDARD_RIGHTS_REQUIRED =         0x000F0000,
+    STANDARD_RIGHTS_READ =             READ_CONTROL,
+    STANDARD_RIGHTS_WRITE =            READ_CONTROL,
+    STANDARD_RIGHTS_EXECUTE =          READ_CONTROL,
+    STANDARD_RIGHTS_ALL =              0x001F0000,
+    SPECIFIC_RIGHTS_ALL =              0x0000FFFF,
+    ACCESS_SYSTEM_SECURITY =           0x01000000,
+    MAXIMUM_ALLOWED =                  0x02000000,
+
+    GENERIC_READ                     = 0x80000000,
+    GENERIC_WRITE                    = 0x40000000,
+    GENERIC_EXECUTE                  = 0x20000000,
+    GENERIC_ALL                      = 0x10000000,
+}
+
+enum
+{
+    FILE_SHARE_READ                 = 0x00000001,
+    FILE_SHARE_WRITE                = 0x00000002,
+    FILE_SHARE_DELETE               = 0x00000004,  
+    FILE_ATTRIBUTE_READONLY         = 0x00000001,  
+    FILE_ATTRIBUTE_HIDDEN           = 0x00000002,  
+    FILE_ATTRIBUTE_SYSTEM           = 0x00000004,  
+    FILE_ATTRIBUTE_DIRECTORY        = 0x00000010,  
+    FILE_ATTRIBUTE_ARCHIVE          = 0x00000020,  
+    FILE_ATTRIBUTE_NORMAL           = 0x00000080,  
+    FILE_ATTRIBUTE_TEMPORARY        = 0x00000100,  
+    FILE_ATTRIBUTE_COMPRESSED       = 0x00000800,  
+    FILE_ATTRIBUTE_OFFLINE          = 0x00001000,  
+    FILE_NOTIFY_CHANGE_FILE_NAME    = 0x00000001,   
+    FILE_NOTIFY_CHANGE_DIR_NAME     = 0x00000002,   
+    FILE_NOTIFY_CHANGE_ATTRIBUTES   = 0x00000004,   
+    FILE_NOTIFY_CHANGE_SIZE         = 0x00000008,   
+    FILE_NOTIFY_CHANGE_LAST_WRITE   = 0x00000010,   
+    FILE_NOTIFY_CHANGE_LAST_ACCESS  = 0x00000020,   
+    FILE_NOTIFY_CHANGE_CREATION     = 0x00000040,   
+    FILE_NOTIFY_CHANGE_SECURITY     = 0x00000100,   
+    FILE_ACTION_ADDED               = 0x00000001,   
+    FILE_ACTION_REMOVED             = 0x00000002,   
+    FILE_ACTION_MODIFIED            = 0x00000003,   
+    FILE_ACTION_RENAMED_OLD_NAME    = 0x00000004,   
+    FILE_ACTION_RENAMED_NEW_NAME    = 0x00000005,   
+    FILE_CASE_SENSITIVE_SEARCH      = 0x00000001,  
+    FILE_CASE_PRESERVED_NAMES       = 0x00000002,  
+    FILE_UNICODE_ON_DISK            = 0x00000004,  
+    FILE_PERSISTENT_ACLS            = 0x00000008,  
+    FILE_FILE_COMPRESSION           = 0x00000010,  
+    FILE_VOLUME_IS_COMPRESSED       = 0x00008000,  
+}
+
+const DWORD MAILSLOT_NO_MESSAGE = cast(DWORD)-1;
+const DWORD MAILSLOT_WAIT_FOREVER = cast(DWORD)-1; 
+
+enum : uint
+{
+    FILE_FLAG_WRITE_THROUGH         = 0x80000000,
+    FILE_FLAG_OVERLAPPED            = 0x40000000,
+    FILE_FLAG_NO_BUFFERING          = 0x20000000,
+    FILE_FLAG_RANDOM_ACCESS         = 0x10000000,
+    FILE_FLAG_SEQUENTIAL_SCAN       = 0x08000000,
+    FILE_FLAG_DELETE_ON_CLOSE       = 0x04000000,
+    FILE_FLAG_BACKUP_SEMANTICS      = 0x02000000,
+    FILE_FLAG_POSIX_SEMANTICS       = 0x01000000,
+}
+
+enum
+{
+    CREATE_NEW          = 1,
+    CREATE_ALWAYS       = 2,
+    OPEN_EXISTING       = 3,
+    OPEN_ALWAYS         = 4,
+    TRUNCATE_EXISTING   = 5,
+}
+
+const HANDLE INVALID_HANDLE_VALUE = cast(HANDLE)-1;
+const DWORD INVALID_SET_FILE_POINTER = cast(DWORD)-1;
+const DWORD INVALID_FILE_SIZE = cast(DWORD)0xFFFFFFFF;
+
+struct OVERLAPPED {
+    DWORD   Internal;
+    DWORD   InternalHigh;
+    DWORD   Offset;
+    DWORD   OffsetHigh;
+    HANDLE  hEvent;
+}
+
+struct SECURITY_ATTRIBUTES {
+    DWORD nLength;
+    void *lpSecurityDescriptor;
+    BOOL bInheritHandle;
+}
+
+alias SECURITY_ATTRIBUTES* PSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES;
+
+struct FILETIME {
+    DWORD dwLowDateTime;
+    DWORD dwHighDateTime;
+}
+alias FILETIME* PFILETIME, LPFILETIME;
+
+struct WIN32_FIND_DATA {
+    DWORD dwFileAttributes;
+    FILETIME ftCreationTime;
+    FILETIME ftLastAccessTime;
+    FILETIME ftLastWriteTime;
+    DWORD nFileSizeHigh;
+    DWORD nFileSizeLow;
+    DWORD dwReserved0;
+    DWORD dwReserved1;
+    char   cFileName[MAX_PATH];
+    char   cAlternateFileName[ 14 ];
+}
+
+struct WIN32_FIND_DATAW {
+    DWORD dwFileAttributes;
+    FILETIME ftCreationTime;
+    FILETIME ftLastAccessTime;
+    FILETIME ftLastWriteTime;
+    DWORD nFileSizeHigh;
+    DWORD nFileSizeLow;
+    DWORD dwReserved0;
+    DWORD dwReserved1;
+    wchar  cFileName[ 260  ];
+    wchar  cAlternateFileName[ 14 ];
+}
+
+export
+{
+BOOL SetCurrentDirectoryA(LPCSTR lpPathName);
+BOOL SetCurrentDirectoryW(LPCWSTR lpPathName);
+DWORD GetCurrentDirectoryA(DWORD nBufferLength, LPSTR lpBuffer);
+DWORD GetCurrentDirectoryW(DWORD nBufferLength, LPWSTR lpBuffer);
+BOOL CreateDirectoryA(LPCSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes);
+BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes);
+BOOL CreateDirectoryExA(LPCSTR lpTemplateDirectory, LPCSTR lpNewDirectory, LPSECURITY_ATTRIBUTES lpSecurityAttributes);
+BOOL CreateDirectoryExW(LPCWSTR lpTemplateDirectory, LPCWSTR lpNewDirectory, LPSECURITY_ATTRIBUTES lpSecurityAttributes);
+BOOL RemoveDirectoryA(LPCSTR lpPathName);
+BOOL RemoveDirectoryW(LPCWSTR lpPathName);
+
+BOOL   CloseHandle(HANDLE hObject);
+
+HANDLE CreateFileA(char *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
+	SECURITY_ATTRIBUTES *lpSecurityAttributes, DWORD dwCreationDisposition,
+	DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
+HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
+	SECURITY_ATTRIBUTES *lpSecurityAttributes, DWORD dwCreationDisposition,
+	DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
+
+BOOL   DeleteFileA(char *lpFileName);
+BOOL   DeleteFileW(LPCWSTR lpFileName);
+
+BOOL   FindClose(HANDLE hFindFile);
+HANDLE FindFirstFileA(char *lpFileName, WIN32_FIND_DATA* lpFindFileData);
+HANDLE FindFirstFileW(LPCWSTR lpFileName, WIN32_FIND_DATAW* lpFindFileData);
+BOOL   FindNextFileA(HANDLE hFindFile, WIN32_FIND_DATA* lpFindFileData);
+BOOL   FindNextFileW(HANDLE hFindFile, WIN32_FIND_DATAW* lpFindFileData);
+BOOL   GetExitCodeThread(HANDLE hThread, DWORD *lpExitCode);
+DWORD  GetLastError();
+DWORD  GetFileAttributesA(char *lpFileName);
+DWORD  GetFileAttributesW(wchar *lpFileName);
+DWORD  GetFileSize(HANDLE hFile, DWORD *lpFileSizeHigh);
+BOOL   CopyFileA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, BOOL bFailIfExists);
+BOOL   CopyFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, BOOL bFailIfExists);
+BOOL   MoveFileA(char *from, char *to);
+BOOL   MoveFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName);
+BOOL   ReadFile(HANDLE hFile, void *lpBuffer, DWORD nNumberOfBytesToRead,
+	DWORD *lpNumberOfBytesRead, OVERLAPPED *lpOverlapped);
+DWORD  SetFilePointer(HANDLE hFile, LONG lDistanceToMove,
+	LONG *lpDistanceToMoveHigh, DWORD dwMoveMethod);
+BOOL   WriteFile(HANDLE hFile, void *lpBuffer, DWORD nNumberOfBytesToWrite,
+	DWORD *lpNumberOfBytesWritten, OVERLAPPED *lpOverlapped);
+DWORD  GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize);
+}
+
+struct MEMORYSTATUS {
+    DWORD dwLength;
+    DWORD dwMemoryLoad;
+    DWORD dwTotalPhys;
+    DWORD dwAvailPhys;
+    DWORD dwTotalPageFile;
+    DWORD dwAvailPageFile;
+    DWORD dwTotalVirtual;
+    DWORD dwAvailVirtual;
+};
+alias MEMORYSTATUS *LPMEMORYSTATUS;
+
+
+export
+{
+ LONG  InterlockedIncrement(LPLONG lpAddend);
+ LONG  InterlockedDecrement(LPLONG lpAddend);
+ LONG  InterlockedExchange(LPLONG Target, LONG Value);
+ LONG  InterlockedExchangeAdd(LPLONG Addend, LONG Value);
+ PVOID InterlockedCompareExchange(PVOID *Destination, PVOID Exchange, PVOID Comperand);
+ BOOL  FreeResource(HGLOBAL hResData);
+ LPVOID LockResource(HGLOBAL hResData);
+}
+
+HMODULE LoadLibraryA(LPCSTR lpLibFileName);
+FARPROC GetProcAddress(HMODULE hModule, LPCSTR lpProcName);
+DWORD GetVersion();
+BOOL FreeLibrary(HMODULE hLibModule);
+void FreeLibraryAndExitThread(HMODULE hLibModule, DWORD dwExitCode);
+BOOL DisableThreadLibraryCalls(HMODULE hLibModule);
+
+//
+// Registry Specific Access Rights.
+//
+
+enum
+{
+	KEY_QUERY_VALUE =         0x0001,
+	KEY_SET_VALUE =           0x0002,
+	KEY_CREATE_SUB_KEY =      0x0004,
+	KEY_ENUMERATE_SUB_KEYS =  0x0008,
+	KEY_NOTIFY =              0x0010,
+	KEY_CREATE_LINK =         0x0020,
+
+	KEY_READ =       cast(int)((STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY)   & ~SYNCHRONIZE),
+	KEY_WRITE =      cast(int)((STANDARD_RIGHTS_WRITE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY) & ~SYNCHRONIZE),
+	KEY_EXECUTE =    cast(int)(KEY_READ & ~SYNCHRONIZE),
+	KEY_ALL_ACCESS = cast(int)((STANDARD_RIGHTS_ALL | KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY | KEY_CREATE_LINK) & ~SYNCHRONIZE),
+}
+
+//
+// Key creation/open disposition
+//
+
+const int REG_CREATED_NEW_KEY =         0x00000001;   // New Registry Key created
+const int REG_OPENED_EXISTING_KEY =     0x00000002;   // Existing Key opened
+
+
+//
+//
+// Predefined Value Types.
+//
+enum
+{
+	REG_NONE =                    0,   // No value type
+	REG_SZ =                      1,   // Unicode nul terminated string
+	REG_EXPAND_SZ =               2,   // Unicode nul terminated string
+                                            // (with environment variable references)
+	REG_BINARY =                  3,   // Free form binary
+	REG_DWORD =                   4,   // 32-bit number
+	REG_DWORD_LITTLE_ENDIAN =     4,   // 32-bit number (same as REG_DWORD)
+	REG_DWORD_BIG_ENDIAN =        5,   // 32-bit number
+	REG_LINK =                    6,   // Symbolic Link (unicode)
+	REG_MULTI_SZ =                7,   // Multiple Unicode strings
+	REG_RESOURCE_LIST =           8,   // Resource list in the resource map
+	REG_FULL_RESOURCE_DESCRIPTOR = 9,  // Resource list in the hardware description
+	REG_RESOURCE_REQUIREMENTS_LIST = 10,
+	REG_QWORD =			11,
+	REG_QWORD_LITTLE_ENDIAN =	11,
+}
+
+/*
+ * MessageBox() Flags
+ */
+enum
+{
+	MB_OK =                       0x00000000,
+	MB_OKCANCEL =                 0x00000001,
+	MB_ABORTRETRYIGNORE =         0x00000002,
+	MB_YESNOCANCEL =              0x00000003,
+	MB_YESNO =                    0x00000004,
+	MB_RETRYCANCEL =              0x00000005,
+
+
+	MB_ICONHAND =                 0x00000010,
+	MB_ICONQUESTION =             0x00000020,
+	MB_ICONEXCLAMATION =          0x00000030,
+	MB_ICONASTERISK =             0x00000040,
+
+
+	MB_USERICON =                 0x00000080,
+	MB_ICONWARNING =              MB_ICONEXCLAMATION,
+	MB_ICONERROR =                MB_ICONHAND,
+
+
+	MB_ICONINFORMATION =          MB_ICONASTERISK,
+	MB_ICONSTOP =                 MB_ICONHAND,
+
+	MB_DEFBUTTON1 =               0x00000000,
+	MB_DEFBUTTON2 =               0x00000100,
+	MB_DEFBUTTON3 =               0x00000200,
+
+	MB_DEFBUTTON4 =               0x00000300,
+
+
+	MB_APPLMODAL =                0x00000000,
+	MB_SYSTEMMODAL =              0x00001000,
+	MB_TASKMODAL =                0x00002000,
+
+	MB_HELP =                     0x00004000, // Help Button
+
+
+	MB_NOFOCUS =                  0x00008000,
+	MB_SETFOREGROUND =            0x00010000,
+	MB_DEFAULT_DESKTOP_ONLY =     0x00020000,
+
+
+	MB_TOPMOST =                  0x00040000,
+	MB_RIGHT =                    0x00080000,
+	MB_RTLREADING =               0x00100000,
+
+
+	MB_TYPEMASK =                 0x0000000F,
+	MB_ICONMASK =                 0x000000F0,
+	MB_DEFMASK =                  0x00000F00,
+	MB_MODEMASK =                 0x00003000,
+	MB_MISCMASK =                 0x0000C000,
+}
+
+
+int MessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);
+int MessageBoxExA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType, WORD wLanguageId);
+
+const HKEY HKEY_CLASSES_ROOT =           cast(HKEY)(0x80000000);
+const HKEY HKEY_CURRENT_USER =           cast(HKEY)(0x80000001);
+const HKEY HKEY_LOCAL_MACHINE =          cast(HKEY)(0x80000002);
+const HKEY HKEY_USERS =                  cast(HKEY)(0x80000003);
+const HKEY HKEY_PERFORMANCE_DATA =       cast(HKEY)(0x80000004);
+const HKEY HKEY_PERFORMANCE_TEXT =       cast(HKEY)(0x80000050);
+const HKEY HKEY_PERFORMANCE_NLSTEXT =    cast(HKEY)(0x80000060);
+const HKEY HKEY_CURRENT_CONFIG =         cast(HKEY)(0x80000005);
+const HKEY HKEY_DYN_DATA =               cast(HKEY)(0x80000006);
+
+enum
+{
+	REG_OPTION_RESERVED =         (0x00000000),   // Parameter is reserved
+
+	REG_OPTION_NON_VOLATILE =     (0x00000000),   // Key is preserved
+                                                    // when system is rebooted
+
+	REG_OPTION_VOLATILE =         (0x00000001),   // Key is not preserved
+                                                    // when system is rebooted
+
+	REG_OPTION_CREATE_LINK =      (0x00000002),   // Created key is a
+                                                    // symbolic link
+
+	REG_OPTION_BACKUP_RESTORE =   (0x00000004),   // open for backup or restore
+                                                    // special access rules
+                                                    // privilege required
+
+	REG_OPTION_OPEN_LINK =        (0x00000008),   // Open symbolic link
+
+	REG_LEGAL_OPTION = (REG_OPTION_RESERVED | REG_OPTION_NON_VOLATILE | REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK | REG_OPTION_BACKUP_RESTORE | REG_OPTION_OPEN_LINK),
+}
+
+export LONG RegDeleteKeyA(HKEY hKey, LPCSTR lpSubKey);
+export LONG RegDeleteValueA(HKEY hKey, LPCSTR lpValueName);
+
+export LONG  RegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcbName, LPDWORD lpReserved, LPSTR lpClass, LPDWORD lpcbClass, FILETIME* lpftLastWriteTime);
+export LONG RegEnumValueA(HKEY hKey, DWORD dwIndex, LPSTR lpValueName, LPDWORD lpcbValueName, LPDWORD lpReserved,
+    LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData);
+
+export LONG RegCloseKey(HKEY hKey);
+export LONG RegFlushKey(HKEY hKey);
+
+export LONG RegOpenKeyA(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult);
+export LONG RegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult);
+
+export LONG RegQueryInfoKeyA(HKEY hKey, LPSTR lpClass, LPDWORD lpcbClass,
+    LPDWORD lpReserved, LPDWORD lpcSubKeys, LPDWORD lpcbMaxSubKeyLen, LPDWORD lpcbMaxClassLen,
+    LPDWORD lpcValues, LPDWORD lpcbMaxValueNameLen, LPDWORD lpcbMaxValueLen, LPDWORD lpcbSecurityDescriptor,
+    PFILETIME lpftLastWriteTime);
+
+export LONG RegQueryValueA(HKEY hKey, LPCSTR lpSubKey, LPSTR lpValue,
+    LPLONG lpcbValue);
+
+export LONG RegCreateKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass,
+   DWORD dwOptions, REGSAM samDesired, SECURITY_ATTRIBUTES* lpSecurityAttributes,
+    PHKEY phkResult, LPDWORD lpdwDisposition);
+
+export LONG RegSetValueExA(HKEY hKey, LPCSTR lpValueName, DWORD Reserved, DWORD dwType, BYTE* lpData, DWORD cbData);
+
+struct MEMORY_BASIC_INFORMATION {
+    PVOID BaseAddress;
+    PVOID AllocationBase;
+    DWORD AllocationProtect;
+    DWORD RegionSize;
+    DWORD State;
+    DWORD Protect;
+    DWORD Type;
+}
+alias MEMORY_BASIC_INFORMATION* PMEMORY_BASIC_INFORMATION;
+
+enum
+{
+	SECTION_QUERY       = 0x0001,
+	SECTION_MAP_WRITE   = 0x0002,
+	SECTION_MAP_READ    = 0x0004,
+	SECTION_MAP_EXECUTE = 0x0008,
+	SECTION_EXTEND_SIZE = 0x0010,
+
+	SECTION_ALL_ACCESS = cast(int)(STANDARD_RIGHTS_REQUIRED|SECTION_QUERY| SECTION_MAP_WRITE | SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_EXTEND_SIZE),
+	PAGE_NOACCESS          = 0x01,
+	PAGE_READONLY          = 0x02,
+	PAGE_READWRITE         = 0x04,
+	PAGE_WRITECOPY         = 0x08,
+	PAGE_EXECUTE           = 0x10,
+	PAGE_EXECUTE_READ      = 0x20,
+	PAGE_EXECUTE_READWRITE = 0x40,
+	PAGE_EXECUTE_WRITECOPY = 0x80,
+	PAGE_GUARD            = 0x100,
+	PAGE_NOCACHE          = 0x200,
+	MEM_COMMIT           = 0x1000,
+	MEM_RESERVE          = 0x2000,
+	MEM_DECOMMIT         = 0x4000,
+	MEM_RELEASE          = 0x8000,
+	MEM_FREE            = 0x10000,
+	MEM_PRIVATE         = 0x20000,
+	MEM_MAPPED          = 0x40000,
+	MEM_RESET           = 0x80000,
+	MEM_TOP_DOWN       = 0x100000,
+	SEC_FILE           = 0x800000,
+	SEC_IMAGE         = 0x1000000,
+	SEC_RESERVE       = 0x4000000,
+	SEC_COMMIT        = 0x8000000,
+	SEC_NOCACHE      = 0x10000000,
+	MEM_IMAGE        = SEC_IMAGE,
+}
+
+enum
+{
+	FILE_MAP_COPY =       SECTION_QUERY,
+	FILE_MAP_WRITE =      SECTION_MAP_WRITE,
+	FILE_MAP_READ =       SECTION_MAP_READ,
+	FILE_MAP_ALL_ACCESS = SECTION_ALL_ACCESS,
+}
+
+
+//
+// Define access rights to files and directories
+//
+
+//
+// The FILE_READ_DATA and FILE_WRITE_DATA constants are also defined in
+// devioctl.h as FILE_READ_ACCESS and FILE_WRITE_ACCESS. The values for these
+// constants *MUST* always be in sync.
+// The values are redefined in devioctl.h because they must be available to
+// both DOS and NT.
+//
+
+enum
+{
+	FILE_READ_DATA =            ( 0x0001 ),   // file & pipe
+	FILE_LIST_DIRECTORY =       ( 0x0001 ),    // directory
+
+	FILE_WRITE_DATA =           ( 0x0002 ),    // file & pipe
+	FILE_ADD_FILE =             ( 0x0002 ),    // directory
+
+	FILE_APPEND_DATA =          ( 0x0004 ),    // file
+	FILE_ADD_SUBDIRECTORY =     ( 0x0004 ),    // directory
+	FILE_CREATE_PIPE_INSTANCE = ( 0x0004 ),    // named pipe
+
+	FILE_READ_EA =              ( 0x0008 ),    // file & directory
+
+	FILE_WRITE_EA =             ( 0x0010 ),    // file & directory
+
+	FILE_EXECUTE =              ( 0x0020 ),    // file
+	FILE_TRAVERSE =             ( 0x0020 ),    // directory
+
+	FILE_DELETE_CHILD =         ( 0x0040 ),    // directory
+
+	FILE_READ_ATTRIBUTES =      ( 0x0080 ),    // all
+
+	FILE_WRITE_ATTRIBUTES =     ( 0x0100 ),    // all
+
+	FILE_ALL_ACCESS =	    cast(int)(STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF),
+
+	FILE_GENERIC_READ =         cast(int)(STANDARD_RIGHTS_READ  | FILE_READ_DATA |  FILE_READ_ATTRIBUTES |                 FILE_READ_EA |  SYNCHRONIZE),
+
+	FILE_GENERIC_WRITE =        cast(int)(STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA |  FILE_WRITE_ATTRIBUTES |                      FILE_WRITE_EA  |  FILE_APPEND_DATA |  SYNCHRONIZE),
+
+	FILE_GENERIC_EXECUTE =      cast(int)(STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES |                 FILE_EXECUTE |  SYNCHRONIZE),
+}
+
+export
+{
+ BOOL GlobalUnlock(HGLOBAL hMem);
+ HGLOBAL GlobalFree(HGLOBAL hMem);
+ UINT GlobalCompact(DWORD dwMinFree);
+ void GlobalFix(HGLOBAL hMem);
+ void GlobalUnfix(HGLOBAL hMem);
+ LPVOID GlobalWire(HGLOBAL hMem);
+ BOOL GlobalUnWire(HGLOBAL hMem);
+ void GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer);
+ HLOCAL LocalAlloc(UINT uFlags, UINT uBytes);
+ HLOCAL LocalReAlloc(HLOCAL hMem, UINT uBytes, UINT uFlags);
+ LPVOID LocalLock(HLOCAL hMem);
+ HLOCAL LocalHandle(LPCVOID pMem);
+ BOOL LocalUnlock(HLOCAL hMem);
+ UINT LocalSize(HLOCAL hMem);
+ UINT LocalFlags(HLOCAL hMem);
+ HLOCAL LocalFree(HLOCAL hMem);
+ UINT LocalShrink(HLOCAL hMem, UINT cbNewSize);
+ UINT LocalCompact(UINT uMinFree);
+ BOOL FlushInstructionCache(HANDLE hProcess, LPCVOID lpBaseAddress, DWORD dwSize);
+ LPVOID VirtualAlloc(LPVOID lpAddress, DWORD dwSize, DWORD flAllocationType, DWORD flProtect);
+ BOOL VirtualFree(LPVOID lpAddress, DWORD dwSize, DWORD dwFreeType);
+ BOOL VirtualProtect(LPVOID lpAddress, DWORD dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
+ DWORD VirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, DWORD dwLength);
+ LPVOID VirtualAllocEx(HANDLE hProcess, LPVOID lpAddress, DWORD dwSize, DWORD flAllocationType, DWORD flProtect);
+ BOOL VirtualFreeEx(HANDLE hProcess, LPVOID lpAddress, DWORD dwSize, DWORD dwFreeType);
+ BOOL VirtualProtectEx(HANDLE hProcess, LPVOID lpAddress, DWORD dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
+ DWORD VirtualQueryEx(HANDLE hProcess, LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, DWORD dwLength);
+}
+
+struct SYSTEMTIME
+{
+    WORD wYear;
+    WORD wMonth;
+    WORD wDayOfWeek;
+    WORD wDay;
+    WORD wHour;
+    WORD wMinute;
+    WORD wSecond;
+    WORD wMilliseconds;
+}
+
+struct TIME_ZONE_INFORMATION {
+    LONG Bias;
+    WCHAR StandardName[ 32 ];
+    SYSTEMTIME StandardDate;
+    LONG StandardBias;
+    WCHAR DaylightName[ 32 ];
+    SYSTEMTIME DaylightDate;
+    LONG DaylightBias;
+}
+
+enum
+{
+	TIME_ZONE_ID_UNKNOWN =  0,
+	TIME_ZONE_ID_STANDARD = 1,
+	TIME_ZONE_ID_DAYLIGHT = 2,
+}
+
+export void GetSystemTime(SYSTEMTIME* lpSystemTime);
+export void GetSystemTimeAsFileTime(FILETIME* lpSystemTimeAsFileTime);
+export BOOL SetSystemTime(SYSTEMTIME* lpSystemTime);
+export void GetLocalTime(SYSTEMTIME* lpSystemTime);
+export BOOL SetLocalTime(SYSTEMTIME* lpSystemTime);
+export BOOL SystemTimeToTzSpecificLocalTime(TIME_ZONE_INFORMATION* lpTimeZoneInformation, SYSTEMTIME* lpUniversalTime, SYSTEMTIME* lpLocalTime);
+export DWORD GetTimeZoneInformation(TIME_ZONE_INFORMATION* lpTimeZoneInformation);
+export BOOL SetTimeZoneInformation(TIME_ZONE_INFORMATION* lpTimeZoneInformation);
+
+export BOOL SystemTimeToFileTime(SYSTEMTIME *lpSystemTime, FILETIME* lpFileTime);
+export BOOL FileTimeToLocalFileTime(FILETIME *lpFileTime, FILETIME* lpLocalFileTime);
+export BOOL LocalFileTimeToFileTime(FILETIME *lpLocalFileTime, FILETIME* lpFileTime);
+export BOOL FileTimeToSystemTime(FILETIME *lpFileTime, SYSTEMTIME* lpSystemTime);
+export LONG CompareFileTime(FILETIME *lpFileTime1, FILETIME *lpFileTime2);
+export BOOL FileTimeToDosDateTime(FILETIME *lpFileTime, WORD* lpFatDate, WORD* lpFatTime);
+export BOOL DosDateTimeToFileTime(WORD wFatDate, WORD wFatTime, FILETIME* lpFileTime);
+export DWORD GetTickCount();
+export BOOL SetSystemTimeAdjustment(DWORD dwTimeAdjustment, BOOL bTimeAdjustmentDisabled);
+export BOOL GetSystemTimeAdjustment(DWORD* lpTimeAdjustment, DWORD* lpTimeIncrement, BOOL* lpTimeAdjustmentDisabled);
+export DWORD FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer, DWORD nSize, void* *Arguments);export DWORD FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, void* *Arguments);
+
+enum
+{
+	FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100,
+	FORMAT_MESSAGE_IGNORE_INSERTS =  0x00000200,
+	FORMAT_MESSAGE_FROM_STRING =     0x00000400,
+	FORMAT_MESSAGE_FROM_HMODULE =    0x00000800,
+	FORMAT_MESSAGE_FROM_SYSTEM =     0x00001000,
+	FORMAT_MESSAGE_ARGUMENT_ARRAY =  0x00002000,
+	FORMAT_MESSAGE_MAX_WIDTH_MASK =  0x000000FF,
+};
+
+
+//
+//  Language IDs.
+//
+//  The following two combinations of primary language ID and
+//  sublanguage ID have special semantics:
+//
+//    Primary Language ID   Sublanguage ID      Result
+//    -------------------   ---------------     ------------------------
+//    LANG_NEUTRAL          SUBLANG_NEUTRAL     Language neutral
+//    LANG_NEUTRAL          SUBLANG_DEFAULT     User default language
+//    LANG_NEUTRAL          SUBLANG_SYS_DEFAULT System default language
+//
+
+//
+//  Primary language IDs.
+//
+
+enum
+{
+	LANG_NEUTRAL                     = 0x00,
+
+	LANG_AFRIKAANS                   = 0x36,
+	LANG_ALBANIAN                    = 0x1c,
+	LANG_ARABIC                      = 0x01,
+	LANG_BASQUE                      = 0x2d,
+	LANG_BELARUSIAN                  = 0x23,
+	LANG_BULGARIAN                   = 0x02,
+	LANG_CATALAN                     = 0x03,
+	LANG_CHINESE                     = 0x04,
+	LANG_CROATIAN                    = 0x1a,
+	LANG_CZECH                       = 0x05,
+	LANG_DANISH                      = 0x06,
+	LANG_DUTCH                       = 0x13,
+	LANG_ENGLISH                     = 0x09,
+	LANG_ESTONIAN                    = 0x25,
+	LANG_FAEROESE                    = 0x38,
+	LANG_FARSI                       = 0x29,
+	LANG_FINNISH                     = 0x0b,
+	LANG_FRENCH                      = 0x0c,
+	LANG_GERMAN                      = 0x07,
+	LANG_GREEK                       = 0x08,
+	LANG_HEBREW                      = 0x0d,
+	LANG_HUNGARIAN                   = 0x0e,
+	LANG_ICELANDIC                   = 0x0f,
+	LANG_INDONESIAN                  = 0x21,
+	LANG_ITALIAN                     = 0x10,
+	LANG_JAPANESE                    = 0x11,
+	LANG_KOREAN                      = 0x12,
+	LANG_LATVIAN                     = 0x26,
+	LANG_LITHUANIAN                  = 0x27,
+	LANG_NORWEGIAN                   = 0x14,
+	LANG_POLISH                      = 0x15,
+	LANG_PORTUGUESE                  = 0x16,
+	LANG_ROMANIAN                    = 0x18,
+	LANG_RUSSIAN                     = 0x19,
+	LANG_SERBIAN                     = 0x1a,
+	LANG_SLOVAK                      = 0x1b,
+	LANG_SLOVENIAN                   = 0x24,
+	LANG_SPANISH                     = 0x0a,
+	LANG_SWEDISH                     = 0x1d,
+	LANG_THAI                        = 0x1e,
+	LANG_TURKISH                     = 0x1f,
+	LANG_UKRAINIAN                   = 0x22,
+	LANG_VIETNAMESE                  = 0x2a,
+}
+//
+//  Sublanguage IDs.
+//
+//  The name immediately following SUBLANG_ dictates which primary
+//  language ID that sublanguage ID can be combined with to form a
+//  valid language ID.
+//
+enum
+{
+	SUBLANG_NEUTRAL =                  0x00,    // language neutral
+	SUBLANG_DEFAULT =                  0x01,    // user default
+	SUBLANG_SYS_DEFAULT =              0x02,    // system default
+
+	SUBLANG_ARABIC_SAUDI_ARABIA =      0x01,    // Arabic (Saudi Arabia)
+	SUBLANG_ARABIC_IRAQ =              0x02,    // Arabic (Iraq)
+	SUBLANG_ARABIC_EGYPT =             0x03,    // Arabic (Egypt)
+	SUBLANG_ARABIC_LIBYA =             0x04,    // Arabic (Libya)
+	SUBLANG_ARABIC_ALGERIA =           0x05,    // Arabic (Algeria)
+	SUBLANG_ARABIC_MOROCCO =           0x06,    // Arabic (Morocco)
+	SUBLANG_ARABIC_TUNISIA =           0x07,    // Arabic (Tunisia)
+	SUBLANG_ARABIC_OMAN =              0x08,    // Arabic (Oman)
+	SUBLANG_ARABIC_YEMEN =             0x09,    // Arabic (Yemen)
+	SUBLANG_ARABIC_SYRIA =             0x0a,    // Arabic (Syria)
+	SUBLANG_ARABIC_JORDAN =            0x0b,    // Arabic (Jordan)
+	SUBLANG_ARABIC_LEBANON =           0x0c,    // Arabic (Lebanon)
+	SUBLANG_ARABIC_KUWAIT =            0x0d,    // Arabic (Kuwait)
+	SUBLANG_ARABIC_UAE =               0x0e,    // Arabic (U.A.E)
+	SUBLANG_ARABIC_BAHRAIN =           0x0f,    // Arabic (Bahrain)
+	SUBLANG_ARABIC_QATAR =             0x10,    // Arabic (Qatar)
+	SUBLANG_CHINESE_TRADITIONAL =      0x01,    // Chinese (Taiwan)
+	SUBLANG_CHINESE_SIMPLIFIED =       0x02,    // Chinese (PR China)
+	SUBLANG_CHINESE_HONGKONG =         0x03,    // Chinese (Hong Kong)
+	SUBLANG_CHINESE_SINGAPORE =        0x04,    // Chinese (Singapore)
+	SUBLANG_DUTCH =                    0x01,    // Dutch
+	SUBLANG_DUTCH_BELGIAN =            0x02,    // Dutch (Belgian)
+	SUBLANG_ENGLISH_US =               0x01,    // English (USA)
+	SUBLANG_ENGLISH_UK =               0x02,    // English (UK)
+	SUBLANG_ENGLISH_AUS =              0x03,    // English (Australian)
+	SUBLANG_ENGLISH_CAN =              0x04,    // English (Canadian)
+	SUBLANG_ENGLISH_NZ =               0x05,    // English (New Zealand)
+	SUBLANG_ENGLISH_EIRE =             0x06,    // English (Irish)
+	SUBLANG_ENGLISH_SOUTH_AFRICA =     0x07,    // English (South Africa)
+	SUBLANG_ENGLISH_JAMAICA =          0x08,    // English (Jamaica)
+	SUBLANG_ENGLISH_CARIBBEAN =        0x09,    // English (Caribbean)
+	SUBLANG_ENGLISH_BELIZE =           0x0a,    // English (Belize)
+	SUBLANG_ENGLISH_TRINIDAD =         0x0b,    // English (Trinidad)
+	SUBLANG_FRENCH =                   0x01,    // French
+	SUBLANG_FRENCH_BELGIAN =           0x02,    // French (Belgian)
+	SUBLANG_FRENCH_CANADIAN =          0x03,    // French (Canadian)
+	SUBLANG_FRENCH_SWISS =             0x04,    // French (Swiss)
+	SUBLANG_FRENCH_LUXEMBOURG =        0x05,    // French (Luxembourg)
+	SUBLANG_GERMAN =                   0x01,    // German
+	SUBLANG_GERMAN_SWISS =             0x02,    // German (Swiss)
+	SUBLANG_GERMAN_AUSTRIAN =          0x03,    // German (Austrian)
+	SUBLANG_GERMAN_LUXEMBOURG =        0x04,    // German (Luxembourg)
+	SUBLANG_GERMAN_LIECHTENSTEIN =     0x05,    // German (Liechtenstein)
+	SUBLANG_ITALIAN =                  0x01,    // Italian
+	SUBLANG_ITALIAN_SWISS =            0x02,    // Italian (Swiss)
+	SUBLANG_KOREAN =                   0x01,    // Korean (Extended Wansung)
+	SUBLANG_KOREAN_JOHAB =             0x02,    // Korean (Johab)
+	SUBLANG_NORWEGIAN_BOKMAL =         0x01,    // Norwegian (Bokmal)
+	SUBLANG_NORWEGIAN_NYNORSK =        0x02,    // Norwegian (Nynorsk)
+	SUBLANG_PORTUGUESE =               0x02,    // Portuguese
+	SUBLANG_PORTUGUESE_BRAZILIAN =     0x01,    // Portuguese (Brazilian)
+	SUBLANG_SERBIAN_LATIN =            0x02,    // Serbian (Latin)
+	SUBLANG_SERBIAN_CYRILLIC =         0x03,    // Serbian (Cyrillic)
+	SUBLANG_SPANISH =                  0x01,    // Spanish (Castilian)
+	SUBLANG_SPANISH_MEXICAN =          0x02,    // Spanish (Mexican)
+	SUBLANG_SPANISH_MODERN =           0x03,    // Spanish (Modern)
+	SUBLANG_SPANISH_GUATEMALA =        0x04,    // Spanish (Guatemala)
+	SUBLANG_SPANISH_COSTA_RICA =       0x05,    // Spanish (Costa Rica)
+	SUBLANG_SPANISH_PANAMA =           0x06,    // Spanish (Panama)
+	SUBLANG_SPANISH_DOMINICAN_REPUBLIC = 0x07,  // Spanish (Dominican Republic)
+	SUBLANG_SPANISH_VENEZUELA =        0x08,    // Spanish (Venezuela)
+	SUBLANG_SPANISH_COLOMBIA =         0x09,    // Spanish (Colombia)
+	SUBLANG_SPANISH_PERU =             0x0a,    // Spanish (Peru)
+	SUBLANG_SPANISH_ARGENTINA =        0x0b,    // Spanish (Argentina)
+	SUBLANG_SPANISH_ECUADOR =          0x0c,    // Spanish (Ecuador)
+	SUBLANG_SPANISH_CHILE =            0x0d,    // Spanish (Chile)
+	SUBLANG_SPANISH_URUGUAY =          0x0e,    // Spanish (Uruguay)
+	SUBLANG_SPANISH_PARAGUAY =         0x0f,    // Spanish (Paraguay)
+	SUBLANG_SPANISH_BOLIVIA =          0x10,    // Spanish (Bolivia)
+	SUBLANG_SPANISH_EL_SALVADOR =      0x11,    // Spanish (El Salvador)
+	SUBLANG_SPANISH_HONDURAS =         0x12,    // Spanish (Honduras)
+	SUBLANG_SPANISH_NICARAGUA =        0x13,    // Spanish (Nicaragua)
+	SUBLANG_SPANISH_PUERTO_RICO =      0x14,    // Spanish (Puerto Rico)
+	SUBLANG_SWEDISH =                  0x01,    // Swedish
+	SUBLANG_SWEDISH_FINLAND =          0x02,    // Swedish (Finland)
+}
+//
+//  Sorting IDs.
+//
+
+enum
+{
+	SORT_DEFAULT                   = 0x0,    // sorting default
+
+	SORT_JAPANESE_XJIS             = 0x0,    // Japanese XJIS order
+	SORT_JAPANESE_UNICODE          = 0x1,    // Japanese Unicode order
+
+	SORT_CHINESE_BIG5              = 0x0,    // Chinese BIG5 order
+	SORT_CHINESE_PRCP              = 0x0,    // PRC Chinese Phonetic order
+	SORT_CHINESE_UNICODE           = 0x1,    // Chinese Unicode order
+	SORT_CHINESE_PRC               = 0x2,    // PRC Chinese Stroke Count order
+
+	SORT_KOREAN_KSC                = 0x0,    // Korean KSC order
+	SORT_KOREAN_UNICODE            = 0x1,    // Korean Unicode order
+
+	SORT_GERMAN_PHONE_BOOK         = 0x1,    // German Phone Book order
+}
+
+// end_r_winnt
+
+//
+//  A language ID is a 16 bit value which is the combination of a
+//  primary language ID and a secondary language ID.  The bits are
+//  allocated as follows:
+//
+//       +-----------------------+-------------------------+
+//       |     Sublanguage ID    |   Primary Language ID   |
+//       +-----------------------+-------------------------+
+//        15                   10 9                       0   bit
+//
+//
+//  Language ID creation/extraction macros:
+//
+//    MAKELANGID    - construct language id from a primary language id and
+//                    a sublanguage id.
+//    PRIMARYLANGID - extract primary language id from a language id.
+//    SUBLANGID     - extract sublanguage id from a language id.
+//
+
+int MAKELANGID(int p, int s) { return ((cast(WORD)s) << 10) | cast(WORD)p; }
+WORD PRIMARYLANGID(int lgid) { return cast(WORD)(lgid & 0x3ff); }
+WORD SUBLANGID(int lgid)     { return cast(WORD)(lgid >> 10); }
+
+
+struct FLOATING_SAVE_AREA {
+    DWORD   ControlWord;
+    DWORD   StatusWord;
+    DWORD   TagWord;
+    DWORD   ErrorOffset;
+    DWORD   ErrorSelector;
+    DWORD   DataOffset;
+    DWORD   DataSelector;
+    BYTE    RegisterArea[80 ];
+    DWORD   Cr0NpxState;
+}
+
+enum
+{
+	SIZE_OF_80387_REGISTERS =      80,
+//
+// The following flags control the contents of the CONTEXT structure.
+//
+	CONTEXT_i386 =    0x00010000,    // this assumes that i386 and
+	CONTEXT_i486 =    0x00010000,    // i486 have identical context records
+
+	CONTEXT_CONTROL =         (CONTEXT_i386 | 0x00000001), // SS:SP, CS:IP, FLAGS, BP
+	CONTEXT_INTEGER =         (CONTEXT_i386 | 0x00000002), // AX, BX, CX, DX, SI, DI
+	CONTEXT_SEGMENTS =        (CONTEXT_i386 | 0x00000004), // DS, ES, FS, GS
+	CONTEXT_FLOATING_POINT =  (CONTEXT_i386 | 0x00000008), // 387 state
+	CONTEXT_DEBUG_REGISTERS = (CONTEXT_i386 | 0x00000010), // DB 0-3,6,7
+
+	CONTEXT_FULL = (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS),
+}
+
+struct CONTEXT
+{
+
+    //
+    // The flags values within this flag control the contents of
+    // a CONTEXT record.
+    //
+    // If the context record is used as an input parameter, then
+    // for each portion of the context record controlled by a flag
+    // whose value is set, it is assumed that that portion of the
+    // context record contains valid context. If the context record
+    // is being used to modify a threads context, then only that
+    // portion of the threads context will be modified.
+    //
+    // If the context record is used as an IN OUT parameter to capture
+    // the context of a thread, then only those portions of the thread's
+    // context corresponding to set flags will be returned.
+    //
+    // The context record is never used as an OUT only parameter.
+    //
+
+    DWORD ContextFlags;
+
+    //
+    // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
+    // set in ContextFlags.  Note that CONTEXT_DEBUG_REGISTERS is NOT
+    // included in CONTEXT_FULL.
+    //
+
+    DWORD   Dr0;
+    DWORD   Dr1;
+    DWORD   Dr2;
+    DWORD   Dr3;
+    DWORD   Dr6;
+    DWORD   Dr7;
+
+    //
+    // This section is specified/returned if the
+    // ContextFlags word contians the flag CONTEXT_FLOATING_POINT.
+    //
+
+    FLOATING_SAVE_AREA FloatSave;
+
+    //
+    // This section is specified/returned if the
+    // ContextFlags word contians the flag CONTEXT_SEGMENTS.
+    //
+
+    DWORD   SegGs;
+    DWORD   SegFs;
+    DWORD   SegEs;
+    DWORD   SegDs;
+
+    //
+    // This section is specified/returned if the
+    // ContextFlags word contians the flag CONTEXT_INTEGER.
+    //
+
+    DWORD   Edi;
+    DWORD   Esi;
+    DWORD   Ebx;
+    DWORD   Edx;
+    DWORD   Ecx;
+    DWORD   Eax;
+
+    //
+    // This section is specified/returned if the
+    // ContextFlags word contians the flag CONTEXT_CONTROL.
+    //
+
+    DWORD   Ebp;
+    DWORD   Eip;
+    DWORD   SegCs;              // MUST BE SANITIZED
+    DWORD   EFlags;             // MUST BE SANITIZED
+    DWORD   Esp;
+    DWORD   SegSs;
+}
+
+enum
+{
+	THREAD_BASE_PRIORITY_LOWRT =  15,  // value that gets a thread to LowRealtime-1
+	THREAD_BASE_PRIORITY_MAX =    2,   // maximum thread base priority boost
+	THREAD_BASE_PRIORITY_MIN =    -2,  // minimum thread base priority boost
+	THREAD_BASE_PRIORITY_IDLE =   -15, // value that gets a thread to idle
+
+	THREAD_PRIORITY_LOWEST =          THREAD_BASE_PRIORITY_MIN,
+	THREAD_PRIORITY_BELOW_NORMAL =    (THREAD_PRIORITY_LOWEST+1),
+	THREAD_PRIORITY_NORMAL =          0,
+	THREAD_PRIORITY_HIGHEST =         THREAD_BASE_PRIORITY_MAX,
+	THREAD_PRIORITY_ABOVE_NORMAL =    (THREAD_PRIORITY_HIGHEST-1),
+	THREAD_PRIORITY_ERROR_RETURN =    int.max,
+
+	THREAD_PRIORITY_TIME_CRITICAL =   THREAD_BASE_PRIORITY_LOWRT,
+	THREAD_PRIORITY_IDLE =            THREAD_BASE_PRIORITY_IDLE,
+}
+
+export HANDLE GetCurrentThread();
+export BOOL GetProcessTimes(HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime);
+export HANDLE GetCurrentProcess();
+export BOOL DuplicateHandle (HANDLE sourceProcess, HANDLE sourceThread,
+        HANDLE targetProcessHandle, HANDLE *targetHandle, DWORD access, 
+        BOOL inheritHandle, DWORD options);
+export DWORD GetCurrentThreadId();
+export BOOL SetThreadPriority(HANDLE hThread, int nPriority);
+export BOOL SetThreadPriorityBoost(HANDLE hThread, BOOL bDisablePriorityBoost);
+export BOOL GetThreadPriorityBoost(HANDLE hThread, PBOOL pDisablePriorityBoost);
+export BOOL GetThreadTimes(HANDLE hThread, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime);
+export int GetThreadPriority(HANDLE hThread);
+export BOOL GetThreadContext(HANDLE hThread, CONTEXT* lpContext);
+export BOOL SetThreadContext(HANDLE hThread, CONTEXT* lpContext);
+export DWORD SuspendThread(HANDLE hThread);
+export DWORD ResumeThread(HANDLE hThread);
+export DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);
+export DWORD WaitForMultipleObjects(DWORD nCount, HANDLE *lpHandles, BOOL bWaitAll, DWORD dwMilliseconds);
+export void Sleep(DWORD dwMilliseconds);
+
+export BOOL QueryPerformanceCounter(long* lpPerformanceCount);
+export BOOL QueryPerformanceFrequency(long* lpFrequency);
+
+enum
+{
+	WM_NOTIFY =                       0x004E,
+	WM_INPUTLANGCHANGEREQUEST =       0x0050,
+	WM_INPUTLANGCHANGE =              0x0051,
+	WM_TCARD =                        0x0052,
+	WM_HELP =                         0x0053,
+	WM_USERCHANGED =                  0x0054,
+	WM_NOTIFYFORMAT =                 0x0055,
+
+	NFR_ANSI =                             1,
+	NFR_UNICODE =                          2,
+	NF_QUERY =                             3,
+	NF_REQUERY =                           4,
+
+	WM_CONTEXTMENU =                  0x007B,
+	WM_STYLECHANGING =                0x007C,
+	WM_STYLECHANGED =                 0x007D,
+	WM_DISPLAYCHANGE =                0x007E,
+	WM_GETICON =                      0x007F,
+	WM_SETICON =                      0x0080,
+
+
+
+	WM_NCCREATE =                     0x0081,
+	WM_NCDESTROY =                    0x0082,
+	WM_NCCALCSIZE =                   0x0083,
+	WM_NCHITTEST =                    0x0084,
+	WM_NCPAINT =                      0x0085,
+	WM_NCACTIVATE =                   0x0086,
+	WM_GETDLGCODE =                   0x0087,
+
+	WM_NCMOUSEMOVE =                  0x00A0,
+	WM_NCLBUTTONDOWN =                0x00A1,
+	WM_NCLBUTTONUP =                  0x00A2,
+	WM_NCLBUTTONDBLCLK =              0x00A3,
+	WM_NCRBUTTONDOWN =                0x00A4,
+	WM_NCRBUTTONUP =                  0x00A5,
+	WM_NCRBUTTONDBLCLK =              0x00A6,
+	WM_NCMBUTTONDOWN =                0x00A7,
+	WM_NCMBUTTONUP =                  0x00A8,
+	WM_NCMBUTTONDBLCLK =              0x00A9,
+
+	WM_KEYFIRST =                     0x0100,
+	WM_KEYDOWN =                      0x0100,
+	WM_KEYUP =                        0x0101,
+	WM_CHAR =                         0x0102,
+	WM_DEADCHAR =                     0x0103,
+	WM_SYSKEYDOWN =                   0x0104,
+	WM_SYSKEYUP =                     0x0105,
+	WM_SYSCHAR =                      0x0106,
+	WM_SYSDEADCHAR =                  0x0107,
+	WM_KEYLAST =                      0x0108,
+
+
+	WM_IME_STARTCOMPOSITION =         0x010D,
+	WM_IME_ENDCOMPOSITION =           0x010E,
+	WM_IME_COMPOSITION =              0x010F,
+	WM_IME_KEYLAST =                  0x010F,
+
+
+	WM_INITDIALOG =                   0x0110,
+	WM_COMMAND =                      0x0111,
+	WM_SYSCOMMAND =                   0x0112,
+	WM_TIMER =                        0x0113,
+	WM_HSCROLL =                      0x0114,
+	WM_VSCROLL =                      0x0115,
+	WM_INITMENU =                     0x0116,
+	WM_INITMENUPOPUP =                0x0117,
+	WM_MENUSELECT =                   0x011F,
+	WM_MENUCHAR =                     0x0120,
+	WM_ENTERIDLE =                    0x0121,
+
+	WM_CTLCOLORMSGBOX =               0x0132,
+	WM_CTLCOLOREDIT =                 0x0133,
+	WM_CTLCOLORLISTBOX =              0x0134,
+	WM_CTLCOLORBTN =                  0x0135,
+	WM_CTLCOLORDLG =                  0x0136,
+	WM_CTLCOLORSCROLLBAR =            0x0137,
+	WM_CTLCOLORSTATIC =               0x0138,
+
+
+
+	WM_MOUSEFIRST =                   0x0200,
+	WM_MOUSEMOVE =                    0x0200,
+	WM_LBUTTONDOWN =                  0x0201,
+	WM_LBUTTONUP =                    0x0202,
+	WM_LBUTTONDBLCLK =                0x0203,
+	WM_RBUTTONDOWN =                  0x0204,
+	WM_RBUTTONUP =                    0x0205,
+	WM_RBUTTONDBLCLK =                0x0206,
+	WM_MBUTTONDOWN =                  0x0207,
+	WM_MBUTTONUP =                    0x0208,
+	WM_MBUTTONDBLCLK =                0x0209,
+
+
+
+	WM_MOUSELAST =                    0x0209,
+
+
+
+
+
+
+
+
+	WM_PARENTNOTIFY =                 0x0210,
+	MENULOOP_WINDOW =                 0,
+	MENULOOP_POPUP =                  1,
+	WM_ENTERMENULOOP =                0x0211,
+	WM_EXITMENULOOP =                 0x0212,
+
+
+	WM_NEXTMENU =                     0x0213,
+}
+
+enum
+{
+/*
+ * Dialog Box Command IDs
+ */
+	IDOK =                1,
+	IDCANCEL =            2,
+	IDABORT =             3,
+	IDRETRY =             4,
+	IDIGNORE =            5,
+	IDYES =               6,
+	IDNO =                7,
+
+	IDCLOSE =         8,
+	IDHELP =          9,
+
+
+// end_r_winuser
+
+
+
+/*
+ * Control Manager Structures and Definitions
+ */
+
+
+
+// begin_r_winuser
+
+/*
+ * Edit Control Styles
+ */
+	ES_LEFT =             0x0000,
+	ES_CENTER =           0x0001,
+	ES_RIGHT =            0x0002,
+	ES_MULTILINE =        0x0004,
+	ES_UPPERCASE =        0x0008,
+	ES_LOWERCASE =        0x0010,
+	ES_PASSWORD =         0x0020,
+	ES_AUTOVSCROLL =      0x0040,
+	ES_AUTOHSCROLL =      0x0080,
+	ES_NOHIDESEL =        0x0100,
+	ES_OEMCONVERT =       0x0400,
+	ES_READONLY =         0x0800,
+	ES_WANTRETURN =       0x1000,
+
+	ES_NUMBER =           0x2000,
+
+
+// end_r_winuser
+
+
+
+/*
+ * Edit Control Notification Codes
+ */
+	EN_SETFOCUS =         0x0100,
+	EN_KILLFOCUS =        0x0200,
+	EN_CHANGE =           0x0300,
+	EN_UPDATE =           0x0400,
+	EN_ERRSPACE =         0x0500,
+	EN_MAXTEXT =          0x0501,
+	EN_HSCROLL =          0x0601,
+	EN_VSCROLL =          0x0602,
+
+
+/* Edit control EM_SETMARGIN parameters */
+	EC_LEFTMARGIN =       0x0001,
+	EC_RIGHTMARGIN =      0x0002,
+	EC_USEFONTINFO =      0xffff,
+
+
+
+
+// begin_r_winuser
+
+/*
+ * Edit Control Messages
+ */
+	EM_GETSEL =               0x00B0,
+	EM_SETSEL =               0x00B1,
+	EM_GETRECT =              0x00B2,
+	EM_SETRECT =              0x00B3,
+	EM_SETRECTNP =            0x00B4,
+	EM_SCROLL =               0x00B5,
+	EM_LINESCROLL =           0x00B6,
+	EM_SCROLLCARET =          0x00B7,
+	EM_GETMODIFY =            0x00B8,
+	EM_SETMODIFY =            0x00B9,
+	EM_GETLINECOUNT =         0x00BA,
+	EM_LINEINDEX =            0x00BB,
+	EM_SETHANDLE =            0x00BC,
+	EM_GETHANDLE =            0x00BD,
+	EM_GETTHUMB =             0x00BE,
+	EM_LINELENGTH =           0x00C1,
+	EM_REPLACESEL =           0x00C2,
+	EM_GETLINE =              0x00C4,
+	EM_LIMITTEXT =            0x00C5,
+	EM_CANUNDO =              0x00C6,
+	EM_UNDO =                 0x00C7,
+	EM_FMTLINES =             0x00C8,
+	EM_LINEFROMCHAR =         0x00C9,
+	EM_SETTABSTOPS =          0x00CB,
+	EM_SETPASSWORDCHAR =      0x00CC,
+	EM_EMPTYUNDOBUFFER =      0x00CD,
+	EM_GETFIRSTVISIBLELINE =  0x00CE,
+	EM_SETREADONLY =          0x00CF,
+	EM_SETWORDBREAKPROC =     0x00D0,
+	EM_GETWORDBREAKPROC =     0x00D1,
+	EM_GETPASSWORDCHAR =      0x00D2,
+
+	EM_SETMARGINS =           0x00D3,
+	EM_GETMARGINS =           0x00D4,
+	EM_SETLIMITTEXT =         EM_LIMITTEXT, /* ;win40 Name change */
+	EM_GETLIMITTEXT =         0x00D5,
+	EM_POSFROMCHAR =          0x00D6,
+	EM_CHARFROMPOS =          0x00D7,
+
+
+
+// end_r_winuser
+
+
+/*
+ * EDITWORDBREAKPROC code values
+ */
+	WB_LEFT =            0,
+	WB_RIGHT =           1,
+	WB_ISDELIMITER =     2,
+
+// begin_r_winuser
+
+/*
+ * Button Control Styles
+ */
+	BS_PUSHBUTTON =       0x00000000,
+	BS_DEFPUSHBUTTON =    0x00000001,
+	BS_CHECKBOX =         0x00000002,
+	BS_AUTOCHECKBOX =     0x00000003,
+	BS_RADIOBUTTON =      0x00000004,
+	BS_3STATE =           0x00000005,
+	BS_AUTO3STATE =       0x00000006,
+	BS_GROUPBOX =         0x00000007,
+	BS_USERBUTTON =       0x00000008,
+	BS_AUTORADIOBUTTON =  0x00000009,
+	BS_OWNERDRAW =        0x0000000B,
+	BS_LEFTTEXT =         0x00000020,
+
+	BS_TEXT =             0x00000000,
+	BS_ICON =             0x00000040,
+	BS_BITMAP =           0x00000080,
+	BS_LEFT =             0x00000100,
+	BS_RIGHT =            0x00000200,
+	BS_CENTER =           0x00000300,
+	BS_TOP =              0x00000400,
+	BS_BOTTOM =           0x00000800,
+	BS_VCENTER =          0x00000C00,
+	BS_PUSHLIKE =         0x00001000,
+	BS_MULTILINE =        0x00002000,
+	BS_NOTIFY =           0x00004000,
+	BS_FLAT =             0x00008000,
+	BS_RIGHTBUTTON =      BS_LEFTTEXT,
+
+
+
+/*
+ * User Button Notification Codes
+ */
+	BN_CLICKED =          0,
+	BN_PAINT =            1,
+	BN_HILITE =           2,
+	BN_UNHILITE =         3,
+	BN_DISABLE =          4,
+	BN_DOUBLECLICKED =    5,
+
+	BN_PUSHED =           BN_HILITE,
+	BN_UNPUSHED =         BN_UNHILITE,
+	BN_DBLCLK =           BN_DOUBLECLICKED,
+	BN_SETFOCUS =         6,
+	BN_KILLFOCUS =        7,
+
+/*
+ * Button Control Messages
+ */
+	BM_GETCHECK =        0x00F0,
+	BM_SETCHECK =        0x00F1,
+	BM_GETSTATE =        0x00F2,
+	BM_SETSTATE =        0x00F3,
+	BM_SETSTYLE =        0x00F4,
+
+	BM_CLICK =           0x00F5,
+	BM_GETIMAGE =        0x00F6,
+	BM_SETIMAGE =        0x00F7,
+
+	BST_UNCHECKED =      0x0000,
+	BST_CHECKED =        0x0001,
+	BST_INDETERMINATE =  0x0002,
+	BST_PUSHED =         0x0004,
+	BST_FOCUS =          0x0008,
+
+
+/*
+ * Static Control Constants
+ */
+	SS_LEFT =             0x00000000,
+	SS_CENTER =           0x00000001,
+	SS_RIGHT =            0x00000002,
+	SS_ICON =             0x00000003,
+	SS_BLACKRECT =        0x00000004,
+	SS_GRAYRECT =         0x00000005,
+	SS_WHITERECT =        0x00000006,
+	SS_BLACKFRAME =       0x00000007,
+	SS_GRAYFRAME =        0x00000008,
+	SS_WHITEFRAME =       0x00000009,
+	SS_USERITEM =         0x0000000A,
+	SS_SIMPLE =           0x0000000B,
+	SS_LEFTNOWORDWRAP =   0x0000000C,
+
+	SS_OWNERDRAW =        0x0000000D,
+	SS_BITMAP =           0x0000000E,
+	SS_ENHMETAFILE =      0x0000000F,
+	SS_ETCHEDHORZ =       0x00000010,
+	SS_ETCHEDVERT =       0x00000011,
+	SS_ETCHEDFRAME =      0x00000012,
+	SS_TYPEMASK =         0x0000001F,
+
+	SS_NOPREFIX =         0x00000080, /* Don't do "&" character translation */
+
+	SS_NOTIFY =           0x00000100,
+	SS_CENTERIMAGE =      0x00000200,
+	SS_RIGHTJUST =        0x00000400,
+	SS_REALSIZEIMAGE =    0x00000800,
+	SS_SUNKEN =           0x00001000,
+	SS_ENDELLIPSIS =      0x00004000,
+	SS_PATHELLIPSIS =     0x00008000,
+	SS_WORDELLIPSIS =     0x0000C000,
+	SS_ELLIPSISMASK =     0x0000C000,
+
+
+// end_r_winuser
+
+
+/*
+ * Static Control Mesages
+ */
+	STM_SETICON =         0x0170,
+	STM_GETICON =         0x0171,
+
+	STM_SETIMAGE =        0x0172,
+	STM_GETIMAGE =        0x0173,
+	STN_CLICKED =         0,
+	STN_DBLCLK =          1,
+	STN_ENABLE =          2,
+	STN_DISABLE =         3,
+
+	STM_MSGMAX =          0x0174,
+}
+
+
+enum
+{
+/*
+ * Window Messages
+ */
+
+	WM_NULL =                         0x0000,
+	WM_CREATE =                       0x0001,
+	WM_DESTROY =                      0x0002,
+	WM_MOVE =                         0x0003,
+	WM_SIZE =                         0x0005,
+
+	WM_ACTIVATE =                     0x0006,
+/*
+ * WM_ACTIVATE state values
+ */
+	WA_INACTIVE =     0,
+	WA_ACTIVE =       1,
+	WA_CLICKACTIVE =  2,
+
+	WM_SETFOCUS =                     0x0007,
+	WM_KILLFOCUS =                    0x0008,
+	WM_ENABLE =                       0x000A,
+	WM_SETREDRAW =                    0x000B,
+	WM_SETTEXT =                      0x000C,
+	WM_GETTEXT =                      0x000D,
+	WM_GETTEXTLENGTH =                0x000E,
+	WM_PAINT =                        0x000F,
+	WM_CLOSE =                        0x0010,
+	WM_QUERYENDSESSION =              0x0011,
+	WM_QUIT =                         0x0012,
+	WM_QUERYOPEN =                    0x0013,
+	WM_ERASEBKGND =                   0x0014,
+	WM_SYSCOLORCHANGE =               0x0015,
+	WM_ENDSESSION =                   0x0016,
+	WM_SHOWWINDOW =                   0x0018,
+	WM_WININICHANGE =                 0x001A,
+
+	WM_SETTINGCHANGE =                WM_WININICHANGE,
+
+
+
+	WM_DEVMODECHANGE =                0x001B,
+	WM_ACTIVATEAPP =                  0x001C,
+	WM_FONTCHANGE =                   0x001D,
+	WM_TIMECHANGE =                   0x001E,
+	WM_CANCELMODE =                   0x001F,
+	WM_SETCURSOR =                    0x0020,
+	WM_MOUSEACTIVATE =                0x0021,
+	WM_CHILDACTIVATE =                0x0022,
+	WM_QUEUESYNC =                    0x0023,
+
+	WM_GETMINMAXINFO =                0x0024,
+}
+
+struct RECT
+{
+    LONG    left;
+    LONG    top;
+    LONG    right;
+    LONG    bottom;
+}
+alias RECT* PRECT, NPRECT, LPRECT;
+
+struct PAINTSTRUCT {
+    HDC         hdc;
+    BOOL        fErase;
+    RECT        rcPaint;
+    BOOL        fRestore;
+    BOOL        fIncUpdate;
+    BYTE        rgbReserved[32];
+}
+alias PAINTSTRUCT* PPAINTSTRUCT, NPPAINTSTRUCT, LPPAINTSTRUCT;
+
+// flags for GetDCEx()
+
+enum
+{
+	DCX_WINDOW =           0x00000001,
+	DCX_CACHE =            0x00000002,
+	DCX_NORESETATTRS =     0x00000004,
+	DCX_CLIPCHILDREN =     0x00000008,
+	DCX_CLIPSIBLINGS =     0x00000010,
+	DCX_PARENTCLIP =       0x00000020,
+	DCX_EXCLUDERGN =       0x00000040,
+	DCX_INTERSECTRGN =     0x00000080,
+	DCX_EXCLUDEUPDATE =    0x00000100,
+	DCX_INTERSECTUPDATE =  0x00000200,
+	DCX_LOCKWINDOWUPDATE = 0x00000400,
+	DCX_VALIDATE =         0x00200000,
+}
+
+export
+{
+ BOOL UpdateWindow(HWND hWnd);
+ HWND SetActiveWindow(HWND hWnd);
+ HWND GetForegroundWindow();
+ BOOL PaintDesktop(HDC hdc);
+ BOOL SetForegroundWindow(HWND hWnd);
+ HWND WindowFromDC(HDC hDC);
+ HDC GetDC(HWND hWnd);
+ HDC GetDCEx(HWND hWnd, HRGN hrgnClip, DWORD flags);
+ HDC GetWindowDC(HWND hWnd);
+ int ReleaseDC(HWND hWnd, HDC hDC);
+ HDC BeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint);
+ BOOL EndPaint(HWND hWnd, PAINTSTRUCT *lpPaint);
+ BOOL GetUpdateRect(HWND hWnd, LPRECT lpRect, BOOL bErase);
+ int GetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase);
+ int SetWindowRgn(HWND hWnd, HRGN hRgn, BOOL bRedraw);
+ int GetWindowRgn(HWND hWnd, HRGN hRgn);
+ int ExcludeUpdateRgn(HDC hDC, HWND hWnd);
+ BOOL InvalidateRect(HWND hWnd, RECT *lpRect, BOOL bErase);
+ BOOL ValidateRect(HWND hWnd, RECT *lpRect);
+ BOOL InvalidateRgn(HWND hWnd, HRGN hRgn, BOOL bErase);
+ BOOL ValidateRgn(HWND hWnd, HRGN hRgn);
+ BOOL RedrawWindow(HWND hWnd, RECT *lprcUpdate, HRGN hrgnUpdate, UINT flags);
+}
+
+// flags for RedrawWindow()
+enum
+{
+	RDW_INVALIDATE =          0x0001,
+	RDW_INTERNALPAINT =       0x0002,
+	RDW_ERASE =               0x0004,
+	RDW_VALIDATE =            0x0008,
+	RDW_NOINTERNALPAINT =     0x0010,
+	RDW_NOERASE =             0x0020,
+	RDW_NOCHILDREN =          0x0040,
+	RDW_ALLCHILDREN =         0x0080,
+	RDW_UPDATENOW =           0x0100,
+	RDW_ERASENOW =            0x0200,
+	RDW_FRAME =               0x0400,
+	RDW_NOFRAME =             0x0800,
+}
+
+export
+{
+ BOOL GetClientRect(HWND hWnd, LPRECT lpRect);
+ BOOL GetWindowRect(HWND hWnd, LPRECT lpRect);
+ BOOL AdjustWindowRect(LPRECT lpRect, DWORD dwStyle, BOOL bMenu);
+ BOOL AdjustWindowRectEx(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle);
+ HFONT CreateFontA(int, int, int, int, int, DWORD,
+                             DWORD, DWORD, DWORD, DWORD, DWORD,
+                             DWORD, DWORD, LPCSTR);
+ HFONT CreateFontW(int, int, int, int, int, DWORD,
+                             DWORD, DWORD, DWORD, DWORD, DWORD,
+                             DWORD, DWORD, LPCWSTR);
+}
+
+enum
+{
+	OUT_DEFAULT_PRECIS =          0,
+	OUT_STRING_PRECIS =           1,
+	OUT_CHARACTER_PRECIS =        2,
+	OUT_STROKE_PRECIS =           3,
+	OUT_TT_PRECIS =               4,
+	OUT_DEVICE_PRECIS =           5,
+	OUT_RASTER_PRECIS =           6,
+	OUT_TT_ONLY_PRECIS =          7,
+	OUT_OUTLINE_PRECIS =          8,
+	OUT_SCREEN_OUTLINE_PRECIS =   9,
+
+	CLIP_DEFAULT_PRECIS =     0,
+	CLIP_CHARACTER_PRECIS =   1,
+	CLIP_STROKE_PRECIS =      2,
+	CLIP_MASK =               0xf,
+	CLIP_LH_ANGLES =          (1<<4),
+	CLIP_TT_ALWAYS =          (2<<4),
+	CLIP_EMBEDDED =           (8<<4),
+
+	DEFAULT_QUALITY =         0,
+	DRAFT_QUALITY =           1,
+	PROOF_QUALITY =           2,
+
+	NONANTIALIASED_QUALITY =  3,
+	ANTIALIASED_QUALITY =     4,
+
+
+	DEFAULT_PITCH =           0,
+	FIXED_PITCH =             1,
+	VARIABLE_PITCH =          2,
+
+	MONO_FONT =               8,
+
+
+	ANSI_CHARSET =            0,
+	DEFAULT_CHARSET =         1,
+	SYMBOL_CHARSET =          2,
+	SHIFTJIS_CHARSET =        128,
+	HANGEUL_CHARSET =         129,
+	GB2312_CHARSET =          134,
+	CHINESEBIG5_CHARSET =     136,
+	OEM_CHARSET =             255,
+
+	JOHAB_CHARSET =           130,
+	HEBREW_CHARSET =          177,
+	ARABIC_CHARSET =          178,
+	GREEK_CHARSET =           161,
+	TURKISH_CHARSET =         162,
+	VIETNAMESE_CHARSET =      163,
+	THAI_CHARSET =            222,
+	EASTEUROPE_CHARSET =      238,
+	RUSSIAN_CHARSET =         204,
+
+	MAC_CHARSET =             77,
+	BALTIC_CHARSET =          186,
+
+	FS_LATIN1 =               0x00000001L,
+	FS_LATIN2 =               0x00000002L,
+	FS_CYRILLIC =             0x00000004L,
+	FS_GREEK =                0x00000008L,
+	FS_TURKISH =              0x00000010L,
+	FS_HEBREW =               0x00000020L,
+	FS_ARABIC =               0x00000040L,
+	FS_BALTIC =               0x00000080L,
+	FS_VIETNAMESE =           0x00000100L,
+	FS_THAI =                 0x00010000L,
+	FS_JISJAPAN =             0x00020000L,
+	FS_CHINESESIMP =          0x00040000L,
+	FS_WANSUNG =              0x00080000L,
+	FS_CHINESETRAD =          0x00100000L,
+	FS_JOHAB =                0x00200000L,
+	FS_SYMBOL =               cast(int)0x80000000L,
+
+
+/* Font Families */
+	FF_DONTCARE =         (0<<4), /* Don't care or don't know. */
+	FF_ROMAN =            (1<<4), /* Variable stroke width, serifed. */
+                                    /* Times Roman, Century Schoolbook, etc. */
+	FF_SWISS =            (2<<4), /* Variable stroke width, sans-serifed. */
+                                    /* Helvetica, Swiss, etc. */
+	FF_MODERN =           (3<<4), /* Constant stroke width, serifed or sans-serifed. */
+                                    /* Pica, Elite, Courier, etc. */
+	FF_SCRIPT =           (4<<4), /* Cursive, etc. */
+	FF_DECORATIVE =       (5<<4), /* Old English, etc. */
+
+/* Font Weights */
+	FW_DONTCARE =         0,
+	FW_THIN =             100,
+	FW_EXTRALIGHT =       200,
+	FW_LIGHT =            300,
+	FW_NORMAL =           400,
+	FW_MEDIUM =           500,
+	FW_SEMIBOLD =         600,
+	FW_BOLD =             700,
+	FW_EXTRABOLD =        800,
+	FW_HEAVY =            900,
+
+	FW_ULTRALIGHT =       FW_EXTRALIGHT,
+	FW_REGULAR =          FW_NORMAL,
+	FW_DEMIBOLD =         FW_SEMIBOLD,
+	FW_ULTRABOLD =        FW_EXTRABOLD,
+	FW_BLACK =            FW_HEAVY,
+
+	PANOSE_COUNT =               10,
+	PAN_FAMILYTYPE_INDEX =        0,
+	PAN_SERIFSTYLE_INDEX =        1,
+	PAN_WEIGHT_INDEX =            2,
+	PAN_PROPORTION_INDEX =        3,
+	PAN_CONTRAST_INDEX =          4,
+	PAN_STROKEVARIATION_INDEX =   5,
+	PAN_ARMSTYLE_INDEX =          6,
+	PAN_LETTERFORM_INDEX =        7,
+	PAN_MIDLINE_INDEX =           8,
+	PAN_XHEIGHT_INDEX =           9,
+
+	PAN_CULTURE_LATIN =           0,
+}
+
+struct RGBQUAD {
+        BYTE    rgbBlue;
+        BYTE    rgbGreen;
+        BYTE    rgbRed;
+        BYTE    rgbReserved;
+}
+alias RGBQUAD* LPRGBQUAD;
+
+struct BITMAPINFOHEADER
+{
+        DWORD      biSize;
+        LONG       biWidth;
+        LONG       biHeight;
+        WORD       biPlanes;
+        WORD       biBitCount;
+        DWORD      biCompression;
+        DWORD      biSizeImage;
+        LONG       biXPelsPerMeter;
+        LONG       biYPelsPerMeter;
+        DWORD      biClrUsed;
+        DWORD      biClrImportant;
+}
+alias BITMAPINFOHEADER* LPBITMAPINFOHEADER, PBITMAPINFOHEADER;
+
+struct BITMAPINFO {
+    BITMAPINFOHEADER    bmiHeader;
+    RGBQUAD             bmiColors[1];
+}
+alias BITMAPINFO* LPBITMAPINFO, PBITMAPINFO;
+
+struct PALETTEENTRY {
+    BYTE        peRed;
+    BYTE        peGreen;
+    BYTE        peBlue;
+    BYTE        peFlags;
+}
+alias PALETTEENTRY* PPALETTEENTRY, LPPALETTEENTRY;
+
+struct LOGPALETTE {
+    WORD        palVersion;
+    WORD        palNumEntries;
+    PALETTEENTRY        palPalEntry[1];
+}
+alias LOGPALETTE* PLOGPALETTE, NPLOGPALETTE, LPLOGPALETTE;
+
+/* Pixel format descriptor */
+struct PIXELFORMATDESCRIPTOR
+{
+    WORD  nSize;
+    WORD  nVersion;
+    DWORD dwFlags;
+    BYTE  iPixelType;
+    BYTE  cColorBits;
+    BYTE  cRedBits;
+    BYTE  cRedShift;
+    BYTE  cGreenBits;
+    BYTE  cGreenShift;
+    BYTE  cBlueBits;
+    BYTE  cBlueShift;
+    BYTE  cAlphaBits;
+    BYTE  cAlphaShift;
+    BYTE  cAccumBits;
+    BYTE  cAccumRedBits;
+    BYTE  cAccumGreenBits;
+    BYTE  cAccumBlueBits;
+    BYTE  cAccumAlphaBits;
+    BYTE  cDepthBits;
+    BYTE  cStencilBits;
+    BYTE  cAuxBuffers;
+    BYTE  iLayerType;
+    BYTE  bReserved;
+    DWORD dwLayerMask;
+    DWORD dwVisibleMask;
+    DWORD dwDamageMask;
+}
+alias PIXELFORMATDESCRIPTOR* PPIXELFORMATDESCRIPTOR, LPPIXELFORMATDESCRIPTOR;
+
+
+export
+{
+ BOOL   RoundRect(HDC, int, int, int, int, int, int);
+ BOOL   ResizePalette(HPALETTE, UINT);
+ int    SaveDC(HDC);
+ int    SelectClipRgn(HDC, HRGN);
+ int    ExtSelectClipRgn(HDC, HRGN, int);
+ int    SetMetaRgn(HDC);
+ HGDIOBJ   SelectObject(HDC, HGDIOBJ);
+ HPALETTE   SelectPalette(HDC, HPALETTE, BOOL);
+ COLORREF   SetBkColor(HDC, COLORREF);
+ int     SetBkMode(HDC, int);
+ LONG    SetBitmapBits(HBITMAP, DWORD, void *);
+ UINT    SetBoundsRect(HDC,   RECT *, UINT);
+ int     SetDIBits(HDC, HBITMAP, UINT, UINT, void *, BITMAPINFO *, UINT);
+ int     SetDIBitsToDevice(HDC, int, int, DWORD, DWORD, int,
+        int, UINT, UINT, void *, BITMAPINFO *, UINT);
+ DWORD   SetMapperFlags(HDC, DWORD);
+ int     SetGraphicsMode(HDC hdc, int iMode);
+ int     SetMapMode(HDC, int);
+ HMETAFILE     SetMetaFileBitsEx(UINT, BYTE *);
+ UINT    SetPaletteEntries(HPALETTE, UINT, UINT, PALETTEENTRY *);
+ COLORREF   SetPixel(HDC, int, int, COLORREF);
+ BOOL     SetPixelV(HDC, int, int, COLORREF);
+ BOOL    SetPixelFormat(HDC, int, PIXELFORMATDESCRIPTOR *);
+ int     SetPolyFillMode(HDC, int);
+ BOOL    StretchBlt(HDC, int, int, int, int, HDC, int, int, int, int, DWORD);
+ BOOL    SetRectRgn(HRGN, int, int, int, int);
+ int     StretchDIBits(HDC, int, int, int, int, int, int, int, int,
+         void *, BITMAPINFO *, UINT, DWORD);
+ int     SetROP2(HDC, int);
+ int     SetStretchBltMode(HDC, int);
+ UINT    SetSystemPaletteUse(HDC, UINT);
+ int     SetTextCharacterExtra(HDC, int);
+ COLORREF   SetTextColor(HDC, COLORREF);
+ UINT    SetTextAlign(HDC, UINT);
+ BOOL    SetTextJustification(HDC, int, int);
+ BOOL    UpdateColors(HDC);
+}
+
+/* Text Alignment Options */
+enum
+{
+	TA_NOUPDATECP =                0,
+	TA_UPDATECP =                  1,
+
+	TA_LEFT =                      0,
+	TA_RIGHT =                     2,
+	TA_CENTER =                    6,
+
+	TA_TOP =                       0,
+	TA_BOTTOM =                    8,
+	TA_BASELINE =                  24,
+
+	TA_RTLREADING =                256,
+	TA_MASK =       (TA_BASELINE+TA_CENTER+TA_UPDATECP+TA_RTLREADING),
+}
+
+struct POINT
+{
+    LONG  x;
+    LONG  y;
+}
+alias POINT* PPOINT, NPPOINT, LPPOINT;
+
+
+export
+{
+ BOOL    MoveToEx(HDC, int, int, LPPOINT);
+ BOOL    TextOutA(HDC, int, int, LPCSTR, int);
+ BOOL    TextOutW(HDC, int, int, LPCWSTR, int);
+}
+
+export void PostQuitMessage(int nExitCode);
+export LRESULT DefWindowProcA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
+export HMODULE GetModuleHandleA(LPCSTR lpModuleName);
+
+alias LRESULT (* WNDPROC)(HWND, UINT, WPARAM, LPARAM);
+
+struct WNDCLASSEXA {
+    UINT        cbSize;
+    /* Win 3.x */
+    UINT        style;
+    WNDPROC     lpfnWndProc;
+    int         cbClsExtra;
+    int         cbWndExtra;
+    HINSTANCE   hInstance;
+    HICON       hIcon;
+    HCURSOR     hCursor;
+    HBRUSH      hbrBackground;
+    LPCSTR      lpszMenuName;
+    LPCSTR      lpszClassName;
+    /* Win 4.0 */
+    HICON       hIconSm;
+}
+alias WNDCLASSEXA* PWNDCLASSEXA, NPWNDCLASSEXA, LPWNDCLASSEXA;
+
+
+struct WNDCLASSA {
+    UINT        style;
+    WNDPROC     lpfnWndProc;
+    int         cbClsExtra;
+    int         cbWndExtra;
+    HINSTANCE   hInstance;
+    HICON       hIcon;
+    HCURSOR     hCursor;
+    HBRUSH      hbrBackground;
+    LPCSTR      lpszMenuName;
+    LPCSTR      lpszClassName;
+}
+alias WNDCLASSA* PWNDCLASSA, NPWNDCLASSA, LPWNDCLASSA;
+alias WNDCLASSA WNDCLASS;
+
+/*
+ * Window Styles
+ */
+enum : uint
+{
+	WS_OVERLAPPED =       0x00000000,
+	WS_POPUP =            0x80000000,
+	WS_CHILD =            0x40000000,
+	WS_MINIMIZE =         0x20000000,
+	WS_VISIBLE =          0x10000000,
+	WS_DISABLED =         0x08000000,
+	WS_CLIPSIBLINGS =     0x04000000,
+	WS_CLIPCHILDREN =     0x02000000,
+	WS_MAXIMIZE =         0x01000000,
+	WS_CAPTION =          0x00C00000,  /* WS_BORDER | WS_DLGFRAME  */
+	WS_BORDER =           0x00800000,
+	WS_DLGFRAME =         0x00400000,
+	WS_VSCROLL =          0x00200000,
+	WS_HSCROLL =          0x00100000,
+	WS_SYSMENU =          0x00080000,
+	WS_THICKFRAME =       0x00040000,
+	WS_GROUP =            0x00020000,
+	WS_TABSTOP =          0x00010000,
+
+	WS_MINIMIZEBOX =      0x00020000,
+	WS_MAXIMIZEBOX =      0x00010000,
+
+	WS_TILED =            WS_OVERLAPPED,
+	WS_ICONIC =           WS_MINIMIZE,
+	WS_SIZEBOX =          WS_THICKFRAME,
+
+/*
+ * Common Window Styles
+ */
+	WS_OVERLAPPEDWINDOW = (WS_OVERLAPPED |            WS_CAPTION |  WS_SYSMENU |  WS_THICKFRAME |            WS_MINIMIZEBOX |                 WS_MAXIMIZEBOX),
+	WS_TILEDWINDOW =      WS_OVERLAPPEDWINDOW,
+	WS_POPUPWINDOW =      (WS_POPUP |  WS_BORDER |  WS_SYSMENU),
+	WS_CHILDWINDOW =      (WS_CHILD),
+}
+
+/*
+ * Class styles
+ */
+enum
+{
+	CS_VREDRAW =          0x0001,
+	CS_HREDRAW =          0x0002,
+	CS_KEYCVTWINDOW =     0x0004,
+	CS_DBLCLKS =          0x0008,
+	CS_OWNDC =            0x0020,
+	CS_CLASSDC =          0x0040,
+	CS_PARENTDC =         0x0080,
+	CS_NOKEYCVT =         0x0100,
+	CS_NOCLOSE =          0x0200,
+	CS_SAVEBITS =         0x0800,
+	CS_BYTEALIGNCLIENT =  0x1000,
+	CS_BYTEALIGNWINDOW =  0x2000,
+	CS_GLOBALCLASS =      0x4000,
+
+
+	CS_IME =              0x00010000,
+}
+
+export
+{
+ HICON LoadIconA(HINSTANCE hInstance, LPCSTR lpIconName);
+ HICON LoadIconW(HINSTANCE hInstance, LPCWSTR lpIconName);
+ HCURSOR LoadCursorA(HINSTANCE hInstance, LPCSTR lpCursorName);
+ HCURSOR LoadCursorW(HINSTANCE hInstance, LPCWSTR lpCursorName);
+}
+
+const LPSTR IDI_APPLICATION =     cast(LPSTR)(32512);
+
+const LPSTR IDC_ARROW =           cast(LPSTR)(32512);
+const LPSTR IDC_CROSS =           cast(LPSTR)(32515);
+
+/*
+ * Color Types
+ */
+enum
+{
+	CTLCOLOR_MSGBOX =         0,
+	CTLCOLOR_EDIT =           1,
+	CTLCOLOR_LISTBOX =        2,
+	CTLCOLOR_BTN =            3,
+	CTLCOLOR_DLG =            4,
+	CTLCOLOR_SCROLLBAR =      5,
+	CTLCOLOR_STATIC =         6,
+	CTLCOLOR_MAX =            7,
+
+	COLOR_SCROLLBAR =         0,
+	COLOR_BACKGROUND =        1,
+	COLOR_ACTIVECAPTION =     2,
+	COLOR_INACTIVECAPTION =   3,
+	COLOR_MENU =              4,
+	COLOR_WINDOW =            5,
+	COLOR_WINDOWFRAME =       6,
+	COLOR_MENUTEXT =          7,
+	COLOR_WINDOWTEXT =        8,
+	COLOR_CAPTIONTEXT =       9,
+	COLOR_ACTIVEBORDER =      10,
+	COLOR_INACTIVEBORDER =    11,
+	COLOR_APPWORKSPACE =      12,
+	COLOR_HIGHLIGHT =         13,
+	COLOR_HIGHLIGHTTEXT =     14,
+	COLOR_BTNFACE =           15,
+	COLOR_BTNSHADOW =         16,
+	COLOR_GRAYTEXT =          17,
+	COLOR_BTNTEXT =           18,
+	COLOR_INACTIVECAPTIONTEXT = 19,
+	COLOR_BTNHIGHLIGHT =      20,
+
+
+	COLOR_3DDKSHADOW =        21,
+	COLOR_3DLIGHT =           22,
+	COLOR_INFOTEXT =          23,
+	COLOR_INFOBK =            24,
+
+	COLOR_DESKTOP =           COLOR_BACKGROUND,
+	COLOR_3DFACE =            COLOR_BTNFACE,
+	COLOR_3DSHADOW =          COLOR_BTNSHADOW,
+	COLOR_3DHIGHLIGHT =       COLOR_BTNHIGHLIGHT,
+	COLOR_3DHILIGHT =         COLOR_BTNHIGHLIGHT,
+	COLOR_BTNHILIGHT =        COLOR_BTNHIGHLIGHT,
+}
+
+const int CW_USEDEFAULT = cast(int)0x80000000;
+/*
+ * Special value for CreateWindow, et al.
+ */
+const HWND HWND_DESKTOP = (cast(HWND)0);
+
+
+export ATOM RegisterClassA(WNDCLASSA *lpWndClass);
+
+export HWND CreateWindowExA(
+    DWORD dwExStyle,
+    LPCSTR lpClassName,
+    LPCSTR lpWindowName,
+    DWORD dwStyle,
+    int X,
+    int Y,
+    int nWidth,
+    int nHeight,
+    HWND hWndParent ,
+    HMENU hMenu,
+    HINSTANCE hInstance,
+    LPVOID lpParam);
+
+
+HWND CreateWindowA(
+    LPCSTR lpClassName,
+    LPCSTR lpWindowName,
+    DWORD dwStyle,
+    int X,
+    int Y,
+    int nWidth,
+    int nHeight,
+    HWND hWndParent ,
+    HMENU hMenu,
+    HINSTANCE hInstance,
+    LPVOID lpParam)
+{
+    return CreateWindowExA(0, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
+}
+
+/*
+ * Message structure
+ */
+struct MSG {
+    HWND        hwnd;
+    UINT        message;
+    WPARAM      wParam;
+    LPARAM      lParam;
+    DWORD       time;
+    POINT       pt;
+}
+alias MSG* PMSG, NPMSG, LPMSG;
+
+export
+{
+ BOOL GetMessageA(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);
+ BOOL TranslateMessage(MSG *lpMsg);
+ LONG DispatchMessageA(MSG *lpMsg);
+ BOOL PeekMessageA(MSG *lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg);
+ HWND GetFocus();
+}
+
+export DWORD ExpandEnvironmentStringsA(LPCSTR lpSrc, LPSTR lpDst, DWORD nSize);
+
+export
+{
+ BOOL IsValidCodePage(UINT CodePage);
+ UINT GetACP();
+ UINT GetOEMCP();
+ //BOOL GetCPInfo(UINT CodePage, LPCPINFO lpCPInfo);
+ BOOL IsDBCSLeadByte(BYTE TestChar);
+ BOOL IsDBCSLeadByteEx(UINT CodePage, BYTE TestChar);
+ int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cchMultiByte, LPWSTR lpWideCharStr, int cchWideChar);
+ int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cchMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar);
+}
+
+export HANDLE CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName);
+export HANDLE CreateFileMappingW(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCWSTR lpName);
+
+export BOOL GetMailslotInfo(HANDLE hMailslot, LPDWORD lpMaxMessageSize, LPDWORD lpNextSize, LPDWORD lpMessageCount, LPDWORD lpReadTimeout);
+export BOOL SetMailslotInfo(HANDLE hMailslot, DWORD lReadTimeout);
+export LPVOID MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, DWORD dwNumberOfBytesToMap);
+export LPVOID MapViewOfFileEx(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, DWORD dwNumberOfBytesToMap, LPVOID lpBaseAddress);
+export BOOL FlushViewOfFile(LPCVOID lpBaseAddress, DWORD dwNumberOfBytesToFlush);
+export BOOL UnmapViewOfFile(LPCVOID lpBaseAddress);
+
+export  HGDIOBJ   GetStockObject(int);
+export BOOL ShowWindow(HWND hWnd, int nCmdShow);
+
+/* Stock Logical Objects */
+enum
+{	WHITE_BRUSH =         0,
+	LTGRAY_BRUSH =        1,
+	GRAY_BRUSH =          2,
+	DKGRAY_BRUSH =        3,
+	BLACK_BRUSH =         4,
+	NULL_BRUSH =          5,
+	HOLLOW_BRUSH =        NULL_BRUSH,
+	WHITE_PEN =           6,
+	BLACK_PEN =           7,
+	NULL_PEN =            8,
+	OEM_FIXED_FONT =      10,
+	ANSI_FIXED_FONT =     11,
+	ANSI_VAR_FONT =       12,
+	SYSTEM_FONT =         13,
+	DEVICE_DEFAULT_FONT = 14,
+	DEFAULT_PALETTE =     15,
+	SYSTEM_FIXED_FONT =   16,
+	DEFAULT_GUI_FONT =    17,
+	STOCK_LAST =          17,
+}
+
+/*
+ * ShowWindow() Commands
+ */
+enum
+{	SW_HIDE =             0,
+	SW_SHOWNORMAL =       1,
+	SW_NORMAL =           1,
+	SW_SHOWMINIMIZED =    2,
+	SW_SHOWMAXIMIZED =    3,
+	SW_MAXIMIZE =         3,
+	SW_SHOWNOACTIVATE =   4,
+	SW_SHOW =             5,
+	SW_MINIMIZE =         6,
+	SW_SHOWMINNOACTIVE =  7,
+	SW_SHOWNA =           8,
+	SW_RESTORE =          9,
+	SW_SHOWDEFAULT =      10,
+	SW_MAX =              10,
+}
+
+struct TEXTMETRICA
+{
+    LONG        tmHeight;
+    LONG        tmAscent;
+    LONG        tmDescent;
+    LONG        tmInternalLeading;
+    LONG        tmExternalLeading;
+    LONG        tmAveCharWidth;
+    LONG        tmMaxCharWidth;
+    LONG        tmWeight;
+    LONG        tmOverhang;
+    LONG        tmDigitizedAspectX;
+    LONG        tmDigitizedAspectY;
+    BYTE        tmFirstChar;
+    BYTE        tmLastChar;
+    BYTE        tmDefaultChar;
+    BYTE        tmBreakChar;
+    BYTE        tmItalic;
+    BYTE        tmUnderlined;
+    BYTE        tmStruckOut;
+    BYTE        tmPitchAndFamily;
+    BYTE        tmCharSet;
+}
+
+export  BOOL   GetTextMetricsA(HDC, TEXTMETRICA*);
+
+/*
+ * Scroll Bar Constants
+ */
+enum
+{	SB_HORZ =             0,
+	SB_VERT =             1,
+	SB_CTL =              2,
+	SB_BOTH =             3,
+}
+
+/*
+ * Scroll Bar Commands
+ */
+enum
+{	SB_LINEUP =           0,
+	SB_LINELEFT =         0,
+	SB_LINEDOWN =         1,
+	SB_LINERIGHT =        1,
+	SB_PAGEUP =           2,
+	SB_PAGELEFT =         2,
+	SB_PAGEDOWN =         3,
+	SB_PAGERIGHT =        3,
+	SB_THUMBPOSITION =    4,
+	SB_THUMBTRACK =       5,
+	SB_TOP =              6,
+	SB_LEFT =             6,
+	SB_BOTTOM =           7,
+	SB_RIGHT =            7,
+	SB_ENDSCROLL =        8,
+}
+
+export int SetScrollPos(HWND hWnd, int nBar, int nPos, BOOL bRedraw);
+export int GetScrollPos(HWND hWnd, int nBar);
+export BOOL SetScrollRange(HWND hWnd, int nBar, int nMinPos, int nMaxPos, BOOL bRedraw);
+export BOOL GetScrollRange(HWND hWnd, int nBar, LPINT lpMinPos, LPINT lpMaxPos);
+export BOOL ShowScrollBar(HWND hWnd, int wBar, BOOL bShow);
+export BOOL EnableScrollBar(HWND hWnd, UINT wSBflags, UINT wArrows);
+
+/*
+ * LockWindowUpdate API
+ */
+
+export BOOL LockWindowUpdate(HWND hWndLock);
+export BOOL ScrollWindow(HWND hWnd, int XAmount, int YAmount, RECT* lpRect, RECT* lpClipRect);
+export BOOL ScrollDC(HDC hDC, int dx, int dy, RECT* lprcScroll, RECT* lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate);
+export int ScrollWindowEx(HWND hWnd, int dx, int dy, RECT* prcScroll, RECT* prcClip, HRGN hrgnUpdate, LPRECT prcUpdate, UINT flags);
+
+/*
+ * Virtual Keys, Standard Set
+ */
+enum
+{	VK_LBUTTON =        0x01,
+	VK_RBUTTON =        0x02,
+	VK_CANCEL =         0x03,
+	VK_MBUTTON =        0x04, /* NOT contiguous with L & RBUTTON */
+
+	VK_BACK =           0x08,
+	VK_TAB =            0x09,
+
+	VK_CLEAR =          0x0C,
+	VK_RETURN =         0x0D,
+
+	VK_SHIFT =          0x10,
+	VK_CONTROL =        0x11,
+	VK_MENU =           0x12,
+	VK_PAUSE =          0x13,
+	VK_CAPITAL =        0x14,
+
+
+	VK_ESCAPE =         0x1B,
+
+	VK_SPACE =          0x20,
+	VK_PRIOR =          0x21,
+	VK_NEXT =           0x22,
+	VK_END =            0x23,
+	VK_HOME =           0x24,
+	VK_LEFT =           0x25,
+	VK_UP =             0x26,
+	VK_RIGHT =          0x27,
+	VK_DOWN =           0x28,
+	VK_SELECT =         0x29,
+	VK_PRINT =          0x2A,
+	VK_EXECUTE =        0x2B,
+	VK_SNAPSHOT =       0x2C,
+	VK_INSERT =         0x2D,
+	VK_DELETE =         0x2E,
+	VK_HELP =           0x2F,
+
+/* VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */
+/* VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */
+
+	VK_LWIN =           0x5B,
+	VK_RWIN =           0x5C,
+	VK_APPS =           0x5D,
+
+	VK_NUMPAD0 =        0x60,
+	VK_NUMPAD1 =        0x61,
+	VK_NUMPAD2 =        0x62,
+	VK_NUMPAD3 =        0x63,
+	VK_NUMPAD4 =        0x64,
+	VK_NUMPAD5 =        0x65,
+	VK_NUMPAD6 =        0x66,
+	VK_NUMPAD7 =        0x67,
+	VK_NUMPAD8 =        0x68,
+	VK_NUMPAD9 =        0x69,
+	VK_MULTIPLY =       0x6A,
+	VK_ADD =            0x6B,
+	VK_SEPARATOR =      0x6C,
+	VK_SUBTRACT =       0x6D,
+	VK_DECIMAL =        0x6E,
+	VK_DIVIDE =         0x6F,
+	VK_F1 =             0x70,
+	VK_F2 =             0x71,
+	VK_F3 =             0x72,
+	VK_F4 =             0x73,
+	VK_F5 =             0x74,
+	VK_F6 =             0x75,
+	VK_F7 =             0x76,
+	VK_F8 =             0x77,
+	VK_F9 =             0x78,
+	VK_F10 =            0x79,
+	VK_F11 =            0x7A,
+	VK_F12 =            0x7B,
+	VK_F13 =            0x7C,
+	VK_F14 =            0x7D,
+	VK_F15 =            0x7E,
+	VK_F16 =            0x7F,
+	VK_F17 =            0x80,
+	VK_F18 =            0x81,
+	VK_F19 =            0x82,
+	VK_F20 =            0x83,
+	VK_F21 =            0x84,
+	VK_F22 =            0x85,
+	VK_F23 =            0x86,
+	VK_F24 =            0x87,
+
+	VK_NUMLOCK =        0x90,
+	VK_SCROLL =         0x91,
+
+/*
+ * VK_L* & VK_R* - left and right Alt, Ctrl and Shift virtual keys.
+ * Used only as parameters to GetAsyncKeyState() and GetKeyState().
+ * No other API or message will distinguish left and right keys in this way.
+ */
+	VK_LSHIFT =         0xA0,
+	VK_RSHIFT =         0xA1,
+	VK_LCONTROL =       0xA2,
+	VK_RCONTROL =       0xA3,
+	VK_LMENU =          0xA4,
+	VK_RMENU =          0xA5,
+
+
+	VK_PROCESSKEY =     0xE5,
+
+
+	VK_ATTN =           0xF6,
+	VK_CRSEL =          0xF7,
+	VK_EXSEL =          0xF8,
+	VK_EREOF =          0xF9,
+	VK_PLAY =           0xFA,
+	VK_ZOOM =           0xFB,
+	VK_NONAME =         0xFC,
+	VK_PA1 =            0xFD,
+	VK_OEM_CLEAR =      0xFE,
+}
+
+export LRESULT SendMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
+
+alias UINT (*LPOFNHOOKPROC) (HWND, UINT, WPARAM, LPARAM);
+
+struct OPENFILENAMEA {
+   DWORD        lStructSize;
+   HWND         hwndOwner;
+   HINSTANCE    hInstance;
+   LPCSTR       lpstrFilter;
+   LPSTR        lpstrCustomFilter;
+   DWORD        nMaxCustFilter;
+   DWORD        nFilterIndex;
+   LPSTR        lpstrFile;
+   DWORD        nMaxFile;
+   LPSTR        lpstrFileTitle;
+   DWORD        nMaxFileTitle;
+   LPCSTR       lpstrInitialDir;
+   LPCSTR       lpstrTitle;
+   DWORD        Flags;
+   WORD         nFileOffset;
+   WORD         nFileExtension;
+   LPCSTR       lpstrDefExt;
+   LPARAM       lCustData;
+   LPOFNHOOKPROC lpfnHook;
+   LPCSTR       lpTemplateName;
+}
+alias OPENFILENAMEA *LPOPENFILENAMEA;
+
+struct OPENFILENAMEW {
+   DWORD        lStructSize;
+   HWND         hwndOwner;
+   HINSTANCE    hInstance;
+   LPCWSTR      lpstrFilter;
+   LPWSTR       lpstrCustomFilter;
+   DWORD        nMaxCustFilter;
+   DWORD        nFilterIndex;
+   LPWSTR       lpstrFile;
+   DWORD        nMaxFile;
+   LPWSTR       lpstrFileTitle;
+   DWORD        nMaxFileTitle;
+   LPCWSTR      lpstrInitialDir;
+   LPCWSTR      lpstrTitle;
+   DWORD        Flags;
+   WORD         nFileOffset;
+   WORD         nFileExtension;
+   LPCWSTR      lpstrDefExt;
+   LPARAM       lCustData;
+   LPOFNHOOKPROC lpfnHook;
+   LPCWSTR      lpTemplateName;
+}
+alias OPENFILENAMEW *LPOPENFILENAMEW;
+
+BOOL          GetOpenFileNameA(LPOPENFILENAMEA);
+BOOL          GetOpenFileNameW(LPOPENFILENAMEW);
+
+BOOL          GetSaveFileNameA(LPOPENFILENAMEA);
+BOOL          GetSaveFileNameW(LPOPENFILENAMEW);
+
+short         GetFileTitleA(LPCSTR, LPSTR, WORD);
+short         GetFileTitleW(LPCWSTR, LPWSTR, WORD);
+
+enum
+{
+	PM_NOREMOVE =         0x0000,
+	PM_REMOVE =           0x0001,
+	PM_NOYIELD =          0x0002,
+}
+
+/* Bitmap Header Definition */
+struct BITMAP
+{
+    LONG        bmType;
+    LONG        bmWidth;
+    LONG        bmHeight;
+    LONG        bmWidthBytes;
+    WORD        bmPlanes;
+    WORD        bmBitsPixel;
+    LPVOID      bmBits;
+}
+alias BITMAP* PBITMAP, NPBITMAP, LPBITMAP;
+
+
+export  HDC       CreateCompatibleDC(HDC);
+
+export  int     GetObjectA(HGDIOBJ, int, LPVOID);
+export  int     GetObjectW(HGDIOBJ, int, LPVOID);
+export  BOOL   DeleteDC(HDC);
+
+struct LOGFONTA
+{
+    LONG      lfHeight;
+    LONG      lfWidth;
+    LONG      lfEscapement;
+    LONG      lfOrientation;
+    LONG      lfWeight;
+    BYTE      lfItalic;
+    BYTE      lfUnderline;
+    BYTE      lfStrikeOut;
+    BYTE      lfCharSet;
+    BYTE      lfOutPrecision;
+    BYTE      lfClipPrecision;
+    BYTE      lfQuality;
+    BYTE      lfPitchAndFamily;
+    CHAR      lfFaceName[32 ];
+}
+alias LOGFONTA* PLOGFONTA, NPLOGFONTA, LPLOGFONTA;
+
+export HMENU LoadMenuA(HINSTANCE hInstance, LPCSTR lpMenuName);
+export HMENU LoadMenuW(HINSTANCE hInstance, LPCWSTR lpMenuName);
+
+export HMENU GetSubMenu(HMENU hMenu, int nPos);
+
+export HBITMAP LoadBitmapA(HINSTANCE hInstance, LPCSTR lpBitmapName);
+export HBITMAP LoadBitmapW(HINSTANCE hInstance, LPCWSTR lpBitmapName);
+
+LPSTR MAKEINTRESOURCEA(int i) { return cast(LPSTR)(cast(DWORD)(cast(WORD)(i))); }
+
+export  HFONT     CreateFontIndirectA(LOGFONTA *);
+
+export BOOL MessageBeep(UINT uType);
+export int ShowCursor(BOOL bShow);
+export BOOL SetCursorPos(int X, int Y);
+export HCURSOR SetCursor(HCURSOR hCursor);
+export BOOL GetCursorPos(LPPOINT lpPoint);
+export BOOL ClipCursor( RECT *lpRect);
+export BOOL GetClipCursor(LPRECT lpRect);
+export HCURSOR GetCursor();
+export BOOL CreateCaret(HWND hWnd, HBITMAP hBitmap , int nWidth, int nHeight);
+export UINT GetCaretBlinkTime();
+export BOOL SetCaretBlinkTime(UINT uMSeconds);
+export BOOL DestroyCaret();
+export BOOL HideCaret(HWND hWnd);
+export BOOL ShowCaret(HWND hWnd);
+export BOOL SetCaretPos(int X, int Y);
+export BOOL GetCaretPos(LPPOINT lpPoint);
+export BOOL ClientToScreen(HWND hWnd, LPPOINT lpPoint);
+export BOOL ScreenToClient(HWND hWnd, LPPOINT lpPoint);
+export int MapWindowPoints(HWND hWndFrom, HWND hWndTo, LPPOINT lpPoints, UINT cPoints);
+export HWND WindowFromPoint(POINT Point);
+export HWND ChildWindowFromPoint(HWND hWndParent, POINT Point);
+
+
+export BOOL TrackPopupMenu(HMENU hMenu, UINT uFlags, int x, int y,
+	int nReserved, HWND hWnd, RECT *prcRect);
+
+align (2) struct DLGTEMPLATE {
+    DWORD style;
+    DWORD dwExtendedStyle;
+    WORD cdit;
+    short x;
+    short y;
+    short cx;
+    short cy;
+}
+alias DLGTEMPLATE *LPDLGTEMPLATEA;
+alias DLGTEMPLATE *LPDLGTEMPLATEW;
+
+
+alias LPDLGTEMPLATEA LPDLGTEMPLATE;
+
+alias  DLGTEMPLATE *LPCDLGTEMPLATEA;
+alias  DLGTEMPLATE *LPCDLGTEMPLATEW;
+
+
+alias LPCDLGTEMPLATEA LPCDLGTEMPLATE;
+
+
+export int DialogBoxParamA(HINSTANCE hInstance, LPCSTR lpTemplateName,
+	HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam);
+export int DialogBoxIndirectParamA(HINSTANCE hInstance,
+	LPCDLGTEMPLATEA hDialogTemplate, HWND hWndParent, DLGPROC lpDialogFunc,
+	LPARAM dwInitParam);
+
+enum : DWORD
+{
+	SRCCOPY =             cast(DWORD)0x00CC0020, /* dest = source                   */
+	SRCPAINT =            cast(DWORD)0x00EE0086, /* dest = source OR dest           */
+	SRCAND =              cast(DWORD)0x008800C6, /* dest = source AND dest          */
+	SRCINVERT =           cast(DWORD)0x00660046, /* dest = source XOR dest          */
+	SRCERASE =            cast(DWORD)0x00440328, /* dest = source AND (NOT dest)   */
+	NOTSRCCOPY =          cast(DWORD)0x00330008, /* dest = (NOT source)             */
+	NOTSRCERASE =         cast(DWORD)0x001100A6, /* dest = (NOT src) AND (NOT dest) */
+	MERGECOPY =           cast(DWORD)0x00C000CA, /* dest = (source AND pattern)     */
+	MERGEPAINT =          cast(DWORD)0x00BB0226, /* dest = (NOT source) OR dest     */
+	PATCOPY =             cast(DWORD)0x00F00021, /* dest = pattern                  */
+	PATPAINT =            cast(DWORD)0x00FB0A09, /* dest = DPSnoo                   */
+	PATINVERT =           cast(DWORD)0x005A0049, /* dest = pattern XOR dest         */
+	DSTINVERT =           cast(DWORD)0x00550009, /* dest = (NOT dest)               */
+	BLACKNESS =           cast(DWORD)0x00000042, /* dest = BLACK                    */
+	WHITENESS =           cast(DWORD)0x00FF0062, /* dest = WHITE                    */
+}
+
+enum
+{
+	SND_SYNC =            0x0000, /* play synchronously (default) */
+	SND_ASYNC =           0x0001, /* play asynchronously */
+	SND_NODEFAULT =       0x0002, /* silence (!default) if sound not found */
+	SND_MEMORY =          0x0004, /* pszSound points to a memory file */
+	SND_LOOP =            0x0008, /* loop the sound until next sndPlaySound */
+	SND_NOSTOP =          0x0010, /* don't stop any currently playing sound */
+
+	SND_NOWAIT =	0x00002000, /* don't wait if the driver is busy */
+	SND_ALIAS =       0x00010000, /* name is a registry alias */
+	SND_ALIAS_ID =	0x00110000, /* alias is a predefined ID */
+	SND_FILENAME =    0x00020000, /* name is file name */
+	SND_RESOURCE =    0x00040004, /* name is resource name or atom */
+
+	SND_PURGE =           0x0040, /* purge non-static events for task */
+	SND_APPLICATION =     0x0080, /* look for application specific association */
+
+
+	SND_ALIAS_START =	0,     /* alias base */
+}
+
+export  BOOL   PlaySoundA(LPCSTR pszSound, HMODULE hmod, DWORD fdwSound);
+export  BOOL   PlaySoundW(LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound);
+
+export  int     GetClipBox(HDC, LPRECT);
+export  int     GetClipRgn(HDC, HRGN);
+export  int     GetMetaRgn(HDC, HRGN);
+export  HGDIOBJ   GetCurrentObject(HDC, UINT);
+export  BOOL    GetCurrentPositionEx(HDC, LPPOINT);
+export  int     GetDeviceCaps(HDC, int);
+
+struct LOGPEN
+  {
+    UINT        lopnStyle;
+    POINT       lopnWidth;
+    COLORREF    lopnColor;
+}
+alias LOGPEN* PLOGPEN, NPLOGPEN, LPLOGPEN;
+
+enum
+{
+	PS_SOLID =            0,
+	PS_DASH =             1, /* -------  */
+	PS_DOT =              2, /* .......  */
+	PS_DASHDOT =          3, /* _._._._  */
+	PS_DASHDOTDOT =       4, /* _.._.._  */
+	PS_NULL =             5,
+	PS_INSIDEFRAME =      6,
+	PS_USERSTYLE =        7,
+	PS_ALTERNATE =        8,
+	PS_STYLE_MASK =       0x0000000F,
+
+	PS_ENDCAP_ROUND =     0x00000000,
+	PS_ENDCAP_SQUARE =    0x00000100,
+	PS_ENDCAP_FLAT =      0x00000200,
+	PS_ENDCAP_MASK =      0x00000F00,
+
+	PS_JOIN_ROUND =       0x00000000,
+	PS_JOIN_BEVEL =       0x00001000,
+	PS_JOIN_MITER =       0x00002000,
+	PS_JOIN_MASK =        0x0000F000,
+
+	PS_COSMETIC =         0x00000000,
+	PS_GEOMETRIC =        0x00010000,
+	PS_TYPE_MASK =        0x000F0000,
+}
+
+export  HPALETTE   CreatePalette(LOGPALETTE *);
+export  HPEN      CreatePen(int, int, COLORREF);
+export  HPEN      CreatePenIndirect(LOGPEN *);
+export  HRGN      CreatePolyPolygonRgn(POINT *, INT *, int, int);
+export  HBRUSH    CreatePatternBrush(HBITMAP);
+export  HRGN      CreateRectRgn(int, int, int, int);
+export  HRGN      CreateRectRgnIndirect(RECT *);
+export  HRGN      CreateRoundRectRgn(int, int, int, int, int, int);
+export  BOOL      CreateScalableFontResourceA(DWORD, LPCSTR, LPCSTR, LPCSTR);
+export  BOOL      CreateScalableFontResourceW(DWORD, LPCWSTR, LPCWSTR, LPCWSTR);
+
+COLORREF RGB(int r, int g, int b)
+{
+    return cast(COLORREF)
+	((cast(BYTE)r|(cast(WORD)(cast(BYTE)g)<<8))|((cast(DWORD)cast(BYTE)b)<<16));
+}
+
+export  BOOL   LineTo(HDC, int, int);
+export  BOOL   DeleteObject(HGDIOBJ);
+export int FillRect(HDC hDC,  RECT *lprc, HBRUSH hbr);
+
+
+export BOOL EndDialog(HWND hDlg, int nResult);
+export HWND GetDlgItem(HWND hDlg, int nIDDlgItem);
+
+export BOOL SetDlgItemInt(HWND hDlg, int nIDDlgItem, UINT uValue, BOOL bSigned);
+export UINT GetDlgItemInt(HWND hDlg, int nIDDlgItem, BOOL *lpTranslated,
+    BOOL bSigned);
+
+export BOOL SetDlgItemTextA(HWND hDlg, int nIDDlgItem, LPCSTR lpString);
+export BOOL SetDlgItemTextW(HWND hDlg, int nIDDlgItem, LPCWSTR lpString);
+
+export UINT GetDlgItemTextA(HWND hDlg, int nIDDlgItem, LPSTR lpString, int nMaxCount);
+export UINT GetDlgItemTextW(HWND hDlg, int nIDDlgItem, LPWSTR lpString, int nMaxCount);
+
+export BOOL CheckDlgButton(HWND hDlg, int nIDButton, UINT uCheck);
+export BOOL CheckRadioButton(HWND hDlg, int nIDFirstButton, int nIDLastButton,
+    int nIDCheckButton);
+
+export UINT IsDlgButtonChecked(HWND hDlg, int nIDButton);
+
+export HWND SetFocus(HWND hWnd);
+
+export int wsprintfA(LPSTR, LPCSTR, ...);
+export int wsprintfW(LPWSTR, LPCWSTR, ...);
+
+const uint INFINITE = uint.max;
+const uint WAIT_OBJECT_0 = 0;
+
+export HANDLE CreateSemaphoreA(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCTSTR lpName);
+export HANDLE OpenSemaphoreA(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName);
+export BOOL ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCount);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/c/windows/winsock.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,540 @@
+/*
+	Written by Christopher E. Miller
+	Placed into public domain.
+*/
+
+
+module std.c.windows.winsock;
+
+private import std.stdint;
+private import std.c.windows.windows;
+
+
+extern(Windows):
+
+alias UINT SOCKET;
+alias int socklen_t;
+
+const SOCKET INVALID_SOCKET = cast(SOCKET)~0;
+const int SOCKET_ERROR = -1;
+
+const int WSADESCRIPTION_LEN = 256;
+const int WSASYS_STATUS_LEN = 128;
+
+struct WSADATA
+{
+	WORD wVersion;
+	WORD wHighVersion;
+	char szDescription[WSADESCRIPTION_LEN + 1];
+	char szSystemStatus[WSASYS_STATUS_LEN + 1];
+	USHORT iMaxSockets;
+	USHORT iMaxUdpDg;
+	char* lpVendorInfo;
+}
+alias WSADATA* LPWSADATA;
+
+
+const int IOCPARM_MASK =  0x7F;
+const int IOC_IN =        cast(int)0x80000000;
+const int FIONBIO =       cast(int)(IOC_IN | ((UINT.sizeof & IOCPARM_MASK) << 16) | (102 << 8) | 126);
+
+
+int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
+int WSACleanup();
+SOCKET socket(int af, int type, int protocol);
+int ioctlsocket(SOCKET s, int cmd, uint* argp);
+int bind(SOCKET s, sockaddr* name, int namelen);
+int connect(SOCKET s, sockaddr* name, int namelen);
+int listen(SOCKET s, int backlog);
+SOCKET accept(SOCKET s, sockaddr* addr, int* addrlen);
+int closesocket(SOCKET s);
+int shutdown(SOCKET s, int how);
+int getpeername(SOCKET s, sockaddr* name, int* namelen);
+int getsockname(SOCKET s, sockaddr* name, int* namelen);
+int send(SOCKET s, void* buf, int len, int flags);
+int sendto(SOCKET s, void* buf, int len, int flags, sockaddr* to, int tolen);
+int recv(SOCKET s, void* buf, int len, int flags);
+int recvfrom(SOCKET s, void* buf, int len, int flags, sockaddr* from, int* fromlen);
+int getsockopt(SOCKET s, int level, int optname, void* optval, int* optlen);
+int setsockopt(SOCKET s, int level, int optname, void* optval, int optlen);
+uint inet_addr(char* cp);
+int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, timeval* timeout);
+char* inet_ntoa(in_addr ina);
+hostent* gethostbyname(char* name);
+hostent* gethostbyaddr(void* addr, int len, int type);
+protoent* getprotobyname(char* name);
+protoent* getprotobynumber(int number);
+servent* getservbyname(char* name, char* proto);
+servent* getservbyport(int port, char* proto);
+int gethostname(char* name, int namelen);
+int getaddrinfo(char* nodename, char* servname, addrinfo* hints, addrinfo** res);
+void freeaddrinfo(addrinfo* ai);
+int getnameinfo(sockaddr* sa, socklen_t salen, char* host, DWORD hostlen, char* serv, DWORD servlen, int flags);
+
+enum: int
+{
+	WSAEWOULDBLOCK =     10035,
+	WSAEINTR =           10004,
+	WSAHOST_NOT_FOUND =  11001,
+}
+
+int WSAGetLastError();
+
+
+enum: int
+{
+	AF_UNSPEC =     0,
+	
+	AF_UNIX =       1,
+	AF_INET =       2,
+	AF_IMPLINK =    3,
+	AF_PUP =        4,
+	AF_CHAOS =      5,
+	AF_NS =         6,
+	AF_IPX =        AF_NS,
+	AF_ISO =        7,
+	AF_OSI =        AF_ISO,
+	AF_ECMA =       8,
+	AF_DATAKIT =    9,
+	AF_CCITT =      10,
+	AF_SNA =        11,
+	AF_DECnet =     12,
+	AF_DLI =        13,
+	AF_LAT =        14,
+	AF_HYLINK =     15,
+	AF_APPLETALK =  16,
+	AF_NETBIOS =    17,
+	AF_VOICEVIEW =  18,
+	AF_FIREFOX =    19,
+	AF_UNKNOWN1 =   20,
+	AF_BAN =        21,
+	AF_ATM =        22,
+	AF_INET6 =      23,
+	AF_CLUSTER =    24,
+	AF_12844 =      25,
+	AF_IRDA =       26,
+	AF_NETDES =     28,
+	
+	AF_MAX =        29,
+	
+	
+	PF_UNSPEC     = AF_UNSPEC,
+	
+	PF_UNIX =       AF_UNIX,
+	PF_INET =       AF_INET,
+	PF_IMPLINK =    AF_IMPLINK,
+	PF_PUP =        AF_PUP,
+	PF_CHAOS =      AF_CHAOS,
+	PF_NS =         AF_NS,
+	PF_IPX =        AF_IPX,
+	PF_ISO =        AF_ISO,
+	PF_OSI =        AF_OSI,
+	PF_ECMA =       AF_ECMA,
+	PF_DATAKIT =    AF_DATAKIT,
+	PF_CCITT =      AF_CCITT,
+	PF_SNA =        AF_SNA,
+	PF_DECnet =     AF_DECnet,
+	PF_DLI =        AF_DLI,
+	PF_LAT =        AF_LAT,
+	PF_HYLINK =     AF_HYLINK,
+	PF_APPLETALK =  AF_APPLETALK,
+	PF_VOICEVIEW =  AF_VOICEVIEW,
+	PF_FIREFOX =    AF_FIREFOX,
+	PF_UNKNOWN1 =   AF_UNKNOWN1,
+	PF_BAN =        AF_BAN,
+	PF_INET6 =      AF_INET6,
+	
+	PF_MAX        = AF_MAX,
+}
+
+
+enum: int
+{
+	SOL_SOCKET = 0xFFFF,
+}
+
+
+enum: int
+{
+	SO_DEBUG =        0x0001,
+	SO_ACCEPTCONN =   0x0002,
+	SO_REUSEADDR =    0x0004,
+	SO_KEEPALIVE =    0x0008,
+	SO_DONTROUTE =    0x0010,
+	SO_BROADCAST =    0x0020,
+	SO_USELOOPBACK =  0x0040,
+	SO_LINGER =       0x0080,
+	SO_DONTLINGER =   ~SO_LINGER,
+	SO_OOBINLINE =    0x0100,
+	SO_SNDBUF =       0x1001,
+	SO_RCVBUF =       0x1002,
+	SO_SNDLOWAT =     0x1003,
+	SO_RCVLOWAT =     0x1004,
+	SO_SNDTIMEO =     0x1005,
+	SO_RCVTIMEO =     0x1006,
+	SO_ERROR =        0x1007,
+	SO_TYPE =         0x1008,
+	SO_EXCLUSIVEADDRUSE = ~SO_REUSEADDR,
+	
+	TCP_NODELAY =    1,
+	
+	IP_MULTICAST_LOOP =  0x4,
+	IP_ADD_MEMBERSHIP =  0x5,
+	IP_DROP_MEMBERSHIP = 0x6,
+	
+	IPV6_UNICAST_HOPS =    4,
+	IPV6_MULTICAST_IF =    9,
+	IPV6_MULTICAST_HOPS =  10,
+	IPV6_MULTICAST_LOOP =  11,
+	IPV6_ADD_MEMBERSHIP =  12,
+	IPV6_DROP_MEMBERSHIP = 13,
+	IPV6_JOIN_GROUP =      IPV6_ADD_MEMBERSHIP,
+	IPV6_LEAVE_GROUP =     IPV6_DROP_MEMBERSHIP,
+}
+
+
+const uint FD_SETSIZE = 64;
+
+
+struct fd_set
+{
+	UINT fd_count;
+	SOCKET[FD_SETSIZE] fd_array;
+}
+
+
+// Removes.
+void FD_CLR(SOCKET fd, fd_set* set)
+{
+	uint c = set.fd_count;
+	SOCKET* start = set.fd_array.ptr;
+	SOCKET* stop = start + c;
+	
+	for(; start != stop; start++)
+	{
+		if(*start == fd)
+			goto found;
+	}
+	return; //not found
+	
+	found:
+	for(++start; start != stop; start++)
+	{
+		*(start - 1) = *start;
+	}
+	
+	set.fd_count = c - 1;
+}
+
+
+// Tests.
+int FD_ISSET(SOCKET fd, fd_set* set)
+{
+	SOCKET* start = set.fd_array.ptr;
+	SOCKET* stop = start + set.fd_count;
+	
+	for(; start != stop; start++)
+	{
+		if(*start == fd)
+			return true;
+	}
+	return false;
+}
+
+
+// Adds.
+void FD_SET(SOCKET fd, fd_set* set)
+{
+	uint c = set.fd_count;
+	set.fd_array.ptr[c] = fd;
+	set.fd_count = c + 1;
+}
+
+
+// Resets to zero.
+void FD_ZERO(fd_set* set)
+{
+	set.fd_count = 0;
+}
+
+
+struct linger
+{
+	USHORT l_onoff;
+	USHORT l_linger;
+}
+
+
+struct protoent
+{
+	char* p_name;
+	char** p_aliases;
+	SHORT p_proto;
+}
+
+
+struct servent
+{
+	char* s_name;
+	char** s_aliases;
+	SHORT s_port;
+	char* s_proto;
+}
+
+
+/+
+union in6_addr
+{
+	private union _u_t
+	{
+		BYTE[16] Byte;
+		WORD[8] Word;
+	}
+	_u_t u;
+}
+
+
+struct in_addr6
+{
+	BYTE[16] s6_addr;
+}
++/
+
+
+version(BigEndian)
+{
+	uint16_t htons(uint16_t x)
+	{
+		return x;
+	}
+	
+	
+	uint32_t htonl(uint32_t x)
+	{
+		return x;
+	}
+}
+else version(LittleEndian)
+{
+	private import std.intrinsic;
+	
+	
+	uint16_t htons(uint16_t x)
+	{
+		return cast(uint16_t)((x >> 8) | (x << 8));
+	}
+
+
+	uint32_t htonl(uint32_t x)
+	{
+		return bswap(x);
+	}
+}
+else
+{
+	static assert(0);
+}
+
+
+uint16_t ntohs(uint16_t x)
+{
+	return htons(x);
+}
+
+
+uint32_t ntohl(uint32_t x)
+{
+	return htonl(x);
+}
+
+
+enum: int
+{
+	SOCK_STREAM =     1,
+	SOCK_DGRAM =      2,
+	SOCK_RAW =        3,
+	SOCK_RDM =        4,
+	SOCK_SEQPACKET =  5,
+}
+
+
+enum: int
+{
+	IPPROTO_IP =    0,
+	IPPROTO_ICMP =  1,
+	IPPROTO_IGMP =  2,
+	IPPROTO_GGP =   3,
+	IPPROTO_TCP =   6,
+	IPPROTO_PUP =   12,
+	IPPROTO_UDP =   17,
+	IPPROTO_IDP =   22,
+	IPPROTO_IPV6 =  41,
+	IPPROTO_ND =    77,
+	IPPROTO_RAW =   255,
+	
+	IPPROTO_MAX =   256,
+}
+
+
+enum: int
+{
+	MSG_OOB =        0x1,
+	MSG_PEEK =       0x2,
+	MSG_DONTROUTE =  0x4,
+        MSG_NOSIGNAL =   0x0, /// not supported on win32, would be 0x4000 if it was
+}
+
+
+enum: int
+{
+	SD_RECEIVE =  0,
+	SD_SEND =     1,
+	SD_BOTH =     2,
+}
+
+
+enum: uint
+{
+	INADDR_ANY =        0,
+	INADDR_LOOPBACK =   0x7F000001,
+	INADDR_BROADCAST =  0xFFFFFFFF,
+	INADDR_NONE =       0xFFFFFFFF,
+	ADDR_ANY =          INADDR_ANY,
+}
+
+
+enum: int
+{
+	AI_PASSIVE = 0x1,
+	AI_CANONNAME = 0x2,
+	AI_NUMERICHOST = 0x4,
+}
+
+
+struct timeval
+{
+	int32_t tv_sec;
+	int32_t tv_usec;
+}
+
+
+union in_addr
+{
+	private union _S_un_t
+	{
+		private struct _S_un_b_t
+		{
+			uint8_t s_b1, s_b2, s_b3, s_b4;
+		}
+		_S_un_b_t S_un_b;
+		
+		private struct _S_un_w_t
+		{
+			uint16_t s_w1, s_w2;
+		}
+		_S_un_w_t S_un_w;
+		
+		uint32_t S_addr;
+	}
+	_S_un_t S_un;
+	
+	uint32_t s_addr;
+	
+	struct
+	{
+		uint8_t s_net, s_host;
+		
+		union
+		{
+			uint16_t s_imp;
+			
+			struct
+			{
+				uint8_t s_lh, s_impno;
+			}
+		}
+	}
+}
+
+
+union in6_addr
+{
+	private union _in6_u_t
+	{
+		uint8_t[16] u6_addr8;
+		uint16_t[8] u6_addr16;
+		uint32_t[4] u6_addr32;
+	}
+	_in6_u_t in6_u;
+	
+	uint8_t[16] s6_addr8;
+	uint16_t[8] s6_addr16;
+	uint32_t[4] s6_addr32;
+	
+	alias s6_addr8 s6_addr;
+}
+
+
+const in6_addr IN6ADDR_ANY = { s6_addr8: [0] };
+const in6_addr IN6ADDR_LOOPBACK = { s6_addr8: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] };
+//alias IN6ADDR_ANY IN6ADDR_ANY_INIT;
+//alias IN6ADDR_LOOPBACK IN6ADDR_LOOPBACK_INIT;
+	
+const uint INET_ADDRSTRLEN = 16;
+const uint INET6_ADDRSTRLEN = 46;
+
+
+struct sockaddr
+{
+	int16_t sa_family;               
+	ubyte[14] sa_data;             
+}
+
+
+struct sockaddr_in
+{
+	int16_t sin_family = AF_INET;
+	uint16_t sin_port;
+	in_addr sin_addr;
+	ubyte[8] sin_zero;
+}
+
+
+struct sockaddr_in6
+{
+	int16_t sin6_family = AF_INET6;
+	uint16_t sin6_port;
+	uint32_t sin6_flowinfo;
+	in6_addr sin6_addr;
+	uint32_t sin6_scope_id;
+}
+
+
+struct addrinfo
+{
+	int32_t ai_flags; 
+	int32_t ai_family;
+	int32_t ai_socktype;
+	int32_t ai_protocol;
+	size_t ai_addrlen;
+	char* ai_canonname;
+	sockaddr* ai_addr;
+	addrinfo* ai_next;
+}
+
+
+struct hostent
+{
+	char* h_name;
+	char** h_aliases;
+	int16_t h_addrtype;
+	int16_t h_length;
+	char** h_addr_list;
+	
+	
+	char* h_addr()
+	{
+		return h_addr_list[0];
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/cstream.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,228 @@
+/**
+ * The std.cstream module bridges std.c.stdio (or std.stdio) and std.stream.
+ * Both std.c.stdio and std.stream are publicly imported by std.cstream.
+ * Authors: Ben Hinkle
+ * License: Public Domain
+ * Macros:
+ *	WIKI=Phobos/StdCstream
+ */
+
+module std.cstream;
+
+import std.stream;
+import std.c.stdio;
+
+/**
+ * A Stream wrapper for a C file of type FILE*.
+ */
+class CFile : Stream {
+  FILE* cfile;
+
+  /**
+   * Create the stream wrapper for the given C file.
+   * Params:
+   *   mode = a bitwise combination of $(B FileMode.In) for a readable file
+   *          and $(B FileMode.Out) for a writeable file.
+   *   seekable = indicates if the stream should be _seekable.
+   */
+  this(FILE* cfile, FileMode mode, bool seekable = false) {
+    super();
+    this.file = cfile;
+    readable = cast(bool)(mode & FileMode.In);
+    writeable = cast(bool)(mode & FileMode.Out);
+    this.seekable = seekable;
+  }
+
+  /**
+   * Closes the stream.
+   */
+  ~this() { close(); }
+
+  /**
+   * Property to get or set the underlying file for this stream.
+   * Setting the file marks the stream as open.
+   */
+  FILE* file() { return cfile; }
+
+  /**
+   * Ditto
+   */
+  void file(FILE* cfile) {
+    this.cfile = cfile; 
+    isopen = true;
+  }
+
+  /**
+   * Overrides of the $(B Stream) methods to call the underlying $(B FILE*)
+   * C functions.
+   */
+  override void flush() { fflush(cfile); }
+
+  /**
+   * Ditto
+   */
+  override void close() { 
+    if (isopen)
+      fclose(cfile); 
+    isopen = readable = writeable = seekable = false; 
+  }
+
+  /**
+   * Ditto
+   */
+  override bool eof() { 
+    return cast(bool)(readEOF || feof(cfile)); 
+  }
+
+  /**
+   * Ditto
+   */
+  override char getc() { 
+    return cast(char)fgetc(cfile); 
+  }
+
+  /**
+   * Ditto
+   */
+  override char ungetc(char c) { 
+    return cast(char)std.c.stdio.ungetc(c,cfile); 
+  }
+
+  /**
+   * Ditto
+   */
+  override size_t readBlock(void* buffer, size_t size) {
+    size_t n = fread(buffer,1,size,cfile);
+    readEOF = cast(bool)(n == 0);
+    return n;
+  }
+
+  /**
+   * Ditto
+   */
+  override size_t writeBlock(void* buffer, size_t size) {
+    return fwrite(buffer,1,size,cfile);
+  }
+
+  /**
+   * Ditto
+   */
+  override ulong seek(long offset, SeekPos rel) {
+    readEOF = false;
+    if (fseek(cfile,cast(int)offset,rel) != 0)
+      throw new SeekException("unable to move file pointer");
+    return ftell(cfile);
+  }
+
+  /**
+   * Ditto
+   */
+  override void writeLine(char[] s) {
+    writeString(s);
+    writeString("\n");
+  }
+
+  /**
+   * Ditto
+   */
+  override void writeLineW(wchar[] s) {
+    writeStringW(s);
+    writeStringW("\n");
+  }
+
+  // run a few tests
+  unittest {
+    FILE* f = fopen("stream.txt","w");
+    assert(f !is null);
+    CFile file = new CFile(f,FileMode.Out);
+    int i = 666;
+    // should be ok to write
+    assert(file.writeable);
+    file.writeLine("Testing stream.d:");
+    file.writeString("Hello, world!");
+    file.write(i);
+    // string#1 + string#2 + int should give exacly that
+    version (Win32)
+      assert(file.position() == 19 + 13 + 4);
+    version (linux)
+      assert(file.position() == 18 + 13 + 4);
+    file.close();
+    // no operations are allowed when file is closed
+    assert(!file.readable && !file.writeable && !file.seekable);
+    f = fopen("stream.txt","r");
+    file = new CFile(f,FileMode.In,true);
+    // should be ok to read
+    assert(file.readable);
+    char[] line = file.readLine();
+    char[] exp = "Testing stream.d:";
+    assert(line[0] == 'T');
+    assert(line.length == exp.length);
+    assert(!std.string.cmp(line, "Testing stream.d:"));
+    // jump over "Hello, "
+    file.seek(7, SeekPos.Current);
+    version (Win32)
+      assert(file.position() == 19 + 7);
+    version (linux)
+      assert(file.position() == 18 + 7);
+    assert(!std.string.cmp(file.readString(6), "world!"));
+    i = 0; file.read(i);
+    assert(i == 666);
+    // string#1 + string#2 + int should give exacly that
+    version (Win32)
+      assert(file.position() == 19 + 13 + 4);
+    version (linux)
+      assert(file.position() == 18 + 13 + 4);
+    // we must be at the end of file
+    file.close();
+    f = fopen("stream.txt","w+");
+    file = new CFile(f,FileMode.In|FileMode.Out,true);
+    file.writeLine("Testing stream.d:");
+    file.writeLine("Another line");
+    file.writeLine("");
+    file.writeLine("That was blank");
+    file.position = 0;
+    char[][] lines;
+    foreach(char[] line; file) {
+      lines ~= line.dup;
+    }
+    assert( lines.length == 5 );
+    assert( lines[0] == "Testing stream.d:");
+    assert( lines[1] == "Another line");
+    assert( lines[2] == "");
+    assert( lines[3] == "That was blank");
+    file.position = 0;
+    lines = new char[][5];
+    foreach(ulong n, char[] line; file) {
+      lines[cast(size_t)(n-1)] = line.dup;
+    }
+    assert( lines[0] == "Testing stream.d:");
+    assert( lines[1] == "Another line");
+    assert( lines[2] == "");
+    assert( lines[3] == "That was blank");
+    file.close();
+    remove("stream.txt");
+  }
+}
+
+/**
+ * CFile wrapper of std.c.stdio.stdin (not seekable).
+ */
+CFile din;
+
+/**
+ * CFile wrapper of std.c.stdio.stdout (not seekable).
+ */
+CFile dout;
+
+/**
+ * CFile wrapper of std.c.stdio.stderr (not seekable).
+ */
+CFile derr;
+
+static this() {
+  // open standard I/O devices
+  din = new CFile(std.c.stdio.stdin,FileMode.In);
+  dout = new CFile(std.c.stdio.stdout,FileMode.Out);
+  derr = new CFile(std.c.stdio.stderr,FileMode.Out);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/date.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,1074 @@
+
+// Written in the D programming language.
+
+/**
+ * Dates are represented in several formats. The date implementation revolves
+ * around a central type, d_time, from which other formats are converted to and
+ * from.
+ * Dates are calculated using the Gregorian calendar.
+ * References:
+ *	$(LINK2 http://en.wikipedia.org/wiki/Gregorian_calendar, Gregorian calendar (Wikipedia))
+ * Macros:
+ *	WIKI = Phobos/StdDate
+ */
+
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+
+/* NOTE: This file has been patched from the original DMD distribution to
+   work with the GDC compiler.
+
+   Modified by David Friedman, May 2005
+*/
+
+module std.date;
+
+private import std.stdio;
+private import std.dateparse;
+
+/**
+ * d_time is a signed arithmetic type giving the time elapsed since January 1,
+ * 1970.
+ * Negative values are for dates preceding 1970. The time unit used is Ticks.
+ * Ticks are milliseconds or smaller intervals.
+ *
+ * The usual arithmetic operations can be performed on d_time, such as adding,
+ * subtracting, etc. Elapsed time in Ticks can be computed by subtracting a
+ * starting d_time from an ending d_time. 
+ */
+alias long d_time;
+
+/**
+ * A value for d_time that does not represent a valid time.
+ */
+const d_time d_time_nan = long.min;
+
+/**
+ * Time broken down into its components.
+ */
+struct Date
+{
+    int year = int.min;	/// use int.min as "nan" year value
+    int month;		/// 1..12
+    int day;		/// 1..31
+    int hour;		/// 0..23
+    int minute;		/// 0..59
+    int second;		/// 0..59
+    int ms;		/// 0..999
+    int weekday;	/// 0: not specified, 1..7: Sunday..Saturday
+    int tzcorrection = int.min;	/// -1200..1200 correction in hours
+
+    /// Parse date out of string s[] and store it in this Date instance.
+    void parse(string s)
+    {
+	DateParse dp;
+
+	dp.parse(s, *this);
+    }
+}
+
+enum
+{
+	HoursPerDay    = 24,
+	MinutesPerHour = 60,
+	msPerMinute    = 60 * 1000,
+	msPerHour      = 60 * msPerMinute,
+	msPerDay       = 86400000,
+	TicksPerMs     = 1,
+	TicksPerSecond = 1000,			/// Will be at least 1000
+	TicksPerMinute = TicksPerSecond * 60,
+	TicksPerHour   = TicksPerMinute * 60,
+	TicksPerDay    = TicksPerHour   * 24,
+}
+
+d_time LocalTZA = 0;
+
+
+const char[] daystr = "SunMonTueWedThuFriSat";
+const char[] monstr = "JanFebMarAprMayJunJulAugSepOctNovDec";
+
+const int[12] mdays = [ 0,31,59,90,120,151,181,212,243,273,304,334 ];
+
+/********************************
+ * Compute year and week [1..53] from t. The ISO 8601 week 1 is the first week
+ * of the year that includes January 4. Monday is the first day of the week.
+ * References:
+ *	$(LINK2 http://en.wikipedia.org/wiki/ISO_8601, ISO 8601 (Wikipedia))
+ */
+
+void toISO8601YearWeek(d_time t, out int year, out int week)
+{
+    year = YearFromTime(t);
+
+    int yday = Day(t) - DayFromYear(year);
+    int d;
+    int w;
+    int ydaybeg;
+
+    /* Determine day of week Jan 4 falls on.
+     * Weeks begin on a Monday.
+     */
+
+    d = DayFromYear(year);
+    w = (d + 3/*Jan4*/ + 3) % 7;
+    if (w < 0)
+        w += 7;
+
+    /* Find yday of beginning of ISO 8601 year
+     */
+    ydaybeg = 3/*Jan4*/ - w;
+
+    /* Check if yday is actually the last week of the previous year
+     */
+    if (yday < ydaybeg)
+    {
+	year -= 1;
+	week = 53;
+        return;
+    }
+
+    /* Check if yday is actually the first week of the next year
+     */
+    if (yday >= 362)                            // possible
+    {   int d2;
+        int ydaybeg2;
+
+        d2 = DayFromYear(year + 1);
+        w = (d2 + 3/*Jan4*/ + 3) % 7;
+        if (w < 0)
+            w += 7;
+        //printf("w = %d\n", w);
+        ydaybeg2 = 3/*Jan4*/ - w;
+        if (d + yday >= d2 + ydaybeg2)
+        {
+	    year += 1;
+	    week = 1;
+            return;
+        }
+    }
+
+    week = (yday - ydaybeg) / 7 + 1;
+}
+
+/* ***********************************
+ * Divide time by divisor. Always round down, even if d is negative.
+ */
+
+d_time floor(d_time d, int divisor)
+{
+    if (d < 0)
+	d -= divisor - 1;
+    return d / divisor;
+}
+
+int dmod(d_time n, d_time d)
+{   d_time r;
+
+    r = n % d;
+    if (r < 0)
+	r += d;
+    assert(cast(int)r == r);
+    return cast(int)r;
+}
+
+int HourFromTime(d_time t)
+{
+    return dmod(floor(t, msPerHour), HoursPerDay);
+}
+
+int MinFromTime(d_time t)
+{
+    return dmod(floor(t, msPerMinute), MinutesPerHour);
+}
+
+int SecFromTime(d_time t)
+{
+    return dmod(floor(t, TicksPerSecond), 60);
+}
+
+int msFromTime(d_time t)
+{
+    return dmod(t / (TicksPerSecond / 1000), 1000);
+}
+
+int TimeWithinDay(d_time t)
+{
+    return dmod(t, msPerDay);
+}
+
+d_time toInteger(d_time n)
+{
+    return n;
+}
+
+int Day(d_time t)
+{
+    return cast(int)floor(t, msPerDay);
+}
+
+int LeapYear(int y)
+{
+    return ((y & 3) == 0 &&
+	    (y % 100 || (y % 400) == 0));
+}
+
+int DaysInYear(int y)
+{
+    return 365 + LeapYear(y);
+}
+
+int DayFromYear(int y)
+{
+    return cast(int) (365 * (y - 1970) +
+		floor((y - 1969), 4) -
+		floor((y - 1901), 100) +
+		floor((y - 1601), 400));
+}
+
+d_time TimeFromYear(int y)
+{
+    return cast(d_time)msPerDay * DayFromYear(y);
+}
+
+/*****************************
+ * Calculates the year from the d_time t.
+ */
+
+int YearFromTime(d_time t)
+{   int y;
+
+    if (t == d_time_nan)
+	return 0;
+
+    // Hazard a guess
+    //y = 1970 + cast(int) (t / (365.2425 * msPerDay));
+    // Use integer only math
+    y = 1970 + cast(int) (t / (3652425 * (msPerDay / 10000)));
+
+    if (TimeFromYear(y) <= t)
+    {
+	while (TimeFromYear(y + 1) <= t)
+	    y++;
+    }
+    else
+    {
+	do
+	{
+	    y--;
+	}
+	while (TimeFromYear(y) > t);
+    }
+    return y;
+}
+
+/*******************************
+ * Determines if d_time t is a leap year.
+ *
+ * A leap year is every 4 years except years ending in 00 that are not
+ * divsible by 400.
+ *
+ * Returns: !=0 if it is a leap year.
+ *
+ * References:
+ *	$(LINK2 http://en.wikipedia.org/wiki/Leap_year, Wikipedia)
+ */
+
+int inLeapYear(d_time t)
+{
+    return LeapYear(YearFromTime(t));
+}
+
+/*****************************
+ * Calculates the month from the d_time t.
+ *
+ * Returns: Integer in the range 0..11, where
+ *	0 represents January and 11 represents December.
+ */
+
+int MonthFromTime(d_time t)
+{
+    int day;
+    int month;
+    int year;
+
+    year = YearFromTime(t);
+    day = Day(t) - DayFromYear(year);
+
+    if (day < 59)
+    {
+	if (day < 31)
+	{   assert(day >= 0);
+	    month = 0;
+	}
+	else
+	    month = 1;
+    }
+    else
+    {
+	day -= LeapYear(year);
+	if (day < 212)
+	{
+	    if (day < 59)
+		month = 1;
+	    else if (day < 90)
+		month = 2;
+	    else if (day < 120)
+		month = 3;
+	    else if (day < 151)
+		month = 4;
+	    else if (day < 181)
+		month = 5;
+	    else
+		month = 6;
+	}
+	else
+	{
+	    if (day < 243)
+		month = 7;
+	    else if (day < 273)
+		month = 8;
+	    else if (day < 304)
+		month = 9;
+	    else if (day < 334)
+		month = 10;
+	    else if (day < 365)
+		month = 11;
+	    else
+		assert(0);
+	}
+    }
+    return month;
+}
+
+/*******************************
+ * Compute which day in a month a d_time t is.
+ * Returns:
+ *	Integer in the range 1..31
+ */
+int DateFromTime(d_time t)
+{
+    int day;
+    int leap;
+    int month;
+    int year;
+    int date;
+
+    year = YearFromTime(t);
+    day = Day(t) - DayFromYear(year);
+    leap = LeapYear(year);
+    month = MonthFromTime(t);
+    switch (month)
+    {
+	case 0:	 date = day +   1;		break;
+	case 1:	 date = day -  30;		break;
+	case 2:	 date = day -  58 - leap;	break;
+	case 3:	 date = day -  89 - leap;	break;
+	case 4:	 date = day - 119 - leap;	break;
+	case 5:	 date = day - 150 - leap;	break;
+	case 6:	 date = day - 180 - leap;	break;
+	case 7:	 date = day - 211 - leap;	break;
+	case 8:	 date = day - 242 - leap;	break;
+	case 9:	 date = day - 272 - leap;	break;
+	case 10: date = day - 303 - leap;	break;
+	case 11: date = day - 333 - leap;	break;
+	default:
+	    assert(0);
+    }
+    return date;
+}
+
+/*******************************
+ * Compute which day of the week a d_time t is.
+ * Returns:
+ *	Integer in the range 0..6, where 0 represents Sunday
+ *	and 6 represents Saturday.
+ */
+int WeekDay(d_time t)
+{   int w;
+
+    w = (cast(int)Day(t) + 4) % 7;
+    if (w < 0)
+	w += 7;
+    return w;
+}
+
+/***********************************
+ * Convert from UTC to local time.
+ */
+
+d_time UTCtoLocalTime(d_time t)
+{
+    return (t == d_time_nan)
+	? d_time_nan
+	: t + LocalTZA + DaylightSavingTA(t);
+}
+
+/***********************************
+ * Convert from local time to UTC.
+ */
+
+d_time LocalTimetoUTC(d_time t)
+{
+    return (t == d_time_nan)
+	? d_time_nan
+	: t - LocalTZA - DaylightSavingTA(t - LocalTZA);
+}
+
+
+d_time MakeTime(d_time hour, d_time min, d_time sec, d_time ms)
+{
+    return hour * TicksPerHour +
+	   min * TicksPerMinute +
+	   sec * TicksPerSecond +
+	   ms * TicksPerMs;
+}
+
+
+d_time MakeDay(d_time year, d_time month, d_time date)
+{   d_time t;
+    int y;
+    int m;
+    int leap;
+
+    y = cast(int)(year + floor(month, 12));
+    m = dmod(month, 12);
+
+    leap = LeapYear(y);
+    t = TimeFromYear(y) + cast(d_time)mdays[m] * msPerDay;
+    if (leap && month >= 2)
+	t += msPerDay;
+
+    if (YearFromTime(t) != y ||
+	MonthFromTime(t) != m ||
+	DateFromTime(t) != 1)
+    {
+	return  d_time_nan;
+    }
+
+    return Day(t) + date - 1;
+}
+
+d_time MakeDate(d_time day, d_time time)
+{
+    if (day == d_time_nan || time == d_time_nan)
+	return d_time_nan;
+
+    return day * TicksPerDay + time;
+}
+
+d_time TimeClip(d_time time)
+{
+    //printf("TimeClip(%g) = %g\n", time, toInteger(time));
+
+    return toInteger(time);
+}
+
+/*************************************
+ * Converts UTC time into a text string of the form:
+ * "Www Mmm dd hh:mm:ss GMT+-TZ yyyy".
+ * For example, "Tue Apr 02 02:04:57 GMT-0800 1996".
+ * If time is invalid, i.e. is d_time_nan,
+ * the string "Invalid date" is returned.
+ *
+ * Example:
+ * ------------------------------------
+  d_time lNow;
+  char[] lNowString;
+
+  // Grab the date and time relative to UTC
+  lNow = std.date.getUTCtime();
+  // Convert this into the local date and time for display.
+  lNowString = std.date.toString(lNow);
+ * ------------------------------------
+ */
+
+string toString(d_time time)
+{
+    d_time t;
+    char sign;
+    int hr;
+    int mn;
+    int len;
+    d_time offset;
+    d_time dst;
+
+    // Years are supposed to be -285616 .. 285616, or 7 digits
+    // "Tue Apr 02 02:04:57 GMT-0800 1996"
+    char[] buffer = new char[29 + 7 + 1];
+
+    if (time == d_time_nan)
+	return "Invalid Date";
+
+    dst = DaylightSavingTA(time);
+    offset = LocalTZA + dst;
+    t = time + offset;
+    sign = '+';
+    if (offset < 0)
+    {	sign = '-';
+//	offset = -offset;
+	offset = -(LocalTZA + dst);
+    }
+
+    mn = cast(int)(offset / msPerMinute);
+    hr = mn / 60;
+    mn %= 60;
+
+    //printf("hr = %d, offset = %g, LocalTZA = %g, dst = %g, + = %g\n", hr, offset, LocalTZA, dst, LocalTZA + dst);
+
+    len = sprintf(buffer.ptr, "%.3s %.3s %02d %02d:%02d:%02d GMT%c%02d%02d %d",
+	&daystr[WeekDay(t) * 3],
+	&monstr[MonthFromTime(t) * 3],
+	DateFromTime(t),
+	HourFromTime(t), MinFromTime(t), SecFromTime(t),
+	sign, hr, mn,
+	/*cast(long)*/YearFromTime(t));
+
+    // Ensure no buggy buffer overflows
+    //printf("len = %d, buffer.length = %d\n", len, buffer.length);
+    assert(len < buffer.length);
+
+    return buffer[0 .. len];
+}
+
+/***********************************
+ * Converts t into a text string of the form: "Www, dd Mmm yyyy hh:mm:ss UTC".
+ * If t is invalid, "Invalid date" is returned.
+ */
+
+string toUTCString(d_time t)
+{
+    // Years are supposed to be -285616 .. 285616, or 7 digits
+    // "Tue, 02 Apr 1996 02:04:57 GMT"
+    char[] buffer = new char[25 + 7 + 1];
+    int len;
+
+    if (t == d_time_nan)
+	return "Invalid Date";
+
+    len = sprintf(buffer.ptr, "%.3s, %02d %.3s %d %02d:%02d:%02d UTC",
+	&daystr[WeekDay(t) * 3], DateFromTime(t),
+	&monstr[MonthFromTime(t) * 3],
+	YearFromTime(t),
+	HourFromTime(t), MinFromTime(t), SecFromTime(t));
+
+    // Ensure no buggy buffer overflows
+    assert(len < buffer.length);
+
+    return buffer[0 .. len];
+}
+
+/************************************
+ * Converts the date portion of time into a text string of the form: "Www Mmm dd
+ * yyyy", for example, "Tue Apr 02 1996".
+ * If time is invalid, "Invalid date" is returned.
+ */
+
+string toDateString(d_time time)
+{
+    d_time t;
+    d_time offset;
+    d_time dst;
+    int len;
+
+    // Years are supposed to be -285616 .. 285616, or 7 digits
+    // "Tue Apr 02 1996"
+    char[] buffer = new char[29 + 7 + 1];
+
+    if (time == d_time_nan)
+	return "Invalid Date";
+
+    dst = DaylightSavingTA(time);
+    offset = LocalTZA + dst;
+    t = time + offset;
+
+    len = sprintf(buffer.ptr, "%.3s %.3s %02d %d",
+	&daystr[WeekDay(t) * 3],
+	&monstr[MonthFromTime(t) * 3],
+	DateFromTime(t),
+	/*cast(long)*/YearFromTime(t));
+
+    // Ensure no buggy buffer overflows
+    assert(len < buffer.length);
+
+    return buffer[0 .. len];
+}
+
+/******************************************
+ * Converts the time portion of t into a text string of the form: "hh:mm:ss
+ * GMT+-TZ", for example, "02:04:57 GMT-0800".
+ * If t is invalid, "Invalid date" is returned.
+ * The input must be in UTC, and the output is in local time.
+ */
+
+string toTimeString(d_time time)
+{
+    d_time t;
+    char sign;
+    int hr;
+    int mn;
+    int len;
+    d_time offset;
+    d_time dst;
+
+    // "02:04:57 GMT-0800"
+    char[] buffer = new char[17 + 1];
+
+    if (time == d_time_nan)
+	return "Invalid Date";
+
+    dst = DaylightSavingTA(time);
+    offset = LocalTZA + dst;
+    t = time + offset;
+    sign = '+';
+    if (offset < 0)
+    {	sign = '-';
+//	offset = -offset;
+	offset = -(LocalTZA + dst);
+    }
+
+    mn = cast(int)(offset / msPerMinute);
+    hr = mn / 60;
+    mn %= 60;
+
+    //printf("hr = %d, offset = %g, LocalTZA = %g, dst = %g, + = %g\n", hr, offset, LocalTZA, dst, LocalTZA + dst);
+
+    len = sprintf(buffer.ptr, "%02d:%02d:%02d GMT%c%02d%02d",
+	HourFromTime(t), MinFromTime(t), SecFromTime(t),
+	sign, hr, mn);
+
+    // Ensure no buggy buffer overflows
+    assert(len < buffer.length);
+
+    // Lop off terminating 0
+    return buffer[0 .. len];
+}
+
+
+/******************************************
+ * Parses s as a textual date string, and returns it as a d_time.
+ * If the string is not a valid date, d_time_nan is returned.
+ */
+
+d_time parse(string s)
+{
+    Date dp;
+    d_time n;
+    d_time day;
+    d_time time;
+
+    try
+    {
+	dp.parse(s);
+
+	//writefln("year = %d, month = %d, day = %d", dp.year, dp.month, dp.day);
+	//writefln("%02d:%02d:%02d.%03d", dp.hour, dp.minute, dp.second, dp.ms);
+	//writefln("weekday = %d, ampm = %d, tzcorrection = %d", dp.weekday, 1, dp.tzcorrection);
+
+	time = MakeTime(dp.hour, dp.minute, dp.second, dp.ms);
+	if (dp.tzcorrection == int.min)
+	    time -= LocalTZA;
+	else
+	{
+	    time += cast(d_time)(dp.tzcorrection / 100) * msPerHour +
+		    cast(d_time)(dp.tzcorrection % 100) * msPerMinute;
+	}
+	day = MakeDay(dp.year, dp.month - 1, dp.day);
+	n = MakeDate(day,time);
+	n = TimeClip(n);
+    }
+    catch
+    {
+	n =  d_time_nan;		// erroneous date string
+    }
+    return n;
+}
+
+static this()
+{
+    LocalTZA = getLocalTZA();
+    //printf("LocalTZA = %g, %g\n", LocalTZA, LocalTZA / msPerHour);
+}
+
+version (Win32)
+{
+
+    private import std.c.windows.windows;
+    //import c.time;
+
+    /******
+     * Get current UTC time.
+     */
+    d_time getUTCtime()
+    {
+	SYSTEMTIME st;
+	d_time n;
+
+	GetSystemTime(&st);		// get time in UTC
+	n = SYSTEMTIME2d_time(&st, 0);
+	return n;
+	//return c.time.time(null) * TicksPerSecond;
+    }
+
+    static d_time FILETIME2d_time(FILETIME *ft)
+    {   SYSTEMTIME st;
+
+	if (!FileTimeToSystemTime(ft, &st))
+	    return d_time_nan;
+	return SYSTEMTIME2d_time(&st, 0);
+    }
+
+    static d_time SYSTEMTIME2d_time(SYSTEMTIME *st, d_time t)
+    {
+	d_time n;
+	d_time day;
+	d_time time;
+
+	if (st.wYear)
+	{
+	    time = MakeTime(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
+	    day = MakeDay(st.wYear, st.wMonth - 1, st.wDay);
+	}
+	else
+	{   // wDayOfWeek is weekday, wDay is which week in the month
+	    int year;
+	    int wd;
+	    int mday;
+	    int month;
+	    d_time x;
+
+	    year = YearFromTime(t);
+	    month = st.wMonth - 1;
+	    x = MakeDay(year, month, 1);
+	    wd = WeekDay(MakeDate(x, 0));
+
+	    mday = (7 - wd + st.wDayOfWeek);
+	    if (mday >= 7)
+		mday -= 7;
+	    mday += (st.wDay - 1) * 7 + 1;
+	    //printf("month = %d, wDayOfWeek = %d, wDay = %d, mday = %d\n", st.wMonth, st.wDayOfWeek, st.wDay, mday);
+
+	    day = MakeDay(year, month, mday);
+	    time = 0;
+	}
+	n = MakeDate(day,time);
+	n = TimeClip(n);
+	return n;
+    }
+
+    d_time getLocalTZA()
+    {
+	d_time t;
+	DWORD r;
+	TIME_ZONE_INFORMATION tzi;
+
+	/* http://msdn.microsoft.com/library/en-us/sysinfo/base/gettimezoneinformation.asp
+	 * http://msdn2.microsoft.com/en-us/library/ms725481.aspx
+	 */
+	r = GetTimeZoneInformation(&tzi);
+	//printf("bias = %d\n", tzi.Bias);
+	//printf("standardbias = %d\n", tzi.StandardBias);
+	//printf("daylightbias = %d\n", tzi.DaylightBias);
+	switch (r)
+	{
+	    case TIME_ZONE_ID_STANDARD:
+		t = -(tzi.Bias + tzi.StandardBias) * cast(d_time)(60 * TicksPerSecond);
+		break;
+	    case TIME_ZONE_ID_DAYLIGHT:
+		//t = -(tzi.Bias + tzi.DaylightBias) * cast(d_time)(60 * TicksPerSecond);
+		//break;
+	    case TIME_ZONE_ID_UNKNOWN:
+		t = -(tzi.Bias) * cast(d_time)(60 * TicksPerSecond);
+		break;
+
+	    default:
+		t = 0;
+		break;
+	}
+
+	return t;
+    }
+
+    /*
+     * Get daylight savings time adjust for time dt.
+     */
+
+    int DaylightSavingTA(d_time dt)
+    {
+	int t;
+	DWORD r;
+	TIME_ZONE_INFORMATION tzi;
+	d_time ts;
+	d_time td;
+
+	/* http://msdn.microsoft.com/library/en-us/sysinfo/base/gettimezoneinformation.asp
+	 */
+	r = GetTimeZoneInformation(&tzi);
+	t = 0;
+	switch (r)
+	{
+	    case TIME_ZONE_ID_STANDARD:
+	    case TIME_ZONE_ID_DAYLIGHT:
+		if (tzi.StandardDate.wMonth == 0 ||
+		    tzi.DaylightDate.wMonth == 0)
+		    break;
+
+		ts = SYSTEMTIME2d_time(&tzi.StandardDate, dt);
+		td = SYSTEMTIME2d_time(&tzi.DaylightDate, dt);
+
+		if (td <= dt && dt <= ts)
+		{
+		    t = -tzi.DaylightBias * (60 * TicksPerSecond);
+		    //printf("DST is in effect, %d\n", t);
+		}
+		else
+		{
+		    //printf("no DST\n");
+		}
+		break;
+
+	    case TIME_ZONE_ID_UNKNOWN:
+		// Daylight savings time not used in this time zone
+		break;
+
+	    default:
+		assert(0);
+	}
+	return t;
+    }
+}
+else version (linux)
+{
+
+    private import std.c.linux.linux;
+
+    d_time getUTCtime()
+    {   timeval tv;
+
+	//printf("getUTCtime()\n");
+	if (gettimeofday(&tv, null))
+	{   // Some error happened - try time() instead
+	    return time(null) * TicksPerSecond;
+	}
+
+	return tv.tv_sec * cast(d_time)TicksPerSecond +
+		(tv.tv_usec / (1000000 / cast(d_time)TicksPerSecond));
+    }
+
+    d_time getLocalTZA()
+    {
+	__time_t t;
+
+	time(&t);
+	localtime(&t);	// this will set timezone
+	return -(timezone * TicksPerSecond);
+    }
+
+    /*
+     * Get daylight savings time adjust for time dt.
+     */
+
+    int DaylightSavingTA(d_time dt)
+    {
+	tm *tmp;
+	int dst = 0;
+
+	if (dt != d_time_nan)
+	{
+	    d_time seconds = dt / TicksPerSecond;
+	    int t;
+	    t = cast(int) seconds;
+	    if (t == seconds)	// if in range
+	    {
+		tmp = localtime(cast(__time_t*)&t);
+		if (tmp.tm_isdst > 0)
+		    dst = TicksPerHour;	// BUG: Assume daylight savings time is plus one hour.
+	    }
+	    else	// out of range for system time, use our own calculation
+	    {	// Daylight savings time goes from 2 AM the first Sunday
+		// in April through 2 AM the last Sunday in October
+
+		dt -= LocalTZA;
+
+		int year = YearFromTime(dt);
+		int leap = LeapYear(dt);
+		//writefln("year = %s, leap = %s, month = %s", year, leap, MonthFromTime(dt));
+
+		d_time start = TimeFromYear(year);		// Jan 1
+		d_time end = start;
+		// Move fwd to Apr 1
+		start += cast(d_time)(mdays[3] + leap) * TicksPerDay;
+		// Advance a day at a time until we find Sunday (0)
+		while (WeekDay(start) != 0)
+		    start += TicksPerDay;
+
+		// Move fwd to Oct 30
+		end += cast(d_time)(mdays[9] + leap + 30) * TicksPerDay;
+		// Back up a day at a time until we find Sunday (0)
+		while (WeekDay(end) != 0)		// 0 is Sunday
+		    end -= TicksPerDay;
+
+		dt -= 2 * TicksPerHour;			// 2 AM
+		if (dt >= start && dt <= end)
+		    dst = TicksPerHour;
+		//writefln("start = %s, dt = %s, end = %s, dst = %s", start, dt, end, dst);
+	    }
+	}
+	return dst;
+    }
+
+}
+else version (Unix)
+{
+    // for now, just copy linux
+    private import std.c.unix.unix;
+
+    d_time getUTCtime()
+    {   timeval tv;
+
+	if (gettimeofday(&tv, null))
+	{   // Some error happened - try time() instead
+	    return time(null) * TicksPerSecond;
+	}
+
+	return tv.tv_sec * cast(d_time)TicksPerSecond +
+		(tv.tv_usec / (1000000 / cast(d_time)TicksPerSecond));
+    }
+
+    private extern (C) time_t _d_gnu_cbridge_tza();
+    
+    d_time getLocalTZA()
+    {
+	return _d_gnu_cbridge_tza() * TicksPerSecond;
+    }
+
+    /*
+     * Get daylight savings time adjust for time dt.
+     */
+
+    int DaylightSavingTA(d_time dt)
+    {
+	tm *tmp;
+	time_t t;
+	int dst = 0;
+
+	if (dt != d_time_nan)
+	{
+	    d_time seconds = dt / TicksPerSecond;
+	    t = cast(time_t) seconds;
+	    if (t == seconds)	// if in range
+	    {
+		tmp = localtime(&t);
+		if (tmp.tm_isdst > 0)
+		    dst = TicksPerHour;	// BUG: Assume daylight savings time is plus one hour.
+	    }
+	    else	// out of range for system time, use our own calculation
+	    {	// Daylight savings time goes from 2 AM the first Sunday
+		// in April through 2 AM the last Sunday in October
+
+		dt -= LocalTZA;
+
+		int year = YearFromTime(dt);
+		int leap = LeapYear(cast(int)dt);
+		//writefln("year = %s, leap = %s, month = %s", year, leap, MonthFromTime(dt));
+
+		d_time start = TimeFromYear(year);		// Jan 1
+		d_time end = start;
+		// Move fwd to Apr 1
+		start += cast(d_time)(mdays[3] + leap) * TicksPerDay;
+		// Advance a day at a time until we find Sunday (0)
+		while (WeekDay(start) != 0)
+		    start += TicksPerDay;
+
+		// Move fwd to Oct 30
+		end += cast(d_time)(mdays[9] + leap + 30) * TicksPerDay;
+		// Back up a day at a time until we find Sunday (0)
+		while (WeekDay(end) != 0)		// 0 is Sunday
+		    end -= TicksPerDay;
+
+		dt -= 2 * TicksPerHour;			// 2 AM
+		if (dt >= start && dt <= end)
+		    dst = TicksPerHour;
+		//writefln("start = %s, dt = %s, end = %s, dst = %s", start, dt, end, dst);
+	    }
+	}
+	return dst;
+    }
+}
+else version (NoSystem)
+{
+    d_time getLocalTZA() { return 0; }    
+    int DaylightSavingTA(d_time dt) { return 0; }
+}
+
+/+ ====================== DOS File Time =============================== +/
+
+/***
+ * Type representing the DOS file date/time format.
+ */
+typedef uint DosFileTime;
+
+/************************************
+ * Convert from DOS file date/time to d_time.
+ */
+
+d_time toDtime(DosFileTime time)
+{
+    uint dt = cast(uint)time;
+
+    if (dt == 0)
+	return d_time_nan;
+
+    int year = ((dt >> 25) & 0x7F) + 1980;
+    int month = ((dt >> 21) & 0x0F) - 1;	// 0..12
+    int dayofmonth = ((dt >> 16) & 0x1F);	// 0..31
+    int hour = (dt >> 11) & 0x1F;		// 0..23
+    int minute = (dt >> 5) & 0x3F;		// 0..59
+    int second = (dt << 1) & 0x3E;		// 0..58 (in 2 second increments)
+
+    d_time t;
+
+    t = std.date.MakeDate(std.date.MakeDay(year, month, dayofmonth),
+	    std.date.MakeTime(hour, minute, second, 0));
+
+    assert(YearFromTime(t) == year);
+    assert(MonthFromTime(t) == month);
+    assert(DateFromTime(t) == dayofmonth);
+    assert(HourFromTime(t) == hour);
+    assert(MinFromTime(t) == minute);
+    assert(SecFromTime(t) == second);
+
+    t -= LocalTZA + DaylightSavingTA(t);
+
+    return t;
+}
+
+/****************************************
+ * Convert from d_time to DOS file date/time.
+ */
+
+DosFileTime toDosFileTime(d_time t)
+{   uint dt;
+
+    if (t == d_time_nan)
+	return cast(DosFileTime)0;
+
+    t += LocalTZA + DaylightSavingTA(t);
+
+    uint year = YearFromTime(t);
+    uint month = MonthFromTime(t);
+    uint dayofmonth = DateFromTime(t);
+    uint hour = HourFromTime(t);
+    uint minute = MinFromTime(t);
+    uint second = SecFromTime(t);
+
+    dt = (year - 1980) << 25;
+    dt |= ((month + 1) & 0x0F) << 21;
+    dt |= (dayofmonth & 0x1F) << 16;
+    dt |= (hour & 0x1F) << 11;
+    dt |= (minute & 0x3F) << 5;
+    dt |= (second >> 1) & 0x1F;
+
+    return cast(DosFileTime)dt;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/date.d~	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,1074 @@
+
+// Written in the D programming language.
+
+/**
+ * Dates are represented in several formats. The date implementation revolves
+ * around a central type, d_time, from which other formats are converted to and
+ * from.
+ * Dates are calculated using the Gregorian calendar.
+ * References:
+ *	$(LINK2 http://en.wikipedia.org/wiki/Gregorian_calendar, Gregorian calendar (Wikipedia))
+ * Macros:
+ *	WIKI = Phobos/StdDate
+ */
+
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+
+/* NOTE: This file has been patched from the original DMD distribution to
+   work with the GDC compiler.
+
+   Modified by David Friedman, May 2005
+*/
+
+module std.date;
+
+private import std.stdio;
+private import std.dateparse;
+
+/**
+ * d_time is a signed arithmetic type giving the time elapsed since January 1,
+ * 1970.
+ * Negative values are for dates preceding 1970. The time unit used is Ticks.
+ * Ticks are milliseconds or smaller intervals.
+ *
+ * The usual arithmetic operations can be performed on d_time, such as adding,
+ * subtracting, etc. Elapsed time in Ticks can be computed by subtracting a
+ * starting d_time from an ending d_time. 
+ */
+alias long d_time;
+
+/**
+ * A value for d_time that does not represent a valid time.
+ */
+const d_time d_time_nan = long.min;
+
+/**
+ * Time broken down into its components.
+ */
+struct Date
+{
+    int year = int.min;	/// use int.min as "nan" year value
+    int month;		/// 1..12
+    int day;		/// 1..31
+    int hour;		/// 0..23
+    int minute;		/// 0..59
+    int second;		/// 0..59
+    int ms;		/// 0..999
+    int weekday;	/// 0: not specified, 1..7: Sunday..Saturday
+    int tzcorrection = int.min;	/// -1200..1200 correction in hours
+
+    /// Parse date out of string s[] and store it in this Date instance.
+    void parse(string s)
+    {
+	DateParse dp;
+
+	dp.parse(s, *this);
+    }
+}
+
+enum
+{
+	HoursPerDay    = 24,
+	MinutesPerHour = 60,
+	msPerMinute    = 60 * 1000,
+	msPerHour      = 60 * msPerMinute,
+	msPerDay       = 86400000,
+	TicksPerMs     = 1,
+	TicksPerSecond = 1000,			/// Will be at least 1000
+	TicksPerMinute = TicksPerSecond * 60,
+	TicksPerHour   = TicksPerMinute * 60,
+	TicksPerDay    = TicksPerHour   * 24,
+}
+
+d_time LocalTZA = 0;
+
+
+const char[] daystr = "SunMonTueWedThuFriSat";
+const char[] monstr = "JanFebMarAprMayJunJulAugSepOctNovDec";
+
+const int[12] mdays = [ 0,31,59,90,120,151,181,212,243,273,304,334 ];
+
+/********************************
+ * Compute year and week [1..53] from t. The ISO 8601 week 1 is the first week
+ * of the year that includes January 4. Monday is the first day of the week.
+ * References:
+ *	$(LINK2 http://en.wikipedia.org/wiki/ISO_8601, ISO 8601 (Wikipedia))
+ */
+
+void toISO8601YearWeek(d_time t, out int year, out int week)
+{
+    year = YearFromTime(t);
+
+    int yday = Day(t) - DayFromYear(year);
+    int d;
+    int w;
+    int ydaybeg;
+
+    /* Determine day of week Jan 4 falls on.
+     * Weeks begin on a Monday.
+     */
+
+    d = DayFromYear(year);
+    w = (d + 3/*Jan4*/ + 3) % 7;
+    if (w < 0)
+        w += 7;
+
+    /* Find yday of beginning of ISO 8601 year
+     */
+    ydaybeg = 3/*Jan4*/ - w;
+
+    /* Check if yday is actually the last week of the previous year
+     */
+    if (yday < ydaybeg)
+    {
+	year -= 1;
+	week = 53;
+        return;
+    }
+
+    /* Check if yday is actually the first week of the next year
+     */
+    if (yday >= 362)                            // possible
+    {   int d2;
+        int ydaybeg2;
+
+        d2 = DayFromYear(year + 1);
+        w = (d2 + 3/*Jan4*/ + 3) % 7;
+        if (w < 0)
+            w += 7;
+        //printf("w = %d\n", w);
+        ydaybeg2 = 3/*Jan4*/ - w;
+        if (d + yday >= d2 + ydaybeg2)
+        {
+	    year += 1;
+	    week = 1;
+            return;
+        }
+    }
+
+    week = (yday - ydaybeg) / 7 + 1;
+}
+
+/* ***********************************
+ * Divide time by divisor. Always round down, even if d is negative.
+ */
+
+d_time floor(d_time d, int divisor)
+{
+    if (d < 0)
+	d -= divisor - 1;
+    return d / divisor;
+}
+
+int dmod(d_time n, d_time d)
+{   d_time r;
+
+    r = n % d;
+    if (r < 0)
+	r += d;
+    assert(cast(int)r == r);
+    return cast(int)r;
+}
+
+int HourFromTime(d_time t)
+{
+    return dmod(floor(t, msPerHour), HoursPerDay);
+}
+
+int MinFromTime(d_time t)
+{
+    return dmod(floor(t, msPerMinute), MinutesPerHour);
+}
+
+int SecFromTime(d_time t)
+{
+    return dmod(floor(t, TicksPerSecond), 60);
+}
+
+int msFromTime(d_time t)
+{
+    return dmod(t / (TicksPerSecond / 1000), 1000);
+}
+
+int TimeWithinDay(d_time t)
+{
+    return dmod(t, msPerDay);
+}
+
+d_time toInteger(d_time n)
+{
+    return n;
+}
+
+int Day(d_time t)
+{
+    return cast(int)floor(t, msPerDay);
+}
+
+int LeapYear(int y)
+{
+    return ((y & 3) == 0 &&
+	    (y % 100 || (y % 400) == 0));
+}
+
+int DaysInYear(int y)
+{
+    return 365 + LeapYear(y);
+}
+
+int DayFromYear(int y)
+{
+    return cast(int) (365 * (y - 1970) +
+		floor((y - 1969), 4) -
+		floor((y - 1901), 100) +
+		floor((y - 1601), 400));
+}
+
+d_time TimeFromYear(int y)
+{
+    return cast(d_time)msPerDay * DayFromYear(y);
+}
+
+/*****************************
+ * Calculates the year from the d_time t.
+ */
+
+int YearFromTime(d_time t)
+{   int y;
+
+    if (t == d_time_nan)
+	return 0;
+
+    // Hazard a guess
+    //y = 1970 + cast(int) (t / (365.2425 * msPerDay));
+    // Use integer only math
+    y = 1970 + cast(int) (t / (3652425 * (msPerDay / 10000)));
+
+    if (TimeFromYear(y) <= t)
+    {
+	while (TimeFromYear(y + 1) <= t)
+	    y++;
+    }
+    else
+    {
+	do
+	{
+	    y--;
+	}
+	while (TimeFromYear(y) > t);
+    }
+    return y;
+}
+
+/*******************************
+ * Determines if d_time t is a leap year.
+ *
+ * A leap year is every 4 years except years ending in 00 that are not
+ * divsible by 400.
+ *
+ * Returns: !=0 if it is a leap year.
+ *
+ * References:
+ *	$(LINK2 http://en.wikipedia.org/wiki/Leap_year, Wikipedia)
+ */
+
+int inLeapYear(d_time t)
+{
+    return LeapYear(YearFromTime(t));
+}
+
+/*****************************
+ * Calculates the month from the d_time t.
+ *
+ * Returns: Integer in the range 0..11, where
+ *	0 represents January and 11 represents December.
+ */
+
+int MonthFromTime(d_time t)
+{
+    int day;
+    int month;
+    int year;
+
+    year = YearFromTime(t);
+    day = Day(t) - DayFromYear(year);
+
+    if (day < 59)
+    {
+	if (day < 31)
+	{   assert(day >= 0);
+	    month = 0;
+	}
+	else
+	    month = 1;
+    }
+    else
+    {
+	day -= LeapYear(year);
+	if (day < 212)
+	{
+	    if (day < 59)
+		month = 1;
+	    else if (day < 90)
+		month = 2;
+	    else if (day < 120)
+		month = 3;
+	    else if (day < 151)
+		month = 4;
+	    else if (day < 181)
+		month = 5;
+	    else
+		month = 6;
+	}
+	else
+	{
+	    if (day < 243)
+		month = 7;
+	    else if (day < 273)
+		month = 8;
+	    else if (day < 304)
+		month = 9;
+	    else if (day < 334)
+		month = 10;
+	    else if (day < 365)
+		month = 11;
+	    else
+		assert(0);
+	}
+    }
+    return month;
+}
+
+/*******************************
+ * Compute which day in a month a d_time t is.
+ * Returns:
+ *	Integer in the range 1..31
+ */
+int DateFromTime(d_time t)
+{
+    int day;
+    int leap;
+    int month;
+    int year;
+    int date;
+
+    year = YearFromTime(t);
+    day = Day(t) - DayFromYear(year);
+    leap = LeapYear(year);
+    month = MonthFromTime(t);
+    switch (month)
+    {
+	case 0:	 date = day +   1;		break;
+	case 1:	 date = day -  30;		break;
+	case 2:	 date = day -  58 - leap;	break;
+	case 3:	 date = day -  89 - leap;	break;
+	case 4:	 date = day - 119 - leap;	break;
+	case 5:	 date = day - 150 - leap;	break;
+	case 6:	 date = day - 180 - leap;	break;
+	case 7:	 date = day - 211 - leap;	break;
+	case 8:	 date = day - 242 - leap;	break;
+	case 9:	 date = day - 272 - leap;	break;
+	case 10: date = day - 303 - leap;	break;
+	case 11: date = day - 333 - leap;	break;
+	default:
+	    assert(0);
+    }
+    return date;
+}
+
+/*******************************
+ * Compute which day of the week a d_time t is.
+ * Returns:
+ *	Integer in the range 0..6, where 0 represents Sunday
+ *	and 6 represents Saturday.
+ */
+int WeekDay(d_time t)
+{   int w;
+
+    w = (cast(int)Day(t) + 4) % 7;
+    if (w < 0)
+	w += 7;
+    return w;
+}
+
+/***********************************
+ * Convert from UTC to local time.
+ */
+
+d_time UTCtoLocalTime(d_time t)
+{
+    return (t == d_time_nan)
+	? d_time_nan
+	: t + LocalTZA + DaylightSavingTA(t);
+}
+
+/***********************************
+ * Convert from local time to UTC.
+ */
+
+d_time LocalTimetoUTC(d_time t)
+{
+    return (t == d_time_nan)
+	? d_time_nan
+	: t - LocalTZA - DaylightSavingTA(t - LocalTZA);
+}
+
+
+d_time MakeTime(d_time hour, d_time min, d_time sec, d_time ms)
+{
+    return hour * TicksPerHour +
+	   min * TicksPerMinute +
+	   sec * TicksPerSecond +
+	   ms * TicksPerMs;
+}
+
+
+d_time MakeDay(d_time year, d_time month, d_time date)
+{   d_time t;
+    int y;
+    int m;
+    int leap;
+
+    y = cast(int)(year + floor(month, 12));
+    m = dmod(month, 12);
+
+    leap = LeapYear(y);
+    t = TimeFromYear(y) + cast(d_time)mdays[m] * msPerDay;
+    if (leap && month >= 2)
+	t += msPerDay;
+
+    if (YearFromTime(t) != y ||
+	MonthFromTime(t) != m ||
+	DateFromTime(t) != 1)
+    {
+	return  d_time_nan;
+    }
+
+    return Day(t) + date - 1;
+}
+
+d_time MakeDate(d_time day, d_time time)
+{
+    if (day == d_time_nan || time == d_time_nan)
+	return d_time_nan;
+
+    return day * TicksPerDay + time;
+}
+
+d_time TimeClip(d_time time)
+{
+    //printf("TimeClip(%g) = %g\n", time, toInteger(time));
+
+    return toInteger(time);
+}
+
+/*************************************
+ * Converts UTC time into a text string of the form:
+ * "Www Mmm dd hh:mm:ss GMT+-TZ yyyy".
+ * For example, "Tue Apr 02 02:04:57 GMT-0800 1996".
+ * If time is invalid, i.e. is d_time_nan,
+ * the string "Invalid date" is returned.
+ *
+ * Example:
+ * ------------------------------------
+  d_time lNow;
+  char[] lNowString;
+
+  // Grab the date and time relative to UTC
+  lNow = std.date.getUTCtime();
+  // Convert this into the local date and time for display.
+  lNowString = std.date.toString(lNow);
+ * ------------------------------------
+ */
+
+string toString(d_time time)
+{
+    d_time t;
+    char sign;
+    int hr;
+    int mn;
+    int len;
+    d_time offset;
+    d_time dst;
+
+    // Years are supposed to be -285616 .. 285616, or 7 digits
+    // "Tue Apr 02 02:04:57 GMT-0800 1996"
+    char[] buffer = new char[29 + 7 + 1];
+
+    if (time == d_time_nan)
+	return "Invalid Date";
+
+    dst = DaylightSavingTA(time);
+    offset = LocalTZA + dst;
+    t = time + offset;
+    sign = '+';
+    if (offset < 0)
+    {	sign = '-';
+//	offset = -offset;
+	offset = -(LocalTZA + dst);
+    }
+
+    mn = cast(int)(offset / msPerMinute);
+    hr = mn / 60;
+    mn %= 60;
+
+    //printf("hr = %d, offset = %g, LocalTZA = %g, dst = %g, + = %g\n", hr, offset, LocalTZA, dst, LocalTZA + dst);
+
+    len = sprintf(buffer.ptr, "%.3s %.3s %02d %02d:%02d:%02d GMT%c%02d%02d %d",
+	&daystr[WeekDay(t) * 3],
+	&monstr[MonthFromTime(t) * 3],
+	DateFromTime(t),
+	HourFromTime(t), MinFromTime(t), SecFromTime(t),
+	sign, hr, mn,
+	/*cast(long)*/YearFromTime(t));
+
+    // Ensure no buggy buffer overflows
+    //printf("len = %d, buffer.length = %d\n", len, buffer.length);
+    assert(len < buffer.length);
+
+    return buffer[0 .. len];
+}
+
+/***********************************
+ * Converts t into a text string of the form: "Www, dd Mmm yyyy hh:mm:ss UTC".
+ * If t is invalid, "Invalid date" is returned.
+ */
+
+string toUTCString(d_time t)
+{
+    // Years are supposed to be -285616 .. 285616, or 7 digits
+    // "Tue, 02 Apr 1996 02:04:57 GMT"
+    char[] buffer = new char[25 + 7 + 1];
+    int len;
+
+    if (t == d_time_nan)
+	return "Invalid Date";
+
+    len = sprintf(buffer.ptr, "%.3s, %02d %.3s %d %02d:%02d:%02d UTC",
+	&daystr[WeekDay(t) * 3], DateFromTime(t),
+	&monstr[MonthFromTime(t) * 3],
+	YearFromTime(t),
+	HourFromTime(t), MinFromTime(t), SecFromTime(t));
+
+    // Ensure no buggy buffer overflows
+    assert(len < buffer.length);
+
+    return buffer[0 .. len];
+}
+
+/************************************
+ * Converts the date portion of time into a text string of the form: "Www Mmm dd
+ * yyyy", for example, "Tue Apr 02 1996".
+ * If time is invalid, "Invalid date" is returned.
+ */
+
+string toDateString(d_time time)
+{
+    d_time t;
+    d_time offset;
+    d_time dst;
+    int len;
+
+    // Years are supposed to be -285616 .. 285616, or 7 digits
+    // "Tue Apr 02 1996"
+    char[] buffer = new char[29 + 7 + 1];
+
+    if (time == d_time_nan)
+	return "Invalid Date";
+
+    dst = DaylightSavingTA(time);
+    offset = LocalTZA + dst;
+    t = time + offset;
+
+    len = sprintf(buffer.ptr, "%.3s %.3s %02d %d",
+	&daystr[WeekDay(t) * 3],
+	&monstr[MonthFromTime(t) * 3],
+	DateFromTime(t),
+	/*cast(long)*/YearFromTime(t));
+
+    // Ensure no buggy buffer overflows
+    assert(len < buffer.length);
+
+    return buffer[0 .. len];
+}
+
+/******************************************
+ * Converts the time portion of t into a text string of the form: "hh:mm:ss
+ * GMT+-TZ", for example, "02:04:57 GMT-0800".
+ * If t is invalid, "Invalid date" is returned.
+ * The input must be in UTC, and the output is in local time.
+ */
+
+string toTimeString(d_time time)
+{
+    d_time t;
+    char sign;
+    int hr;
+    int mn;
+    int len;
+    d_time offset;
+    d_time dst;
+
+    // "02:04:57 GMT-0800"
+    char[] buffer = new char[17 + 1];
+
+    if (time == d_time_nan)
+	return "Invalid Date";
+
+    dst = DaylightSavingTA(time);
+    offset = LocalTZA + dst;
+    t = time + offset;
+    sign = '+';
+    if (offset < 0)
+    {	sign = '-';
+//	offset = -offset;
+	offset = -(LocalTZA + dst);
+    }
+
+    mn = cast(int)(offset / msPerMinute);
+    hr = mn / 60;
+    mn %= 60;
+
+    //printf("hr = %d, offset = %g, LocalTZA = %g, dst = %g, + = %g\n", hr, offset, LocalTZA, dst, LocalTZA + dst);
+
+    len = sprintf(buffer.ptr, "%02d:%02d:%02d GMT%c%02d%02d",
+	HourFromTime(t), MinFromTime(t), SecFromTime(t),
+	sign, hr, mn);
+
+    // Ensure no buggy buffer overflows
+    assert(len < buffer.length);
+
+    // Lop off terminating 0
+    return buffer[0 .. len];
+}
+
+
+/******************************************
+ * Parses s as a textual date string, and returns it as a d_time.
+ * If the string is not a valid date, d_time_nan is returned.
+ */
+
+d_time parse(string s)
+{
+    Date dp;
+    d_time n;
+    d_time day;
+    d_time time;
+
+    try
+    {
+	dp.parse(s);
+
+	//writefln("year = %d, month = %d, day = %d", dp.year, dp.month, dp.day);
+	//writefln("%02d:%02d:%02d.%03d", dp.hour, dp.minute, dp.second, dp.ms);
+	//writefln("weekday = %d, ampm = %d, tzcorrection = %d", dp.weekday, 1, dp.tzcorrection);
+
+	time = MakeTime(dp.hour, dp.minute, dp.second, dp.ms);
+	if (dp.tzcorrection == int.min)
+	    time -= LocalTZA;
+	else
+	{
+	    time += cast(d_time)(dp.tzcorrection / 100) * msPerHour +
+		    cast(d_time)(dp.tzcorrection % 100) * msPerMinute;
+	}
+	day = MakeDay(dp.year, dp.month - 1, dp.day);
+	n = MakeDate(day,time);
+	n = TimeClip(n);
+    }
+    catch
+    {
+	n =  d_time_nan;		// erroneous date string
+    }
+    return n;
+}
+
+static this()
+{
+    LocalTZA = getLocalTZA();
+    //printf("LocalTZA = %g, %g\n", LocalTZA, LocalTZA / msPerHour);
+}
+
+version (Win32)
+{
+
+    private import std.c.windows.windows;
+    //import c.time;
+
+    /******
+     * Get current UTC time.
+     */
+    d_time getUTCtime()
+    {
+	SYSTEMTIME st;
+	d_time n;
+
+	GetSystemTime(&st);		// get time in UTC
+	n = SYSTEMTIME2d_time(&st, 0);
+	return n;
+	//return c.time.time(null) * TicksPerSecond;
+    }
+
+    static d_time FILETIME2d_time(FILETIME *ft)
+    {   SYSTEMTIME st;
+
+	if (!FileTimeToSystemTime(ft, &st))
+	    return d_time_nan;
+	return SYSTEMTIME2d_time(&st, 0);
+    }
+
+    static d_time SYSTEMTIME2d_time(SYSTEMTIME *st, d_time t)
+    {
+	d_time n;
+	d_time day;
+	d_time time;
+
+	if (st.wYear)
+	{
+	    time = MakeTime(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
+	    day = MakeDay(st.wYear, st.wMonth - 1, st.wDay);
+	}
+	else
+	{   // wDayOfWeek is weekday, wDay is which week in the month
+	    int year;
+	    int wd;
+	    int mday;
+	    int month;
+	    d_time x;
+
+	    year = YearFromTime(t);
+	    month = st.wMonth - 1;
+	    x = MakeDay(year, month, 1);
+	    wd = WeekDay(MakeDate(x, 0));
+
+	    mday = (7 - wd + st.wDayOfWeek);
+	    if (mday >= 7)
+		mday -= 7;
+	    mday += (st.wDay - 1) * 7 + 1;
+	    //printf("month = %d, wDayOfWeek = %d, wDay = %d, mday = %d\n", st.wMonth, st.wDayOfWeek, st.wDay, mday);
+
+	    day = MakeDay(year, month, mday);
+	    time = 0;
+	}
+	n = MakeDate(day,time);
+	n = TimeClip(n);
+	return n;
+    }
+
+    d_time getLocalTZA()
+    {
+	d_time t;
+	DWORD r;
+	TIME_ZONE_INFORMATION tzi;
+
+	/* http://msdn.microsoft.com/library/en-us/sysinfo/base/gettimezoneinformation.asp
+	 * http://msdn2.microsoft.com/en-us/library/ms725481.aspx
+	 */
+	r = GetTimeZoneInformation(&tzi);
+	//printf("bias = %d\n", tzi.Bias);
+	//printf("standardbias = %d\n", tzi.StandardBias);
+	//printf("daylightbias = %d\n", tzi.DaylightBias);
+	switch (r)
+	{
+	    case TIME_ZONE_ID_STANDARD:
+		t = -(tzi.Bias + tzi.StandardBias) * cast(d_time)(60 * TicksPerSecond);
+		break;
+	    case TIME_ZONE_ID_DAYLIGHT:
+		//t = -(tzi.Bias + tzi.DaylightBias) * cast(d_time)(60 * TicksPerSecond);
+		//break;
+	    case TIME_ZONE_ID_UNKNOWN:
+		t = -(tzi.Bias) * cast(d_time)(60 * TicksPerSecond);
+		break;
+
+	    default:
+		t = 0;
+		break;
+	}
+
+	return t;
+    }
+
+    /*
+     * Get daylight savings time adjust for time dt.
+     */
+
+    int DaylightSavingTA(d_time dt)
+    {
+	int t;
+	DWORD r;
+	TIME_ZONE_INFORMATION tzi;
+	d_time ts;
+	d_time td;
+
+	/* http://msdn.microsoft.com/library/en-us/sysinfo/base/gettimezoneinformation.asp
+	 */
+	r = GetTimeZoneInformation(&tzi);
+	t = 0;
+	switch (r)
+	{
+	    case TIME_ZONE_ID_STANDARD:
+	    case TIME_ZONE_ID_DAYLIGHT:
+		if (tzi.StandardDate.wMonth == 0 ||
+		    tzi.DaylightDate.wMonth == 0)
+		    break;
+
+		ts = SYSTEMTIME2d_time(&tzi.StandardDate, dt);
+		td = SYSTEMTIME2d_time(&tzi.DaylightDate, dt);
+
+		if (td <= dt && dt <= ts)
+		{
+		    t = -tzi.DaylightBias * (60 * TicksPerSecond);
+		    //printf("DST is in effect, %d\n", t);
+		}
+		else
+		{
+		    //printf("no DST\n");
+		}
+		break;
+
+	    case TIME_ZONE_ID_UNKNOWN:
+		// Daylight savings time not used in this time zone
+		break;
+
+	    default:
+		assert(0);
+	}
+	return t;
+    }
+}
+else version (Unix)
+{
+    // for now, just copy linux
+    private import std.c.unix.unix;
+
+    d_time getUTCtime()
+    {   timeval tv;
+
+	if (gettimeofday(&tv, null))
+	{   // Some error happened - try time() instead
+	    return time(null) * TicksPerSecond;
+	}
+
+	return tv.tv_sec * cast(d_time)TicksPerSecond +
+		(tv.tv_usec / (1000000 / cast(d_time)TicksPerSecond));
+    }
+
+    private extern (C) time_t _d_gnu_cbridge_tza();
+    
+    d_time getLocalTZA()
+    {
+	return _d_gnu_cbridge_tza() * TicksPerSecond;
+    }
+
+    /*
+     * Get daylight savings time adjust for time dt.
+     */
+
+    int DaylightSavingTA(d_time dt)
+    {
+	tm *tmp;
+	time_t t;
+	int dst = 0;
+
+	if (dt != d_time_nan)
+	{
+	    d_time seconds = dt / TicksPerSecond;
+	    t = cast(time_t) seconds;
+	    if (t == seconds)	// if in range
+	    {
+		tmp = localtime(&t);
+		if (tmp.tm_isdst > 0)
+		    dst = TicksPerHour;	// BUG: Assume daylight savings time is plus one hour.
+	    }
+	    else	// out of range for system time, use our own calculation
+	    {	// Daylight savings time goes from 2 AM the first Sunday
+		// in April through 2 AM the last Sunday in October
+
+		dt -= LocalTZA;
+
+		int year = YearFromTime(dt);
+		int leap = LeapYear(cast(int)dt);
+		//writefln("year = %s, leap = %s, month = %s", year, leap, MonthFromTime(dt));
+
+		d_time start = TimeFromYear(year);		// Jan 1
+		d_time end = start;
+		// Move fwd to Apr 1
+		start += cast(d_time)(mdays[3] + leap) * TicksPerDay;
+		// Advance a day at a time until we find Sunday (0)
+		while (WeekDay(start) != 0)
+		    start += TicksPerDay;
+
+		// Move fwd to Oct 30
+		end += cast(d_time)(mdays[9] + leap + 30) * TicksPerDay;
+		// Back up a day at a time until we find Sunday (0)
+		while (WeekDay(end) != 0)		// 0 is Sunday
+		    end -= TicksPerDay;
+
+		dt -= 2 * TicksPerHour;			// 2 AM
+		if (dt >= start && dt <= end)
+		    dst = TicksPerHour;
+		//writefln("start = %s, dt = %s, end = %s, dst = %s", start, dt, end, dst);
+	    }
+	}
+	return dst;
+    }
+}
+else version (linux)
+{
+
+    private import std.c.linux.linux;
+
+    d_time getUTCtime()
+    {   timeval tv;
+
+	//printf("getUTCtime()\n");
+	if (gettimeofday(&tv, null))
+	{   // Some error happened - try time() instead
+	    return time(null) * TicksPerSecond;
+	}
+
+	return tv.tv_sec * cast(d_time)TicksPerSecond +
+		(tv.tv_usec / (1000000 / cast(d_time)TicksPerSecond));
+    }
+
+    d_time getLocalTZA()
+    {
+	int t;
+
+	time(&t);
+	localtime(&t);	// this will set timezone
+	return -(timezone * TicksPerSecond);
+    }
+
+    /*
+     * Get daylight savings time adjust for time dt.
+     */
+
+    int DaylightSavingTA(d_time dt)
+    {
+	tm *tmp;
+	int t;
+	int dst = 0;
+
+	if (dt != d_time_nan)
+	{
+	    d_time seconds = dt / TicksPerSecond;
+	    t = cast(int) seconds;
+	    if (t == seconds)	// if in range
+	    {
+		tmp = localtime(&t);
+		if (tmp.tm_isdst > 0)
+		    dst = TicksPerHour;	// BUG: Assume daylight savings time is plus one hour.
+	    }
+	    else	// out of range for system time, use our own calculation
+	    {	// Daylight savings time goes from 2 AM the first Sunday
+		// in April through 2 AM the last Sunday in October
+
+		dt -= LocalTZA;
+
+		int year = YearFromTime(dt);
+		int leap = LeapYear(dt);
+		//writefln("year = %s, leap = %s, month = %s", year, leap, MonthFromTime(dt));
+
+		d_time start = TimeFromYear(year);		// Jan 1
+		d_time end = start;
+		// Move fwd to Apr 1
+		start += cast(d_time)(mdays[3] + leap) * TicksPerDay;
+		// Advance a day at a time until we find Sunday (0)
+		while (WeekDay(start) != 0)
+		    start += TicksPerDay;
+
+		// Move fwd to Oct 30
+		end += cast(d_time)(mdays[9] + leap + 30) * TicksPerDay;
+		// Back up a day at a time until we find Sunday (0)
+		while (WeekDay(end) != 0)		// 0 is Sunday
+		    end -= TicksPerDay;
+
+		dt -= 2 * TicksPerHour;			// 2 AM
+		if (dt >= start && dt <= end)
+		    dst = TicksPerHour;
+		//writefln("start = %s, dt = %s, end = %s, dst = %s", start, dt, end, dst);
+	    }
+	}
+	return dst;
+    }
+
+}
+else version (NoSystem)
+{
+    d_time getLocalTZA() { return 0; }    
+    int DaylightSavingTA(d_time dt) { return 0; }
+}
+
+/+ ====================== DOS File Time =============================== +/
+
+/***
+ * Type representing the DOS file date/time format.
+ */
+typedef uint DosFileTime;
+
+/************************************
+ * Convert from DOS file date/time to d_time.
+ */
+
+d_time toDtime(DosFileTime time)
+{
+    uint dt = cast(uint)time;
+
+    if (dt == 0)
+	return d_time_nan;
+
+    int year = ((dt >> 25) & 0x7F) + 1980;
+    int month = ((dt >> 21) & 0x0F) - 1;	// 0..12
+    int dayofmonth = ((dt >> 16) & 0x1F);	// 0..31
+    int hour = (dt >> 11) & 0x1F;		// 0..23
+    int minute = (dt >> 5) & 0x3F;		// 0..59
+    int second = (dt << 1) & 0x3E;		// 0..58 (in 2 second increments)
+
+    d_time t;
+
+    t = std.date.MakeDate(std.date.MakeDay(year, month, dayofmonth),
+	    std.date.MakeTime(hour, minute, second, 0));
+
+    assert(YearFromTime(t) == year);
+    assert(MonthFromTime(t) == month);
+    assert(DateFromTime(t) == dayofmonth);
+    assert(HourFromTime(t) == hour);
+    assert(MinFromTime(t) == minute);
+    assert(SecFromTime(t) == second);
+
+    t -= LocalTZA + DaylightSavingTA(t);
+
+    return t;
+}
+
+/****************************************
+ * Convert from d_time to DOS file date/time.
+ */
+
+DosFileTime toDosFileTime(d_time t)
+{   uint dt;
+
+    if (t == d_time_nan)
+	return cast(DosFileTime)0;
+
+    t += LocalTZA + DaylightSavingTA(t);
+
+    uint year = YearFromTime(t);
+    uint month = MonthFromTime(t);
+    uint dayofmonth = DateFromTime(t);
+    uint hour = HourFromTime(t);
+    uint minute = MinFromTime(t);
+    uint second = SecFromTime(t);
+
+    dt = (year - 1980) << 25;
+    dt |= ((month + 1) & 0x0F) << 21;
+    dt |= (dayofmonth & 0x1F) << 16;
+    dt |= (hour & 0x1F) << 11;
+    dt |= (minute & 0x3F) << 5;
+    dt |= (second >> 1) & 0x1F;
+
+    return cast(DosFileTime)dt;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/dateparse.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,788 @@
+
+/*
+ *  Copyright (C) 1999-2004 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, subject to the following restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+
+module std.dateparse;
+
+private
+{
+    import std.string;
+    import std.c.stdlib;
+    import std.date;
+}
+
+//debug=dateparse;
+
+class DateParseError : Error
+{
+    this(char[] s)
+    {
+	super("Invalid date string: " ~ s);
+    }
+}
+
+struct DateParse
+{
+    void parse(char[] s, out Date date)
+    {
+	*this = DateParse.init;
+
+	//version (Win32)
+	    buffer = (cast(char *)alloca(s.length))[0 .. s.length];
+	//else
+	    //buffer = new char[s.length];
+
+	debug(dateparse) printf("DateParse.parse('%.*s')\n",
+	    cast(int) s.length, s.ptr);
+	if (!parseString(s))
+	{
+	    goto Lerror;
+	}
+
+    /+
+	if (year == year.init)
+	    year = 0;
+	else
+    +/
+	debug(dateparse)
+	    printf("year = %d, month = %d, day = %d\n%02d:%02d:%02d.%03d\nweekday = %d, tzcorrection = %d\n",
+		year, month, day,
+		hours, minutes, seconds, ms,
+		weekday, tzcorrection);
+	if (
+	    year == year.init ||
+	    (month < 1 || month > 12) ||
+	    (day < 1 || day > 31) ||
+	    (hours < 0 || hours > 23) ||
+	    (minutes < 0 || minutes > 59) ||
+	    (seconds < 0 || seconds > 59) ||
+	    (tzcorrection != int.min &&
+	     ((tzcorrection < -2300 || tzcorrection > 2300) ||
+	      (tzcorrection % 10)))
+	    )
+	{
+	 Lerror:
+	    throw new DateParseError(s);
+	}
+
+	if (ampm)
+	{   if (hours > 12)
+		goto Lerror;
+	    if (hours < 12)
+	    {
+		if (ampm == 2)	// if P.M.
+		    hours += 12;
+	    }
+	    else if (ampm == 1)	// if 12am
+	    {
+		hours = 0;		// which is midnight
+	    }
+	}
+
+//	if (tzcorrection != tzcorrection.init)
+//	    tzcorrection /= 100;
+
+	if (year >= 0 && year <= 99)
+	    year += 1900;
+
+	date.year = year;
+	date.month = month;
+	date.day = day;
+	date.hour = hours;
+	date.minute = minutes;
+	date.second = seconds;
+	date.ms = ms;
+	date.weekday = weekday;
+	date.tzcorrection = tzcorrection;
+    }
+
+
+private:
+    int year = int.min;	// our "nan" Date value
+    int month;		// 1..12
+    int day;		// 1..31
+    int hours;		// 0..23
+    int minutes;	// 0..59
+    int seconds;	// 0..59
+    int ms;		// 0..999
+    int weekday;	// 1..7
+    int ampm;		// 0: not specified
+			// 1: AM
+			// 2: PM
+    int tzcorrection = int.min;	// -1200..1200 correction in hours
+
+    char[] s;
+    int si;
+    int number;
+    char[] buffer;
+
+    enum DP : byte
+    {
+	err,
+	weekday,
+	month,
+	number,
+	end,
+	colon,
+	minus,
+	slash,
+	ampm,
+	plus,
+	tz,
+	dst,
+	dsttz,
+    }
+
+    DP nextToken()
+    {   int nest;
+	uint c;
+	int bi;
+	DP result = DP.err;
+
+	//printf("DateParse::nextToken()\n");
+	for (;;)
+	{
+	    assert(si <= s.length);
+	    if (si == s.length)
+	    {	result = DP.end;
+		goto Lret;
+	    }
+	    //printf("\ts[%d] = '%c'\n", si, s[si]);
+	    switch (s[si])
+	    {
+		case ':':	result = DP.colon; goto ret_inc;
+		case '+':	result = DP.plus;  goto ret_inc;
+		case '-':	result = DP.minus; goto ret_inc;
+		case '/':	result = DP.slash; goto ret_inc;
+		case '.':
+		    version(DATE_DOT_DELIM)
+		    {
+			result = DP.slash;
+			goto ret_inc;
+		    }
+		    else
+		    {
+			si++;
+			break;
+		    }
+
+		ret_inc:
+		    si++;
+		    goto Lret;
+
+		case ' ':
+		case '\n':
+		case '\r':
+		case '\t':
+		case ',':
+		    si++;
+		    break;
+
+		case '(':		// comment
+		    nest = 1;
+		    for (;;)
+		    {
+			si++;
+			if (si == s.length)
+			    goto Lret;		// error
+			switch (s[si])
+			{
+			    case '(':
+				nest++;
+				break;
+
+			    case ')':
+				if (--nest == 0)
+				    goto Lendofcomment;
+				break;
+
+			    default:
+				break;
+			}
+		    }
+		Lendofcomment:
+		    si++;
+		    break;
+
+		default:
+		    number = 0;
+		    for (;;)
+		    {
+			if (si == s.length)
+			    // c cannot be undefined here
+			    break;
+			c = s[si];
+			if (!(c >= '0' && c <= '9'))
+			    break;
+			result = DP.number;
+			number = number * 10 + (c - '0');
+			si++;
+		    }
+		    if (result == DP.number)
+			goto Lret;
+
+		    bi = 0;
+		bufloop:
+		    while (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')
+		    {
+			if (c < 'a')		// if upper case
+			    c += cast(uint)'a' - cast(uint)'A';	// to lower case
+			buffer[bi] = cast(char)c;
+			bi++;
+			do
+			{
+			    si++;
+			    if (si == s.length)
+				break bufloop;
+			    c = s[si];
+			} while (c == '.');	// ignore embedded '.'s
+		    }
+		    result = classify(buffer[0 .. bi]);
+		    goto Lret;
+	    }
+	}
+    Lret:
+	//printf("-DateParse::nextToken()\n");
+	return result;
+    }
+
+    DP classify(char[] buf)
+    {
+	struct DateID
+	{
+	    char[] name;
+	    DP tok;
+	    short value;
+	}
+
+	static DateID dateidtab[] =
+	[
+	    {   "january",	DP.month,	1},
+	    {   "february",	DP.month,	2},
+	    {   "march",	DP.month,	3},
+	    {   "april",	DP.month,	4},
+	    {   "may",		DP.month,	5},
+	    {   "june",		DP.month,	6},
+	    {   "july",		DP.month,	7},
+	    {   "august",	DP.month,	8},
+	    {   "september",	DP.month,	9},
+	    {   "october",	DP.month,	10},
+	    {   "november",	DP.month,	11},
+	    {   "december",	DP.month,	12},
+	    {   "jan",		DP.month,	1},
+	    {   "feb",		DP.month,	2},
+	    {   "mar",		DP.month,	3},
+	    {   "apr",		DP.month,	4},
+	    {   "jun",		DP.month,	6},
+	    {   "jul",		DP.month,	7},
+	    {   "aug",		DP.month,	8},
+	    {   "sep",		DP.month,	9},
+	    {   "sept",		DP.month,	9},
+	    {   "oct",		DP.month,	10},
+	    {   "nov",		DP.month,	11},
+	    {   "dec",		DP.month,	12},
+
+	    {   "sunday",	DP.weekday,	1},
+	    {   "monday",	DP.weekday,	2},
+	    {   "tuesday",	DP.weekday,	3},
+	    {   "tues",		DP.weekday,	3},
+	    {   "wednesday",	DP.weekday,	4},
+	    {   "wednes",	DP.weekday,	4},
+	    {   "thursday",	DP.weekday,	5},
+	    {   "thur",		DP.weekday,	5},
+	    {   "thurs",	DP.weekday,	5},
+	    {   "friday",	DP.weekday,	6},
+	    {   "saturday",	DP.weekday,	7},
+
+	    {   "sun",		DP.weekday,	1},
+	    {   "mon",		DP.weekday,	2},
+	    {   "tue",		DP.weekday,	3},
+	    {   "wed",		DP.weekday,	4},
+	    {   "thu",		DP.weekday,	5},
+	    {   "fri",		DP.weekday,	6},
+	    {   "sat",		DP.weekday,	7},
+
+	    {   "am",		DP.ampm,		1},
+	    {   "pm",		DP.ampm,		2},
+
+	    {   "gmt",		DP.tz,		+000},
+	    {   "ut",		DP.tz,		+000},
+	    {   "utc",		DP.tz,		+000},
+	    {   "wet",		DP.tz,		+000},
+	    {   "z",		DP.tz,		+000},
+	    {   "wat",		DP.tz,		+100},
+	    {   "a",		DP.tz,		+100},
+	    {   "at",		DP.tz,		+200},
+	    {   "b",		DP.tz,		+200},
+	    {   "c",		DP.tz,		+300},
+	    {   "ast",		DP.tz,		+400},
+	    {   "d",		DP.tz,		+400},
+	    {   "est",		DP.tz,		+500},
+	    {   "e",		DP.tz,		+500},
+	    {   "cst",		DP.tz,		+600},
+	    {   "f",		DP.tz,		+600},
+	    {   "mst",		DP.tz,		+700},
+	    {   "g",		DP.tz,		+700},
+	    {   "pst",		DP.tz,		+800},
+	    {   "h",		DP.tz,		+800},
+	    {   "yst",		DP.tz,		+900},
+	    {   "i",		DP.tz,		+900},
+	    {   "ahst",		DP.tz,		+1000},
+	    {   "cat",		DP.tz,		+1000},
+	    {   "hst",		DP.tz,		+1000},
+	    {   "k",		DP.tz,		+1000},
+	    {   "nt",		DP.tz,		+1100},
+	    {   "l",		DP.tz,		+1100},
+	    {   "idlw",		DP.tz,		+1200},
+	    {   "m",		DP.tz,		+1200},
+
+	    {   "cet",		DP.tz,		-100},
+	    {   "fwt",		DP.tz,		-100},
+	    {   "met",		DP.tz,		-100},
+	    {   "mewt",		DP.tz,		-100},
+	    {   "swt",		DP.tz,		-100},
+	    {   "n",		DP.tz,		-100},
+	    {   "eet",		DP.tz,		-200},
+	    {   "o",		DP.tz,		-200},
+	    {   "bt",		DP.tz,		-300},
+	    {   "p",		DP.tz,		-300},
+	    {   "zp4",		DP.tz,		-400},
+	    {   "q",		DP.tz,		-400},
+	    {   "zp5",		DP.tz,		-500},
+	    {   "r",		DP.tz,		-500},
+	    {   "zp6",		DP.tz,		-600},
+	    {   "s",		DP.tz,		-600},
+	    {   "wast",		DP.tz,		-700},
+	    {   "t",		DP.tz,		-700},
+	    {   "cct",		DP.tz,		-800},
+	    {   "u",		DP.tz,		-800},
+	    {   "jst",		DP.tz,		-900},
+	    {   "v",		DP.tz,		-900},
+	    {   "east",		DP.tz,		-1000},
+	    {   "gst",		DP.tz,		-1000},
+	    {   "w",		DP.tz,		-1000},
+	    {   "x",		DP.tz,		-1100},
+	    {   "idle",		DP.tz,		-1200},
+	    {   "nzst",		DP.tz,		-1200},
+	    {   "nzt",		DP.tz,		-1200},
+	    {   "y",		DP.tz,		-1200},
+
+	    {   "bst",		DP.dsttz,	000},
+	    {   "adt",		DP.dsttz,	+400},
+	    {   "edt",		DP.dsttz,	+500},
+	    {   "cdt",		DP.dsttz,	+600},
+	    {   "mdt",		DP.dsttz,	+700},
+	    {   "pdt",		DP.dsttz,	+800},
+	    {   "ydt",		DP.dsttz,	+900},
+	    {   "hdt",		DP.dsttz,	+1000},
+	    {   "mest",		DP.dsttz,	-100},
+	    {   "mesz",		DP.dsttz,	-100},
+	    {   "sst",		DP.dsttz,	-100},
+	    {   "fst",		DP.dsttz,	-100},
+	    {   "wadt",		DP.dsttz,	-700},
+	    {   "eadt",		DP.dsttz,	-1000},
+	    {   "nzdt",		DP.dsttz,	-1200},
+
+	    {   "dst",		DP.dst,		0},
+	];
+
+	//message(DTEXT("DateParse::classify('%s')\n"), buf);
+
+	// Do a linear search. Yes, it would be faster with a binary
+	// one.
+	for (uint i = 0; i < dateidtab.length; i++)
+	{
+	    if (std.string.cmp(dateidtab[i].name, buf) == 0)
+	    {
+		number = dateidtab[i].value;
+		return dateidtab[i].tok;
+	    }
+	}
+	return DP.err;
+    }
+
+    int parseString(char[] s)
+    {
+	int n1;
+	int dp;
+	int sisave;
+	int result;
+
+	//message(DTEXT("DateParse::parseString('%ls')\n"), s);
+	this.s = s;
+	si = 0;
+	dp = nextToken();
+	for (;;)
+	{
+	    //message(DTEXT("\tdp = %d\n"), dp);
+	    switch (dp)
+	    {
+		case DP.end:
+		    result = 1;
+		Lret:
+		    return result;
+
+		case DP.err:
+		case_error:
+		    //message(DTEXT("\terror\n"));
+		default:
+		    result = 0;
+		    goto Lret;
+
+		case DP.minus:
+		    break;			// ignore spurious '-'
+
+		case DP.weekday:
+		    weekday = number;
+		    break;
+
+		case DP.month:		// month day, [year]
+		    month = number;
+		    dp = nextToken();
+		    if (dp == DP.number)
+		    {
+			day = number;
+			sisave = si;
+			dp = nextToken();
+			if (dp == DP.number)
+			{
+			    n1 = number;
+			    dp = nextToken();
+			    if (dp == DP.colon)
+			    {   // back up, not a year
+				si = sisave;
+			    }
+			    else
+			    {   year = n1;
+				continue;
+			    }
+			    break;
+			}
+		    }
+		    continue;
+
+		case DP.number:
+		    n1 = number;
+		    dp = nextToken();
+		    switch (dp)
+		    {
+			case DP.end:
+			    year = n1;
+			    break;
+
+			case DP.minus:
+			case DP.slash:	// n1/ ? ? ?
+			    dp = parseCalendarDate(n1);
+			    if (dp == DP.err)
+				goto case_error;
+			    break;
+
+		       case DP.colon:	// hh:mm [:ss] [am | pm]
+			    dp = parseTimeOfDay(n1);
+			    if (dp == DP.err)
+				goto case_error;
+			    break;
+
+		       case DP.ampm:
+			    hours = n1;
+			    minutes = 0;
+			    seconds = 0;
+			    ampm = number;
+			    break;
+
+			case DP.month:
+			    day = n1;
+			    month = number;
+			    dp = nextToken();
+			    if (dp == DP.number)
+			    {   // day month year
+				year = number;
+				dp = nextToken();
+			    }
+			    break;
+
+			default:
+			    year = n1;
+			    break;
+		    }
+		    continue;
+	    }
+	    dp = nextToken();
+	}
+	assert(0);
+    }
+
+    int parseCalendarDate(int n1)
+    {
+	int n2;
+	int n3;
+	int dp;
+
+	debug(dateparse) printf("DateParse.parseCalendarDate(%d)\n", n1);
+	dp = nextToken();
+	if (dp == DP.month)	// day/month
+	{
+	    day = n1;
+	    month = number;
+	    dp = nextToken();
+	    if (dp == DP.number)
+	    {   // day/month year
+		year = number;
+		dp = nextToken();
+	    }
+	    else if (dp == DP.minus || dp == DP.slash)
+	    {   // day/month/year
+		dp = nextToken();
+		if (dp != DP.number)
+		    goto case_error;
+		year = number;
+		dp = nextToken();
+	    }
+	    return dp;
+	}
+	if (dp != DP.number)
+	    goto case_error;
+	n2 = number;
+	//message(DTEXT("\tn2 = %d\n"), n2);
+	dp = nextToken();
+	if (dp == DP.minus || dp == DP.slash)
+	{
+	    dp = nextToken();
+	    if (dp != DP.number)
+		goto case_error;
+	    n3 = number;
+	    //message(DTEXT("\tn3 = %d\n"), n3);
+	    dp = nextToken();
+
+	    // case1: year/month/day
+	    // case2: month/day/year
+	    int case1, case2;
+
+	    case1 = (n1 > 12 ||
+		     (n2 >= 1 && n2 <= 12) &&
+		     (n3 >= 1 && n3 <= 31));
+	    case2 = ((n1 >= 1 && n1 <= 12) &&
+		     (n2 >= 1 && n2 <= 31) ||
+		     n3 > 31);
+	    if (case1 == case2)
+		goto case_error;
+	    if (case1)
+	    {
+		year = n1;
+		month = n2;
+		day = n3;
+	    }
+	    else
+	    {
+		month = n1;
+		day = n2;
+		year = n3;
+	    }
+	}
+	else
+	{   // must be month/day
+	    month = n1;
+	    day = n2;
+	}
+	return dp;
+
+    case_error:
+	return DP.err;
+    }
+
+    int parseTimeOfDay(int n1)
+    {
+	int dp;
+	int sign;
+
+	// 12am is midnight
+	// 12pm is noon
+
+	//message(DTEXT("DateParse::parseTimeOfDay(%d)\n"), n1);
+	hours = n1;
+	dp = nextToken();
+	if (dp != DP.number)
+	    goto case_error;
+	minutes = number;
+	dp = nextToken();
+	if (dp == DP.colon)
+	{
+	    dp = nextToken();
+	    if (dp != DP.number)
+		goto case_error;
+	    seconds = number;
+	    dp = nextToken();
+	}
+	else
+	    seconds = 0;
+
+	if (dp == DP.ampm)
+	{
+	    ampm = number;
+	    dp = nextToken();
+	}
+	else if (dp == DP.plus || dp == DP.minus)
+	{
+	Loffset:
+	    sign = (dp == DP.minus) ? -1 : 1;
+	    dp = nextToken();
+	    if (dp != DP.number)
+		goto case_error;
+	    tzcorrection = -sign * number;
+	    dp = nextToken();
+	}
+	else if (dp == DP.tz)
+	{
+	    tzcorrection = number;
+	    dp = nextToken();
+	    if (number == 0 && (dp == DP.plus || dp == DP.minus))
+		goto Loffset;
+	    if (dp == DP.dst)
+	    {   tzcorrection += 100;
+		dp = nextToken();
+	    }
+	}
+	else if (dp == DP.dsttz)
+	{
+	    tzcorrection = number;
+	    dp = nextToken();
+	}
+
+	return dp;
+
+    case_error:
+	return DP.err;
+    }
+
+}
+
+unittest
+{
+    DateParse dp;
+    Date d;
+
+    dp.parse("March 10, 1959 12:00 -800", d);
+    assert(d.year         == 1959);
+    assert(d.month        == 3);
+    assert(d.day          == 10);
+    assert(d.hour         == 12);
+    assert(d.minute       == 0);
+    assert(d.second       == 0);
+    assert(d.ms           == 0);
+    assert(d.weekday      == 0);
+    assert(d.tzcorrection == 800);
+
+    dp.parse("Tue Apr 02 02:04:57 GMT-0800 1996", d);
+    assert(d.year         == 1996);
+    assert(d.month        == 4);
+    assert(d.day          == 2);
+    assert(d.hour         == 2);
+    assert(d.minute       == 4);
+    assert(d.second       == 57);
+    assert(d.ms           == 0);
+    assert(d.weekday      == 3);
+    assert(d.tzcorrection == 800);
+
+    dp.parse("March 14, -1980 21:14:50", d);
+    assert(d.year         == 1980);
+    assert(d.month        == 3);
+    assert(d.day          == 14);
+    assert(d.hour         == 21);
+    assert(d.minute       == 14);
+    assert(d.second       == 50);
+    assert(d.ms           == 0);
+    assert(d.weekday      == 0);
+    assert(d.tzcorrection == int.min);
+
+    dp.parse("Tue Apr 02 02:04:57 1996", d);
+    assert(d.year         == 1996);
+    assert(d.month        == 4);
+    assert(d.day          == 2);
+    assert(d.hour         == 2);
+    assert(d.minute       == 4);
+    assert(d.second       == 57);
+    assert(d.ms           == 0);
+    assert(d.weekday      == 3);
+    assert(d.tzcorrection == int.min);
+
+    dp.parse("Tue, 02 Apr 1996 02:04:57 G.M.T.", d);
+    assert(d.year         == 1996);
+    assert(d.month        == 4);
+    assert(d.day          == 2);
+    assert(d.hour         == 2);
+    assert(d.minute       == 4);
+    assert(d.second       == 57);
+    assert(d.ms           == 0);
+    assert(d.weekday      == 3);
+    assert(d.tzcorrection == 0);
+
+    dp.parse("December 31, 3000", d);
+    assert(d.year         == 3000);
+    assert(d.month        == 12);
+    assert(d.day          == 31);
+    assert(d.hour         == 0);
+    assert(d.minute       == 0);
+    assert(d.second       == 0);
+    assert(d.ms           == 0);
+    assert(d.weekday      == 0);
+    assert(d.tzcorrection == int.min);
+
+    dp.parse("Wed, 31 Dec 1969 16:00:00 GMT", d);
+    assert(d.year         == 1969);
+    assert(d.month        == 12);
+    assert(d.day          == 31);
+    assert(d.hour         == 16);
+    assert(d.minute       == 0);
+    assert(d.second       == 0);
+    assert(d.ms           == 0);
+    assert(d.weekday      == 4);
+    assert(d.tzcorrection == 0);
+
+    dp.parse("1/1/1999 12:30 AM", d);
+    assert(d.year         == 1999);
+    assert(d.month        == 1);
+    assert(d.day          == 1);
+    assert(d.hour         == 0);
+    assert(d.minute       == 30);
+    assert(d.second       == 0);
+    assert(d.ms           == 0);
+    assert(d.weekday      == 0);
+    assert(d.tzcorrection == int.min);
+
+    dp.parse("Tue, 20 May 2003 15:38:58 +0530", d);
+    assert(d.year         == 2003);
+    assert(d.month        == 5);
+    assert(d.day          == 20);
+    assert(d.hour         == 15);
+    assert(d.minute       == 38);
+    assert(d.second       == 58);
+    assert(d.ms           == 0);
+    assert(d.weekday      == 3);
+    assert(d.tzcorrection == -530);
+
+    debug(dateparse) printf("year = %d, month = %d, day = %d\n%02d:%02d:%02d.%03d\nweekday = %d, tzcorrection = %d\n",
+	d.year, d.month, d.day,
+	d.hour, d.minute, d.second, d.ms,
+	d.weekday, d.tzcorrection);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/file.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,1588 @@
+// Written in the D programming language.
+
+/**
+ * Macros:
+ *	WIKI = Phobos/StdFile
+ */
+
+/*
+ *  Copyright (C) 2001-2004 by Digital Mars, www.digitalmars.com
+ * Written by Walter Bright, Christopher E. Miller, Andre Fornacon
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, subject to the following restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/* NOTE: This file has been patched from the original DMD distribution to
+   work with the GDC compiler.
+
+   Modified by David Friedman, March 2006
+*/
+
+module std.file;
+
+private import std.c.stdio;
+private import std.c.stdlib;
+private import std.c.string;
+private import std.path;
+private import std.string;
+private import std.regexp;
+private import std.gc;
+
+/* =========================== Win32 ======================= */
+
+version (Win32)
+{
+
+private import std.c.windows.windows;
+private import std.utf;
+private import std.windows.syserror;
+private import std.windows.charset;
+private import std.date;
+
+int useWfuncs = 1;
+
+static this()
+{
+    // Win 95, 98, ME do not implement the W functions
+    useWfuncs = (GetVersion() < 0x80000000);
+}
+
+/***********************************
+ * Exception thrown for file I/O errors.
+ */
+
+class FileException : Exception
+{
+
+    uint errno;			// operating system error code
+
+    this(char[] name)
+    {
+	this(name, "file I/O");
+    }
+
+    this(char[] name, char[] message)
+    {
+	super(name ~ ": " ~ message);
+    }
+
+    this(char[] name, uint errno)
+    {
+	this(name, sysErrorString(errno));
+	this.errno = errno;
+    }
+}
+
+/* **********************************
+ * Basic File operations.
+ */
+
+/********************************************
+ * Read file name[], return array of bytes read.
+ * Throws:
+ *	FileException on error.
+ */
+
+void[] read(char[] name)
+{
+    DWORD numread;
+    HANDLE h;
+
+    if (useWfuncs)
+    {
+	wchar* namez = std.utf.toUTF16z(name);
+	h = CreateFileW(namez,GENERIC_READ,FILE_SHARE_READ,null,OPEN_EXISTING,
+	    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,cast(HANDLE)null);
+    }
+    else
+    {
+	char* namez = toMBSz(name);
+	h = CreateFileA(namez,GENERIC_READ,FILE_SHARE_READ,null,OPEN_EXISTING,
+	    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,cast(HANDLE)null);
+    }
+
+    if (h == INVALID_HANDLE_VALUE)
+	goto err1;
+
+    auto size = GetFileSize(h, null);
+    if (size == INVALID_FILE_SIZE)
+	goto err2;
+
+    auto buf = std.gc.malloc(size);
+    if (buf)
+	std.gc.hasNoPointers(buf.ptr);
+
+    if (ReadFile(h,buf.ptr,size,&numread,null) != 1)
+	goto err2;
+
+    if (numread != size)
+	goto err2;
+
+    if (!CloseHandle(h))
+	goto err;
+
+    return buf[0 .. size];
+
+err2:
+    CloseHandle(h);
+err:
+    delete buf;
+err1:
+    throw new FileException(name, GetLastError());
+}
+
+/*********************************************
+ * Write buffer[] to file name[].
+ * Throws: FileException on error.
+ */
+
+void write(char[] name, void[] buffer)
+{
+    HANDLE h;
+    DWORD numwritten;
+
+    if (useWfuncs)
+    {
+	wchar* namez = std.utf.toUTF16z(name);
+	h = CreateFileW(namez,GENERIC_WRITE,0,null,CREATE_ALWAYS,
+	    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,cast(HANDLE)null);
+    }
+    else
+    {
+	char* namez = toMBSz(name);
+	h = CreateFileA(namez,GENERIC_WRITE,0,null,CREATE_ALWAYS,
+	    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,cast(HANDLE)null);
+    }
+    if (h == INVALID_HANDLE_VALUE)
+	goto err;
+
+    if (WriteFile(h,buffer.ptr,buffer.length,&numwritten,null) != 1)
+	goto err2;
+
+    if (buffer.length != numwritten)
+	goto err2;
+    
+    if (!CloseHandle(h))
+	goto err;
+    return;
+
+err2:
+    CloseHandle(h);
+err:
+    throw new FileException(name, GetLastError());
+}
+
+
+/*********************************************
+ * Append buffer[] to file name[].
+ * Throws: FileException on error.
+ */
+
+void append(char[] name, void[] buffer)
+{
+    HANDLE h;
+    DWORD numwritten;
+
+    if (useWfuncs)
+    {
+	wchar* namez = std.utf.toUTF16z(name);
+	h = CreateFileW(namez,GENERIC_WRITE,0,null,OPEN_ALWAYS,
+	    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,cast(HANDLE)null);
+    }
+    else
+    {
+	char* namez = toMBSz(name);
+	h = CreateFileA(namez,GENERIC_WRITE,0,null,OPEN_ALWAYS,
+	    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,cast(HANDLE)null);
+    }
+    if (h == INVALID_HANDLE_VALUE)
+	goto err;
+
+    SetFilePointer(h, 0, null, FILE_END);
+
+    if (WriteFile(h,buffer.ptr,buffer.length,&numwritten,null) != 1)
+	goto err2;
+
+    if (buffer.length != numwritten)
+	goto err2;
+    
+    if (!CloseHandle(h))
+	goto err;
+    return;
+
+err2:
+    CloseHandle(h);
+err:
+    throw new FileException(name, GetLastError());
+}
+
+
+/***************************************************
+ * Rename file from[] to to[].
+ * Throws: FileException on error.
+ */
+
+void rename(char[] from, char[] to)
+{
+    BOOL result;
+
+    if (useWfuncs)
+	result = MoveFileW(std.utf.toUTF16z(from), std.utf.toUTF16z(to));
+    else
+	result = MoveFileA(toMBSz(from), toMBSz(to));
+    if (!result)
+	throw new FileException(to, GetLastError());
+}
+
+
+/***************************************************
+ * Delete file name[].
+ * Throws: FileException on error.
+ */
+
+void remove(char[] name)
+{
+    BOOL result;
+
+    if (useWfuncs)
+	result = DeleteFileW(std.utf.toUTF16z(name));
+    else
+	result = DeleteFileA(toMBSz(name));
+    if (!result)
+	throw new FileException(name, GetLastError());
+}
+
+
+/***************************************************
+ * Get size of file name[].
+ * Throws: FileException on error.
+ */
+
+ulong getSize(char[] name)
+{
+    HANDLE findhndl;
+    uint resulth;
+    uint resultl;
+
+    if (useWfuncs)
+    {
+	WIN32_FIND_DATAW filefindbuf;
+
+	findhndl = FindFirstFileW(std.utf.toUTF16z(name), &filefindbuf);
+	resulth = filefindbuf.nFileSizeHigh;
+	resultl = filefindbuf.nFileSizeLow;
+    }
+    else
+    {
+	WIN32_FIND_DATA filefindbuf;
+
+	findhndl = FindFirstFileA(toMBSz(name), &filefindbuf);
+	resulth = filefindbuf.nFileSizeHigh;
+	resultl = filefindbuf.nFileSizeLow;
+    }
+
+    if (findhndl == cast(HANDLE)-1)
+    {
+	throw new FileException(name, GetLastError());
+    }
+    FindClose(findhndl);
+    return (cast(ulong)resulth << 32) + resultl;
+}
+
+/*************************
+ * Get creation/access/modified times of file name[].
+ * Throws: FileException on error.
+ */
+
+void getTimes(char[] name, out d_time ftc, out d_time fta, out d_time ftm)
+{
+    HANDLE findhndl;
+
+    if (useWfuncs)
+    {
+	WIN32_FIND_DATAW filefindbuf;
+
+	findhndl = FindFirstFileW(std.utf.toUTF16z(name), &filefindbuf);
+	ftc = std.date.FILETIME2d_time(&filefindbuf.ftCreationTime);
+	fta = std.date.FILETIME2d_time(&filefindbuf.ftLastAccessTime);
+	ftm = std.date.FILETIME2d_time(&filefindbuf.ftLastWriteTime);
+    }
+    else
+    {
+	WIN32_FIND_DATA filefindbuf;
+
+	findhndl = FindFirstFileA(toMBSz(name), &filefindbuf);
+	ftc = std.date.FILETIME2d_time(&filefindbuf.ftCreationTime);
+	fta = std.date.FILETIME2d_time(&filefindbuf.ftLastAccessTime);
+	ftm = std.date.FILETIME2d_time(&filefindbuf.ftLastWriteTime);
+    }
+
+    if (findhndl == cast(HANDLE)-1)
+    {
+	throw new FileException(name, GetLastError());
+    }
+    FindClose(findhndl);
+}
+
+
+/***************************************************
+ * Does file name[] (or directory) exist?
+ * Return 1 if it does, 0 if not.
+ */
+
+int exists(char[] name)
+{
+    uint result;
+
+    if (useWfuncs)
+	// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base/getfileattributes.asp
+	result = GetFileAttributesW(std.utf.toUTF16z(name));
+    else
+	result = GetFileAttributesA(toMBSz(name));
+
+    return (result == 0xFFFFFFFF) ? 0 : 1;
+}
+
+/***************************************************
+ * Get file name[] attributes.
+ * Throws: FileException on error.
+ */
+
+uint getAttributes(char[] name)
+{
+    uint result;
+
+    if (useWfuncs)
+	result = GetFileAttributesW(std.utf.toUTF16z(name));
+    else
+	result = GetFileAttributesA(toMBSz(name));
+    if (result == 0xFFFFFFFF)
+    {
+	throw new FileException(name, GetLastError());
+    }
+    return result;
+}
+
+/****************************************************
+ * Is name[] a file?
+ * Throws: FileException if name[] doesn't exist.
+ */
+
+int isfile(char[] name)
+{
+    return (getAttributes(name) & FILE_ATTRIBUTE_DIRECTORY) == 0;
+}
+
+/****************************************************
+ * Is name[] a directory?
+ * Throws: FileException if name[] doesn't exist.
+ */
+
+int isdir(char[] name)
+{
+    return (getAttributes(name) & FILE_ATTRIBUTE_DIRECTORY) != 0;
+}
+
+/****************************************************
+ * Change directory to pathname[].
+ * Throws: FileException on error.
+ */
+
+void chdir(char[] pathname)
+{   BOOL result;
+
+    if (useWfuncs)
+	result = SetCurrentDirectoryW(std.utf.toUTF16z(pathname));
+    else
+	result = SetCurrentDirectoryA(toMBSz(pathname));
+
+    if (!result)
+    {
+	throw new FileException(pathname, GetLastError());
+    }
+}
+
+/****************************************************
+ * Make directory pathname[].
+ * Throws: FileException on error.
+ */
+
+void mkdir(char[] pathname)
+{   BOOL result;
+
+    if (useWfuncs)
+	result = CreateDirectoryW(std.utf.toUTF16z(pathname), null);
+    else
+	result = CreateDirectoryA(toMBSz(pathname), null);
+
+    if (!result)
+    {
+	throw new FileException(pathname, GetLastError());
+    }
+}
+
+/****************************************************
+ * Remove directory pathname[].
+ * Throws: FileException on error.
+ */
+
+void rmdir(char[] pathname)
+{   BOOL result;
+
+    if (useWfuncs)
+	result = RemoveDirectoryW(std.utf.toUTF16z(pathname));
+    else
+	result = RemoveDirectoryA(toMBSz(pathname));
+
+    if (!result)
+    {
+	throw new FileException(pathname, GetLastError());
+    }
+}
+
+/****************************************************
+ * Get current directory.
+ * Throws: FileException on error.
+ */
+
+char[] getcwd()
+{
+    if (useWfuncs)
+    {
+	wchar c;
+
+	auto len = GetCurrentDirectoryW(0, &c);
+	if (!len)
+	    goto Lerr;
+	auto dir = new wchar[len];
+	len = GetCurrentDirectoryW(len, dir.ptr);
+	if (!len)
+	    goto Lerr;
+	return std.utf.toUTF8(dir[0 .. len]); // leave off terminating 0
+    }
+    else
+    {
+	char c;
+
+	auto len = GetCurrentDirectoryA(0, &c);
+	if (!len)
+	    goto Lerr;
+	auto dir = new char[len];
+	len = GetCurrentDirectoryA(len, dir.ptr);
+	if (!len)
+	    goto Lerr;
+	return dir[0 .. len];		// leave off terminating 0
+    }
+
+Lerr:
+    throw new FileException("getcwd", GetLastError());
+}
+
+/***************************************************
+ * Directory Entry
+ */
+
+struct DirEntry
+{
+    char[] name;			/// file or directory name
+    ulong size = ~0UL;			/// size of file in bytes
+    d_time creationTime = d_time_nan;	/// time of file creation
+    d_time lastAccessTime = d_time_nan;	/// time file was last accessed
+    d_time lastWriteTime = d_time_nan;	/// time file was last written to
+    uint attributes;		// Windows file attributes OR'd together
+
+    void init(char[] path, WIN32_FIND_DATA *fd)
+    {
+	wchar[] wbuf;
+	size_t clength;
+	size_t wlength;
+	size_t n;
+
+	clength = std.string.strlen(fd.cFileName.ptr);
+
+	// Convert cFileName[] to unicode
+	wlength = MultiByteToWideChar(0,0,fd.cFileName.ptr,clength,null,0);
+	if (wlength > wbuf.length)
+	    wbuf.length = wlength;
+	n = MultiByteToWideChar(0,0,fd.cFileName.ptr,clength,cast(wchar*)wbuf,wlength);
+	assert(n == wlength);
+	// toUTF8() returns a new buffer
+	name = std.path.join(path, std.utf.toUTF8(wbuf[0 .. wlength]));
+
+	size = (cast(ulong)fd.nFileSizeHigh << 32) | fd.nFileSizeLow;
+	creationTime = std.date.FILETIME2d_time(&fd.ftCreationTime);
+	lastAccessTime = std.date.FILETIME2d_time(&fd.ftLastAccessTime);
+	lastWriteTime = std.date.FILETIME2d_time(&fd.ftLastWriteTime);
+	attributes = fd.dwFileAttributes;
+    }
+
+    void init(char[] path, WIN32_FIND_DATAW *fd)
+    {
+	size_t clength = std.string.wcslen(fd.cFileName.ptr);
+	name = std.path.join(path, std.utf.toUTF8(fd.cFileName[0 .. clength]));
+	size = (cast(ulong)fd.nFileSizeHigh << 32) | fd.nFileSizeLow;
+	creationTime = std.date.FILETIME2d_time(&fd.ftCreationTime);
+	lastAccessTime = std.date.FILETIME2d_time(&fd.ftLastAccessTime);
+	lastWriteTime = std.date.FILETIME2d_time(&fd.ftLastWriteTime);
+	attributes = fd.dwFileAttributes;
+    }
+
+    /****
+     * Return !=0 if DirEntry is a directory.
+     */
+    uint isdir()
+    {
+	return attributes & FILE_ATTRIBUTE_DIRECTORY;
+    }
+
+    /****
+     * Return !=0 if DirEntry is a file.
+     */
+    uint isfile()
+    {
+	return !(attributes & FILE_ATTRIBUTE_DIRECTORY);
+    }
+}
+
+
+/***************************************************
+ * Return contents of directory pathname[].
+ * The names in the contents do not include the pathname.
+ * Throws: FileException on error
+ * Example:
+ *	This program lists all the files and subdirectories in its
+ *	path argument.
+ * ----
+ * import std.stdio;
+ * import std.file;
+ *
+ * void main(char[][] args)
+ * {
+ *    auto dirs = std.file.listdir(args[1]);
+ *
+ *    foreach (d; dirs)
+ *	writefln(d);
+ * }
+ * ----
+ */
+
+char[][] listdir(char[] pathname)
+{
+    char[][] result;
+    
+    bool listing(char[] filename)
+    {
+	result ~= filename;
+	return true; // continue
+    }
+    
+    listdir(pathname, &listing);
+    return result;
+}
+
+
+/*****************************************************
+ * Return all the files in the directory and its subdirectories
+ * that match pattern or regular expression r.
+ * Params:
+ *	pathname = Directory name
+ *	pattern = String with wildcards, such as $(RED "*.d"). The supported
+ *		wildcard strings are described under fnmatch() in
+ *		$(LINK2 std_path.html, std.path).
+ *	r = Regular expression, for more powerful _pattern matching.
+ * Example:
+ *	This program lists all the files with a "d" extension in
+ *	the path passed as the first argument.
+ * ----
+ * import std.stdio;
+ * import std.file;
+ *
+ * void main(char[][] args)
+ * {
+ *    auto d_source_files = std.file.listdir(args[1], "*.d");
+ *
+ *    foreach (d; d_source_files)
+ *	writefln(d);
+ * }
+ * ----
+ * A regular expression version that searches for all files with "d" or
+ * "obj" extensions:
+ * ----
+ * import std.stdio;
+ * import std.file;
+ * import std.regexp;
+ *
+ * void main(char[][] args)
+ * {
+ *    auto d_source_files = std.file.listdir(args[1], RegExp(r"\.(d|obj)$"));
+ *
+ *    foreach (d; d_source_files)
+ *	writefln(d);
+ * }
+ * ----
+ */
+
+char[][] listdir(char[] pathname, char[] pattern)
+{   char[][] result;
+    
+    bool callback(DirEntry* de)
+    {
+	if (de.isdir)
+	    listdir(de.name, &callback);
+	else
+	{   if (std.path.fnmatch(de.name, pattern))
+		result ~= de.name;
+	}
+	return true; // continue
+    }
+    
+    listdir(pathname, &callback);
+    return result;
+}
+
+/** Ditto */
+
+char[][] listdir(char[] pathname, RegExp r)
+{   char[][] result;
+    
+    bool callback(DirEntry* de)
+    {
+	if (de.isdir)
+	    listdir(de.name, &callback);
+	else
+	{   if (r.test(de.name))
+		result ~= de.name;
+	}
+	return true; // continue
+    }
+    
+    listdir(pathname, &callback);
+    return result;
+}
+
+/******************************************************
+ * For each file and directory name in pathname[],
+ * pass it to the callback delegate.
+ * Params:
+ *	callback =	Delegate that processes each
+ *			filename in turn. Returns true to
+ *			continue, false to stop.
+ * Example:
+ *	This program lists all the files in its
+ *	path argument, including the path.
+ * ----
+ * import std.stdio;
+ * import std.path;
+ * import std.file;
+ *
+ * void main(char[][] args)
+ * {
+ *    auto pathname = args[1];
+ *    char[][] result;
+ *
+ *    bool listing(char[] filename)
+ *    {
+ *      result ~= std.path.join(pathname, filename);
+ *      return true; // continue
+ *    }
+ *
+ *    listdir(pathname, &listing);
+ *
+ *    foreach (name; result)
+ *      writefln("%s", name);
+ * }
+ * ----
+ */
+
+void listdir(char[] pathname, bool delegate(char[] filename) callback)
+{
+    bool listing(DirEntry* de)
+    {
+	return callback(std.path.getBaseName(de.name));
+    }
+
+    listdir(pathname, &listing);
+}
+
+/******************************************************
+ * For each file and directory DirEntry in pathname[],
+ * pass it to the callback delegate.
+ * Params:
+ *	callback =	Delegate that processes each
+ *			DirEntry in turn. Returns true to
+ *			continue, false to stop.
+ * Example:
+ *	This program lists all the files in its
+ *	path argument and all subdirectories thereof.
+ * ----
+ * import std.stdio;
+ * import std.file;
+ *
+ * void main(char[][] args)
+ * {
+ *    bool callback(DirEntry* de)
+ *    {
+ *      if (de.isdir)
+ *        listdir(de.name, &callback);
+ *      else
+ *        writefln(de.name);
+ *      return true;
+ *    }
+ *
+ *    listdir(args[1], &callback);
+ * }
+ * ----
+ */
+
+void listdir(char[] pathname, bool delegate(DirEntry* de) callback)
+{
+    char[] c;
+    HANDLE h;
+    DirEntry de;
+
+    c = std.path.join(pathname, "*.*");
+    if (useWfuncs)
+    {
+	WIN32_FIND_DATAW fileinfo;
+
+	h = FindFirstFileW(std.utf.toUTF16z(c), &fileinfo);
+	if (h != INVALID_HANDLE_VALUE)
+	{
+	    try
+	    {
+		do
+		{
+		    // Skip "." and ".."
+		    if (std.string.wcscmp(fileinfo.cFileName.ptr, ".") == 0 ||
+			std.string.wcscmp(fileinfo.cFileName.ptr, "..") == 0)
+			continue;
+
+		    de.init(pathname, &fileinfo);
+		    if (!callback(&de))
+			break;
+		} while (FindNextFileW(h,&fileinfo) != FALSE);
+	    }
+	    finally
+	    {
+		FindClose(h);
+	    }
+	}
+    }
+    else
+    {
+	WIN32_FIND_DATA fileinfo;
+
+	h = FindFirstFileA(toMBSz(c), &fileinfo);
+	if (h != INVALID_HANDLE_VALUE)	// should we throw exception if invalid?
+	{
+	    try
+	    {
+		do
+		{
+		    // Skip "." and ".."
+		    if (std.string.strcmp(fileinfo.cFileName.ptr, ".") == 0 ||
+			std.string.strcmp(fileinfo.cFileName.ptr, "..") == 0)
+			continue;
+
+		    de.init(pathname, &fileinfo);
+		    if (!callback(&de))
+			break;
+		} while (FindNextFileA(h,&fileinfo) != FALSE);
+	    }
+	    finally
+	    {
+		FindClose(h);
+	    }
+	}
+    }
+}
+
+/******************************************
+ * Since Win 9x does not support the "W" API's, first convert
+ * to wchar, then convert to multibyte using the current code
+ * page.
+ * (Thanks to yaneurao for this)
+ * Deprecated: use std.windows.charset.toMBSz instead.
+ */
+
+char* toMBSz(char[] s)
+{
+    return std.windows.charset.toMBSz(s);
+}
+
+
+/***************************************************
+ * Copy a file from[] to[].
+ */
+
+void copy(char[] from, char[] to)
+{
+    BOOL result;
+
+    if (useWfuncs)
+	result = CopyFileW(std.utf.toUTF16z(from), std.utf.toUTF16z(to), false);
+    else
+	result = CopyFileA(toMBSz(from), toMBSz(to), false);
+    if (!result)
+         throw new FileException(to, GetLastError());
+}
+
+
+}
+
+/* =========================== linux ======================= */
+
+else version (Unix)
+{
+
+version(linux) {
+  import std.c.linux.linux;
+  alias std.c.linux.linux sys;
+} else {
+  import std.c.unix.unix;
+  alias std.c.unix.unix sys;
+}
+import std.date, std.c.string;
+
+/***********************************
+ */
+
+extern(C) char* strerror_r(int errnum, char* buf, size_t buflen);
+class FileException : Exception
+{
+
+    uint errno;			// operating system error code
+
+    this(char[] name)
+    {
+	this(name, "file I/O");
+    }
+
+    this(char[] name, char[] message)
+    {
+	super(name ~ ": " ~ message);
+    }
+
+    this(char[] name, uint errno)
+    {	char[80] buf = void;
+	auto s = strerror_r(errno, buf.ptr, buf.length);
+	this(name, std.string.toString(s).dup);
+	this.errno = errno;
+    }
+}
+
+/********************************************
+ * Read a file.
+ * Returns:
+ *	array of bytes read
+ */
+
+void[] read(char[] name)
+{
+    uint numread;
+    struct_stat statbuf;
+
+    auto namez = toStringz(name);
+    //printf("file.read('%s')\n",namez);
+    auto fd = sys.open(namez, O_RDONLY);
+    if (fd == -1)
+    {
+        //printf("\topen error, errno = %d\n",getErrno());
+        goto err1;
+    }
+
+    //printf("\tfile opened\n");
+    if (sys.fstat(fd, &statbuf))
+    {
+        //printf("\tfstat error, errno = %d\n",getErrno());
+        goto err2;
+    }
+    auto size = statbuf.st_size;
+    if (size > size_t.max)
+	goto err2;
+
+    auto buf = std.gc.malloc(size);
+    if (buf.ptr)
+	std.gc.hasNoPointers(buf.ptr);
+
+    numread = sys.read(fd, buf.ptr, size);
+    if (numread != size)
+    {
+        //printf("\tread error, errno = %d\n",getErrno());
+        goto err2;
+    }
+
+    if (sys.close(fd) == -1)
+    {
+	//printf("\tclose error, errno = %d\n",getErrno());
+        goto err;
+    }
+
+    return buf[0 .. size];
+
+err2:
+    sys.close(fd);
+err:
+    delete buf;
+
+err1:
+    throw new FileException(name, getErrno());
+}
+
+/*********************************************
+ * Write a file.
+ * Returns:
+ *	0	success
+ */
+
+void write(char[] name, void[] buffer)
+{
+    int fd;
+    char *namez;
+
+    namez = toStringz(name);
+    fd = sys.open(namez, O_CREAT | O_WRONLY | O_TRUNC, 0660);
+    if (fd == -1)
+        goto err;
+
+    auto numwritten = sys.write(fd, buffer.ptr, buffer.length);
+    if (buffer.length != numwritten)
+        goto err2;
+
+    if (sys.close(fd) == -1)
+        goto err;
+
+    return;
+
+err2:
+    sys.close(fd);
+err:
+    throw new FileException(name, getErrno());
+}
+
+
+/*********************************************
+ * Append to a file.
+ */
+
+void append(char[] name, void[] buffer)
+{
+    int fd;
+    char *namez;
+
+    namez = toStringz(name);
+    fd = sys.open(namez, O_APPEND | O_WRONLY | O_CREAT, 0660);
+    if (fd == -1)
+        goto err;
+
+    auto numwritten = sys.write(fd, buffer.ptr, buffer.length);
+    if (buffer.length != numwritten)
+        goto err2;
+
+    if (sys.close(fd) == -1)
+        goto err;
+
+    return;
+
+err2:
+    sys.close(fd);
+err:
+    throw new FileException(name, getErrno());
+}
+
+
+/***************************************************
+ * Rename a file.
+ */
+
+void rename(char[] from, char[] to)
+{
+    char *fromz = toStringz(from);
+    char *toz = toStringz(to);
+
+    if (std.c.stdio.rename(fromz, toz) == -1)
+	throw new FileException(to, getErrno());
+}
+
+
+/***************************************************
+ * Delete a file.
+ */
+
+void remove(char[] name)
+{
+    if (std.c.stdio.remove(toStringz(name)) == -1)
+	throw new FileException(name, getErrno());
+}
+
+
+/***************************************************
+ * Get file size.
+ */
+
+ulong getSize(char[] name)
+{
+    uint size;
+    int fd;
+    struct_stat statbuf;
+    char *namez;
+
+    namez = toStringz(name);
+    //printf("file.getSize('%s')\n",namez);
+    fd = sys.open(namez, O_RDONLY);
+    if (fd == -1)
+    {
+        //printf("\topen error, errno = %d\n",getErrno());
+        goto err1;
+    }
+
+    //printf("\tfile opened\n");
+    if (sys.fstat(fd, &statbuf))
+    {
+        //printf("\tfstat error, errno = %d\n",getErrno());
+        goto err2;
+    }
+    size = statbuf.st_size;
+
+    if (sys.close(fd) == -1)
+    {
+	//printf("\tclose error, errno = %d\n",getErrno());
+        goto err;
+    }
+
+    return size;
+
+err2:
+    sys.close(fd);
+err:
+err1:
+    throw new FileException(name, getErrno());
+}
+
+
+/***************************************************
+ * Get file attributes.
+ */
+
+uint getAttributes(char[] name)
+{
+    struct_stat statbuf;
+    char *namez;
+
+    namez = toStringz(name);
+    if (sys.stat(namez, &statbuf))
+    {
+	throw new FileException(name, getErrno());
+    }
+
+    return statbuf.st_mode;
+}
+
+/*************************
+ * Get creation/access/modified times of file name[].
+ * Throws: FileException on error.
+ */
+
+void getTimes(char[] name, out d_time ftc, out d_time fta, out d_time ftm)
+{
+    struct_stat statbuf;
+    char *namez;
+
+    namez = toStringz(name);
+    if (sys.stat(namez, &statbuf))
+    {
+	throw new FileException(name, getErrno());
+    }
+
+    ftc = cast(d_time)statbuf.st_ctime * std.date.TicksPerSecond;
+    fta = cast(d_time)statbuf.st_atime * std.date.TicksPerSecond;
+    ftm = cast(d_time)statbuf.st_mtime * std.date.TicksPerSecond;
+}
+
+
+/****************************************************
+ * Does file/directory exist?
+ */
+
+int exists(char[] name)
+{
+    return access(toStringz(name),0) == 0;
+
+/+
+    struct_stat statbuf;
+    char *namez;
+
+    namez = toStringz(name);
+    if (sys.stat(namez, &statbuf))
+    {
+	return 0;
+    }
+    return 1;
++/
+}
+
+unittest
+{
+    assert(exists("."));
+}
+
+/****************************************************
+ * Is name a file?
+ */
+
+int isfile(char[] name)
+{
+    return (getAttributes(name) & S_IFMT) == S_IFREG;	// regular file
+}
+
+/****************************************************
+ * Is name a directory?
+ */
+
+int isdir(char[] name)
+{
+    return (getAttributes(name) & S_IFMT) == S_IFDIR;
+}
+
+/****************************************************
+ * Change directory.
+ */
+
+void chdir(char[] pathname)
+{
+    if (sys.chdir(toStringz(pathname)))
+    {
+	throw new FileException(pathname, getErrno());
+    }
+}
+
+/****************************************************
+ * Make directory.
+ */
+
+void mkdir(char[] pathname)
+{
+    if (sys.mkdir(toStringz(pathname), 0777))
+    {
+	throw new FileException(pathname, getErrno());
+    }
+}
+
+/****************************************************
+ * Remove directory.
+ */
+
+void rmdir(char[] pathname)
+{
+    if (sys.rmdir(toStringz(pathname)))
+    {
+	throw new FileException(pathname, getErrno());
+    }
+}
+
+/****************************************************
+ * Get current directory.
+ */
+
+char[] getcwd()
+{
+    version(all)
+    {
+	const PATH_MAX=4096;
+	char buf[PATH_MAX];
+	if (! sys.getcwd(buf.ptr, buf.length))
+	{
+	    throw new FileException("cannot get cwd", getErrno());
+	}
+	size_t len = strlen(buf.ptr);
+	char[] result = new char[len];
+	result[] = buf[0..len];
+	return result;
+    }
+    else
+    {
+    auto p = sys.getcwd(null, 0);
+    if (!p)
+    {
+	throw new FileException("cannot get cwd", getErrno());
+    }
+    auto len = std.string.strlen(p);
+    auto buf = new char[len];
+    buf[] = p[0 .. len];
+    std.c.stdlib.free(p);
+    return buf;
+    }	    
+
+}
+
+/***************************************************
+ * Directory Entry
+ */
+
+struct DirEntry
+{
+    char[] name;			/// file or directory name
+    ulong _size = ~0UL;			// size of file in bytes
+    d_time _creationTime = d_time_nan;	// time of file creation
+    d_time _lastAccessTime = d_time_nan; // time file was last accessed
+    d_time _lastWriteTime = d_time_nan;	// time file was last written to
+    version (GNU)
+	typeof(struct_stat.st_mode) _st_mode;
+    else
+	ubyte d_type;
+    ubyte didstat;			// done lazy evaluation of stat()
+
+    void init(char[] path, dirent *fd)
+    {	size_t len = std.string.strlen(fd.d_name.ptr);
+	name = std.path.join(path, fd.d_name[0 .. len]);
+	version(GNU)
+	    { }
+	else
+	    d_type = fd.d_type;
+	didstat = 0;
+    }
+
+    int isdir()
+    {
+	version(GNU)
+	{
+	    if (!didstat)
+		doStat();
+	    return (_st_mode & S_IFMT) == S_IFDIR;
+	}
+	else
+	    return d_type & DT_DIR;
+    }
+
+    int isfile()
+    {
+	version(GNU)
+	{
+	    if (!didstat)
+		doStat();
+	    return (_st_mode & S_IFMT) == S_IFREG;
+	}
+	else
+	    return d_type & DT_REG;
+    }
+
+    ulong size()
+    {
+	if (!didstat)
+	    doStat();
+	return _size;
+    }
+
+    d_time creationTime()
+    {
+	if (!didstat)
+	    doStat();
+	return _creationTime;
+    }
+
+    d_time lastAccessTime()
+    {
+	if (!didstat)
+	    doStat();
+	return _lastAccessTime;
+    }
+
+    d_time lastWriteTime()
+    {
+	if (!didstat)
+	    doStat();
+	return _lastWriteTime;
+    }
+
+    /* This is to support lazy evaluation, because doing stat's is
+     * expensive and not always needed.
+     */
+
+    void doStat()
+    {
+	int fd;
+	struct_stat statbuf;
+	char* namez;
+
+	namez = toStringz(name);
+	if (sys.stat(namez, &statbuf))
+	{
+	    //printf("\tstat error, errno = %d\n",getErrno());
+	    return;
+	}
+	_size = statbuf.st_size;
+	_creationTime = cast(d_time)statbuf.st_ctime * std.date.TicksPerSecond;
+	_lastAccessTime = cast(d_time)statbuf.st_atime * std.date.TicksPerSecond;
+	_lastWriteTime = cast(d_time)statbuf.st_mtime * std.date.TicksPerSecond;
+	version(GNU) _st_mode = statbuf.st_mode;
+	didstat = 1;
+    }
+}
+
+
+/***************************************************
+ * Return contents of directory.
+ */
+
+char[][] listdir(char[] pathname)
+{
+    char[][] result;
+    
+    bool listing(char[] filename)
+    {
+	result ~= filename;
+	return true; // continue
+    }
+    
+    listdir(pathname, &listing);
+    return result;
+}
+
+char[][] listdir(char[] pathname, char[] pattern)
+{   char[][] result;
+    
+    bool callback(DirEntry* de)
+    {
+	if (de.isdir)
+	    listdir(de.name, &callback);
+	else
+	{   if (std.path.fnmatch(de.name, pattern))
+		result ~= de.name;
+	}
+	return true; // continue
+    }
+    
+    listdir(pathname, &callback);
+    return result;
+}
+
+char[][] listdir(char[] pathname, RegExp r)
+{   char[][] result;
+    
+    bool callback(DirEntry* de)
+    {
+	if (de.isdir)
+	    listdir(de.name, &callback);
+	else
+	{   if (r.test(de.name))
+		result ~= de.name;
+	}
+	return true; // continue
+    }
+    
+    listdir(pathname, &callback);
+    return result;
+}
+
+void listdir(char[] pathname, bool delegate(char[] filename) callback)
+{
+    bool listing(DirEntry* de)
+    {
+	return callback(std.path.getBaseName(de.name));
+    }
+
+    listdir(pathname, &listing);
+}
+
+void listdir(char[] pathname, bool delegate(DirEntry* de) callback)
+{
+    DIR* h;
+    dirent* fdata;
+    DirEntry de;
+
+    h = opendir(toStringz(pathname));
+    if (h)
+    {
+	try
+	{
+	    while((fdata = readdir(h)) != null)
+	    {
+		// Skip "." and ".."
+		if (!std.string.strcmp(fdata.d_name.ptr, ".") ||
+		    !std.string.strcmp(fdata.d_name.ptr, ".."))
+			continue;
+
+		de.init(pathname, fdata);
+		if (!callback(&de))	    
+		    break;
+	    }
+	}
+	finally
+	{
+	    closedir(h);
+	}
+    }
+    else
+    {
+        throw new FileException(pathname, getErrno());
+    }
+}
+
+
+/***************************************************
+ * Copy a file. File timestamps are preserved.
+ */
+
+void copy(char[] from, char[] to)
+{
+  version (all)
+  {
+    struct_stat statbuf;
+
+    char* fromz = toStringz(from);
+    char* toz = toStringz(to);
+    //printf("file.copy(from='%s', to='%s')\n", fromz, toz);
+
+    int fd = sys.open(fromz, O_RDONLY);
+    if (fd == -1)
+    {
+        //printf("\topen error, errno = %d\n",getErrno());
+        goto err1;
+    }
+
+    //printf("\tfile opened\n");
+    if (sys.fstat(fd, &statbuf))
+    {
+        //printf("\tfstat error, errno = %d\n",getErrno());
+        goto err2;
+    }
+
+    int fdw = sys.open(toz, O_CREAT | O_WRONLY | O_TRUNC, 0660);
+    if (fdw == -1)
+    {
+        //printf("\topen error, errno = %d\n",getErrno());
+        goto err2;
+    }
+
+    size_t BUFSIZ = 4096 * 16;
+    void* buf = std.c.stdlib.malloc(BUFSIZ);
+    if (!buf)
+    {	BUFSIZ = 4096;
+	buf = std.c.stdlib.malloc(BUFSIZ);
+    }
+    if (!buf)
+    {
+        //printf("\topen error, errno = %d\n",getErrno());
+        goto err4;
+    }
+
+    for (auto size = statbuf.st_size; size; )
+    {	size_t toread = (size > BUFSIZ) ? BUFSIZ : size;
+
+	auto n = sys.read(fd, buf, toread);
+	if (n != toread)
+	{
+	    //printf("\tread error, errno = %d\n",getErrno());
+	    goto err5;
+	}
+	n = sys.write(fdw, buf, toread);
+	if (n != toread)
+	{
+	    //printf("\twrite error, errno = %d\n",getErrno());
+	    goto err5;
+	}
+	size -= toread;
+    }
+
+    std.c.stdlib.free(buf);
+
+    if (sys.close(fdw) == -1)
+    {
+	//printf("\tclose error, errno = %d\n",getErrno());
+        goto err2;
+    }
+
+    utimbuf utim;
+    utim.actime = cast(typeof(utim.actime))statbuf.st_atime;
+    utim.modtime = cast(typeof(utim.modtime))statbuf.st_mtime;
+    if (utime(toz, &utim) == -1)
+    {
+	//printf("\tutime error, errno = %d\n",getErrno());
+	goto err3;
+    }
+
+    if (sys.close(fd) == -1)
+    {
+	//printf("\tclose error, errno = %d\n",getErrno());
+        goto err1;
+    }
+
+    return;
+
+err5:
+    std.c.stdlib.free(buf);
+err4:
+    sys.close(fdw);
+err3:
+    std.c.stdio.remove(toz);
+err2:
+    sys.close(fd);
+err1:
+    throw new FileException(from, getErrno());
+  }
+  else
+  {
+    void[] buffer;
+
+    buffer = read(from);
+    write(to, buffer);
+    delete buffer;
+  }
+}
+
+
+
+}
+
+unittest
+{
+    //printf("std.file.unittest\n");
+    void[] buf;
+
+    buf = new void[10];
+    (cast(byte[])buf)[] = 3;
+    write("unittest_write.tmp", buf);
+    void buf2[] = read("unittest_write.tmp");
+    assert(buf == buf2);
+
+    copy("unittest_write.tmp", "unittest_write2.tmp");
+    buf2 = read("unittest_write2.tmp");
+    assert(buf == buf2);
+
+    remove("unittest_write.tmp");
+    if (exists("unittest_write.tmp"))
+	assert(0);
+    remove("unittest_write2.tmp");
+    if (exists("unittest_write2.tmp"))
+	assert(0);
+}
+
+unittest
+{
+    listdir (".", delegate bool (DirEntry * de)
+    {
+	auto s = std.string.format("%s : c %s, w %s, a %s", de.name,
+		toUTCString (de.creationTime),
+		toUTCString (de.lastWriteTime),
+		toUTCString (de.lastAccessTime));
+	return true;
+    }
+    );
+}
+
+
--- a/lphobos/std/intrinsic.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/std/intrinsic.d	Mon Aug 04 19:28:49 2008 +0200
@@ -207,7 +207,7 @@
 	becomes byte 0.
  */
 version (LLVM)
-pragma(LLVM_internal, "intrinsic", "llvm.bswap.i32")
+pragma(intrinsic, "llvm.bswap.i32")
     uint bswap(uint val);
 else
     uint bswap(uint v);
--- a/lphobos/std/math.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/std/math.d	Mon Aug 04 19:28:49 2008 +0200
@@ -190,13 +190,14 @@
  *	Results are undefined if |x| >= $(POWER 2,64).
  */
 
-pragma(LLVM_internal, "intrinsic", "llvm.cos.f32")
+pragma(intrinsic, "llvm.cos.f32")
 float cos(float x);
 
-pragma(LLVM_internal, "intrinsic", "llvm.cos.f64") {
+pragma(intrinsic, "llvm.cos.f64")
 double cos(double x); // ditto
+
+pragma(intrinsic, "llvm.cos.f80")
 real cos(real x); /// ditto
-}
 
 
 /***********************************
@@ -212,13 +213,14 @@
  *	Results are undefined if |x| >= $(POWER 2,64).
  */
 
-pragma(LLVM_internal, "intrinsic", "llvm.sin.f32")
+pragma(intrinsic, "llvm.sin.f32")
 float sin(float x);
 
-pragma(LLVM_internal, "intrinsic", "llvm.sin.f64") {
+pragma(intrinsic, "llvm.sin.f64")
 double sin(double x); // ditto
+
+pragma(intrinsic, "llvm.sin.f80")
 real sin(real x); /// ditto
-}
 
 
 /****************************************************************************
@@ -553,13 +555,14 @@
  *	)
  */
 
-pragma(LLVM_internal, "intrinsic", "llvm.sqrt.f32")
+pragma(intrinsic, "llvm.sqrt.f32")
 float sqrt(float x);	/* intrinsic */
 
-pragma(LLVM_internal, "intrinsic", "llvm.sqrt.f64") {
+pragma(intrinsic, "llvm.sqrt.f64")
 double sqrt(double x);	/* intrinsic */	/// ditto
+
+pragma(intrinsic, "llvm.sqrt.f80")
 real sqrt(real x);	/* intrinsic */ /// ditto
-}
 
 creal sqrt(creal z)
 {
@@ -1499,19 +1502,23 @@
  * Fast integral powers.
  */
 
-pragma(LLVM_internal, "intrinsic", "llvm.powi.f32")
+pragma(intrinsic, "llvm.powi.f32")
 {
 float pow(float x, uint n);
 /// ditto
 float pow(float x, int n);
 }
 
-pragma(LLVM_internal, "intrinsic", "llvm.powi.f64")
+pragma(intrinsic, "llvm.powi.f64")
 {
 /// ditto
 double pow(double x, uint n);
 /// ditto
 double pow(double x, int n);
+}
+
+pragma(intrinsic, "llvm.powi.f80")
+{
 /// ditto
 real pow(real x, uint n);
 /// ditto
@@ -1606,16 +1613,14 @@
  * )
  */
 
-pragma(LLVM_internal, "intrinsic", "llvm.pow.f32")
+pragma(intrinsic, "llvm.pow.f32")
 float pow(float x, float y);
 
-pragma(LLVM_internal, "intrinsic", "llvm.pow.f64")
-{
-/// ditto
+pragma(intrinsic, "llvm.pow.f64")
 double pow(double x, double y);
-/// ditto
+
+pragma(intrinsic, "llvm.pow.f80")
 real pow(real x, real y);
-}
 
 /+
 real pow(real x, real y);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/md5.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,504 @@
+/* md5.d - RSA Data Security, Inc., MD5 message-digest algorithm
+ * Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm.
+ */
+
+/**
+ * Computes MD5 digests of arbitrary data. MD5 digests are 16 byte quantities that are like a checksum or crc, but are more robust. 
+ *
+ * There are two ways to do this. The first does it all in one function call to
+ * sum(). The second is for when the data is buffered. 
+ *
+ * Bugs:
+ * MD5 digests have been demonstrated to not be unique.
+ *
+ * Author:
+ * The routines and algorithms are derived from the
+ * $(I RSA Data Security, Inc. MD5 Message-Digest Algorithm).
+ *
+ * References:
+ *	$(LINK2 http://en.wikipedia.org/wiki/Md5, Wikipedia on MD5)
+ *
+ * Macros:
+ *	WIKI = Phobos/StdMd5
+ */
+
+/++++++++++++++++++++++++++++++++
+ Example:
+
+--------------------
+// This code is derived from the
+// RSA Data Security, Inc. MD5 Message-Digest Algorithm.
+
+import std.md5;
+
+private import std.stdio;
+private import std.string;
+private import std.c.stdio;
+private import std.c.string;
+
+int main(char[][] args)
+{
+    foreach (char[] arg; args)
+	 MDFile(arg);
+    return 0;
+}
+
+/* Digests a file and prints the result. */
+void MDFile(char[] filename)
+{
+    FILE* file;
+    MD5_CTX context;
+    int len;
+    ubyte[4 * 1024] buffer;
+    ubyte digest[16];
+
+    if ((file = fopen(std.string.toStringz(filename), "rb")) == null)
+	writefln("%s can't be opened", filename);
+    else
+    {
+	context.start();
+	while ((len = fread(buffer, 1, buffer.sizeof, file)) != 0)
+	    context.update(buffer[0 .. len]);
+	context.finish(digest);
+	fclose(file);
+
+	writefln("MD5 (%s) = %s", filename, digestToString(digest));
+    }
+}
+--------------------
+ +/
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* NOTE: This file has been patched from the original DMD distribution to
+   work with the GDC compiler.
+
+   Modified by David Friedman, September 2004
+*/
+
+module std.md5;
+
+//debug=md5;		// uncomment to turn on debugging printf's
+
+import std.string;
+
+version(D_InlineAsm)
+    version(X86)
+	version = Asm86;
+
+/***************************************
+ * Computes MD5 digest of array of data.
+ */
+
+void sum(ubyte[16] digest, void[] data)
+{
+    MD5_CTX context;
+
+    context.start();
+    context.update(data);
+    context.finish(digest);
+}
+
+/******************
+ * Prints a message digest in hexadecimal to stdout.
+ */
+void printDigest(ubyte digest[16])
+{
+    foreach (ubyte u; digest)
+	printf("%02x", u);
+}
+
+/****************************************
+ * Converts MD5 digest to a string.
+ */
+
+char[] digestToString(ubyte[16] digest)
+{
+    char[] result = new char[32];
+    int i;
+
+    foreach (ubyte u; digest)
+    {
+	result[i] = std.string.hexdigits[u >> 4];
+	result[i + 1] = std.string.hexdigits[u & 15];
+	i += 2;
+    }
+    return result;
+}
+
+/**
+ * Holds context of MD5 computation.
+ *
+ * Used when data to be digested is buffered.
+ */
+struct MD5_CTX
+{
+    uint state[4] =                                   /* state (ABCD) */
+    /* magic initialization constants */
+    [0x67452301,0xefcdab89,0x98badcfe,0x10325476];
+
+    ulong count;	/* number of bits, modulo 2^64 */
+    ubyte buffer[64];	/* input buffer */
+
+    static ubyte[64] PADDING =
+    [
+      0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+    ];
+
+    /* F, G, H and I are basic MD5 functions.
+     */
+    private static
+    {
+	uint F(uint x, uint y, uint z) { return (x & y) | (~x & z); }
+	uint G(uint x, uint y, uint z) { return (x & z) | (y & ~z); }
+	uint H(uint x, uint y, uint z) { return x ^ y ^ z; }
+	uint I(uint x, uint y, uint z) { return y ^ (x | ~z); }
+    }
+
+    /* ROTATE_LEFT rotates x left n bits.
+     */
+    static uint ROTATE_LEFT(uint x, uint n)
+    {
+	version (Asm86)
+	{
+	    version (GNU)
+	    {
+		asm
+		{
+		    naked ;
+		    mov ECX, n ;
+		    mov EAX, x ;
+		    rol EAX, CL ;
+		    ret ;
+		}
+	    }
+	    else
+	    {
+		asm
+		{   naked			;
+		    mov	ECX,EAX		;
+		    mov	EAX,4[ESP]	;
+		    rol	EAX,CL		;
+		    ret	4		;
+		}
+	    }
+	}
+	else
+	{
+	    return (x << n) | (x >> (32-n));
+	}
+    }
+
+    /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+     * Rotation is separate from addition to prevent recomputation.
+     */
+    static void FF(inout uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
+    {
+	a += F (b, c, d) + x + cast(uint)(ac);
+	a = ROTATE_LEFT (a, s);
+	a += b;
+    }
+
+    static void GG(inout uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
+    {
+	a += G (b, c, d) + x + cast(uint)(ac);
+	a = ROTATE_LEFT (a, s);
+	a += b;
+    }
+
+    static void HH(inout uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
+    {
+	a += H (b, c, d) + x + cast(uint)(ac);
+	a = ROTATE_LEFT (a, s);
+	a += b;
+    }
+
+    static void II(inout uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
+    {
+	a += I (b, c, d) + x + cast(uint)(ac);
+	a = ROTATE_LEFT (a, s);
+	a += b;
+    }
+
+    /**
+     * MD5 initialization. Begins an MD5 operation, writing a new context.
+     */
+    void start()
+    {
+	*this = MD5_CTX.init;
+    }
+
+    /** MD5 block update operation. Continues an MD5 message-digest
+      operation, processing another message block, and updating the
+      context.
+     */
+    void update(void[] input)
+    {
+      uint index, partLen;
+      size_t i;
+      size_t inputLen = input.length;
+
+      /* Compute number of bytes mod 64 */
+      index = (cast(uint)count >> 3) & (64 - 1);
+
+      /* Update number of bits */
+      count += inputLen * 8;
+
+      partLen = 64 - index;
+
+      /* Transform as many times as possible. */
+      if (inputLen >= partLen)
+      {
+	    std.c.string.memcpy(&buffer[index], input.ptr, partLen);
+	    transform (buffer.ptr);
+
+	    for (i = partLen; i + 63 < inputLen; i += 64)
+	       transform ((cast(ubyte[])input)[i .. i + 64].ptr);
+
+	    index = 0;
+      }
+      else
+	    i = 0;
+
+      /* Buffer remaining input */
+      if (inputLen - i)
+	    std.c.string.memcpy(&buffer[index], &input[i], inputLen-i);
+    }
+
+    /** MD5 finalization. Ends an MD5 message-digest operation, writing the
+     * the message to digest and zeroing the context.
+     */
+    void finish(ubyte[16] digest)         /* message digest */
+    {
+      ubyte bits[8];
+      uint index, padLen;
+      uint[2] cnt;
+
+      /* Save number of bits */
+      cnt[0] = cast(uint)count;
+      cnt[1] = cast(uint)(count >> 32);
+      Encode (bits.ptr, cnt.ptr, 8);
+
+      /* Pad out to 56 mod 64. */
+      index = (cast(uint)count >> 3) & (64 - 1);
+      padLen = (index < 56) ? (56 - index) : (120 - index);
+      update (PADDING[0 .. padLen]);
+
+      /* Append length (before padding) */
+      update (bits);
+
+      /* Store state in digest */
+      Encode (digest.ptr, state.ptr, 16);
+
+      /* Zeroize sensitive information. */
+      std.c.string.memset (this, 0, MD5_CTX.sizeof);
+    }
+
+    /* MD5 basic transformation. Transforms state based on block.
+     */
+
+    /* Constants for MD5Transform routine. */
+    enum
+    {
+	S11 = 7,
+	S12 = 12,
+	S13 = 17,
+	S14 = 22,
+	S21 = 5,
+	S22 = 9,
+	S23 = 14,
+	S24 = 20,
+	S31 = 4,
+	S32 = 11,
+	S33 = 16,
+	S34 = 23,
+	S41 = 6,
+	S42 = 10,
+	S43 = 15,
+	S44 = 21,
+    }
+
+    private void transform (ubyte* /*[64]*/ block)
+    {
+      uint a = state[0],
+	   b = state[1],
+	   c = state[2],
+	   d = state[3];
+      uint[16] x;
+
+      Decode (x.ptr, block, 64);
+
+      /* Round 1 */
+      FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+      FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+      FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+      FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+      FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+      FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+      FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+      FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+      FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+      FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+      FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+      FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+      FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+      FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+      FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+      FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+     /* Round 2 */
+      GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+      GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+      GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+      GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+      GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+      GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
+      GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+      GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+      GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+      GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+      GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+      GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+      GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+      GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+      GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+      GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+      /* Round 3 */
+      HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+      HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+      HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+      HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+      HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+      HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+      HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+      HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+      HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+      HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+      HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+      HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
+      HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+      HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+      HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+      HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+      /* Round 4 */
+      II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+      II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+      II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+      II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+      II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+      II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+      II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+      II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+      II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+      II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+      II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+      II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+      II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+      II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+      II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+      II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+      state[0] += a;
+      state[1] += b;
+      state[2] += c;
+      state[3] += d;
+
+      /* Zeroize sensitive information. */
+      x[] = 0;
+    }
+
+    /* Encodes input (uint) into output (ubyte). Assumes len is
+      a multiple of 4.
+     */
+    private static void Encode (ubyte *output, uint *input, uint len)
+    {
+	uint i, j;
+
+	for (i = 0, j = 0; j < len; i++, j += 4)
+	{
+	    uint u = input[i];
+	    output[j]   = cast(ubyte)(u);
+	    output[j+1] = cast(ubyte)(u >> 8);
+	    output[j+2] = cast(ubyte)(u >> 16);
+	    output[j+3] = cast(ubyte)(u >> 24);
+	}
+    }
+
+    /* Decodes input (ubyte) into output (uint). Assumes len is
+      a multiple of 4.
+     */
+    private static void Decode (uint *output, ubyte *input, uint len)
+    {
+	uint i, j;
+
+	for (i = 0, j = 0; j < len; i++, j += 4)
+	{
+	    version (LittleEndian)
+	    {
+		output[i] = *cast(uint*)&input[j];
+	    }
+	    else
+	    {
+		output[i] = (cast(uint)input[j]) | ((cast(uint)input[j+1]) << 8) |
+			((cast(uint)input[j+2]) << 16) | ((cast(uint)input[j+3]) << 24);
+	    }
+	}
+    }
+}
+
+unittest
+{
+    debug(md5) printf("std.md5.unittest\n");
+
+    ubyte[16] digest;
+
+    sum (digest, "");
+    assert(digest == cast(ubyte[])x"d41d8cd98f00b204e9800998ecf8427e");
+
+    sum (digest, "a");
+    assert(digest == cast(ubyte[])x"0cc175b9c0f1b6a831c399e269772661");
+
+    sum (digest, "abc");
+    assert(digest == cast(ubyte[])x"900150983cd24fb0d6963f7d28e17f72");
+
+    sum (digest, "message digest");
+    assert(digest == cast(ubyte[])x"f96b697d7cb7938d525a2f31aaf161d0");
+
+    sum (digest, "abcdefghijklmnopqrstuvwxyz");
+    assert(digest == cast(ubyte[])x"c3fcd3d76192e4007dfb496cca67e13b");
+
+    sum (digest, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+    assert(digest == cast(ubyte[])x"d174ab98d277d9f5a5611c2c9f419d9f");
+
+    sum (digest,
+	"1234567890123456789012345678901234567890"
+	"1234567890123456789012345678901234567890");
+    assert(digest == cast(ubyte[])x"57edf4a22be3c955ac49da2e2107b67a");
+
+    assert(digestToString(cast(ubyte[16])x"c3fcd3d76192e4007dfb496cca67e13b")
+        == "C3FCD3D76192E4007DFB496CCA67E13B");
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/mmfile.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,648 @@
+/* Copyright 2004-2005 by Digital Mars
+ * Written by Walter Bright and Matthew Wilson
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, in both source and binary form, subject to the following
+ * restrictions:
+ *
+ * -  The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * -  Altered source versions must be plainly marked as such, and must not
+ *    be misrepresented as being the original software.
+ * -  This notice may not be removed or altered from any source
+ *    distribution.
+ *
+ */
+
+/**
+ * Read and write memory mapped files.
+ * Macros:
+ *	WIKI=Phobos/StdMmfile
+ */
+
+/* NOTE: This file has been patched from the original DMD distribution to
+   work with the GDC compiler.
+
+   Modified by David Friedman, September 2004
+*/
+
+module std.mmfile;
+
+private import std.c.stdio;
+private import std.c.stdlib;
+private import std.string;
+
+//debug = MMFILE;
+
+version (Win32)
+{
+	private import std.c.windows.windows;
+	private import std.utf;
+	
+	private uint dwVersion;
+	
+	static this()
+	{	// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/getversion.asp
+		dwVersion = GetVersion();
+	}
+
+	private const bool Have_MMFile = true; // private for now...
+}
+else version (Unix)
+{
+	version (/*GNU_Unix_Have_MMap*/Unix)
+	{
+	    version(linux) {
+		import std.c.linux.linux;
+		alias std.c.linux.linux unix;
+	    } else {
+		private import std.c.unix.unix;
+		alias std.c.unix.unix unix;
+	    }
+
+	    version = unix_mm;
+	    private const bool Have_MMFile = true;
+	}
+	else
+	{
+	    private const bool Have_MMFile = false;
+	}
+
+}
+else
+{
+	private const bool Have_MMFile = false;
+	// Can't simply fail because std.stream imports this module.
+	//static assert(0);
+}
+
+static if (Have_MMFile)
+{
+    private import std.file;
+    private import std.path;
+}
+
+/**
+ * MmFile objects control the memory mapped file resource.
+ */
+class MmFile
+{
+    /**
+     * The mode the memory mapped file is opened with.
+     */
+    enum Mode
+    {	Read,		/// read existing file
+	ReadWriteNew,	/// delete existing file, write new file
+	ReadWrite,	/// read/write existing file, create if not existing
+	ReadCopyOnWrite, /// read/write existing file, copy on write
+    }
+    
+    /**
+     * Open memory mapped file filename for reading.
+     * File is closed when the object instance is deleted.
+     * Throws:
+     *	std.file.FileException
+     */
+    this(char[] filename)
+    {
+		this(filename, Mode.Read, 0, null);
+    }
+    
+    /**
+     * Open memory mapped file filename in mode.
+     * File is closed when the object instance is deleted.
+     * Params:
+     *	filename = name of the file.
+     *		If null, an anonymous file mapping is created.
+     *	mode = access mode defined above.
+     *	size =  the size of the file. If 0, it is taken to be the
+     *		size of the existing file.
+     *	address = the preferred address to map the file to,
+     *		although the system is not required to honor it.
+     *		If null, the system selects the most convenient address.
+     *	window = preferred block size of the amount of data to map at one time
+     *		with 0 meaning map the entire file. The window size must be a
+     *		multiple of the memory allocation page size. 
+     * Throws:
+     *	std.file.FileException
+     */
+    this(char[] filename, Mode mode, ulong size, void* address,
+			size_t window = 0)
+    {
+		this.filename = filename;
+		this.mMode = mode;
+		this.window = window;
+		this.address = address;
+	
+		version (Win32)
+		{
+			void* p;
+			uint dwDesiredAccess2;
+			uint dwShareMode;
+			uint dwCreationDisposition;
+			uint flProtect;
+	    
+			if (dwVersion & 0x80000000 && (dwVersion & 0xFF) == 3)
+			{
+			    throw new FileException(filename,
+				"Win32s does not implement mm files");
+			}
+	    
+			switch (mode)
+			{
+			    case Mode.Read:
+				dwDesiredAccess2 = GENERIC_READ;
+				dwShareMode = FILE_SHARE_READ;
+				dwCreationDisposition = OPEN_EXISTING;
+				flProtect = PAGE_READONLY;
+				dwDesiredAccess = FILE_MAP_READ;
+				break;
+
+			    case Mode.ReadWriteNew:
+				assert(size != 0);
+				dwDesiredAccess2 = GENERIC_READ | GENERIC_WRITE;
+				dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+				dwCreationDisposition = CREATE_ALWAYS;
+				flProtect = PAGE_READWRITE;
+				dwDesiredAccess = FILE_MAP_WRITE;
+				break;
+
+			    case Mode.ReadWrite:
+				dwDesiredAccess2 = GENERIC_READ | GENERIC_WRITE;
+				dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+				dwCreationDisposition = OPEN_ALWAYS;
+				flProtect = PAGE_READWRITE;
+				dwDesiredAccess = FILE_MAP_WRITE;
+				break;
+
+			    case Mode.ReadCopyOnWrite:
+				if (dwVersion & 0x80000000)
+				{
+				    throw new FileException(filename,
+					"Win9x does not implement copy on write");
+				}
+				dwDesiredAccess2 = GENERIC_READ | GENERIC_WRITE;
+				dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+				dwCreationDisposition = OPEN_EXISTING;
+				flProtect = PAGE_WRITECOPY;
+				dwDesiredAccess = FILE_MAP_COPY;
+				break;
+
+			    default:
+				assert(0);
+			}
+		
+			if (filename)
+			{
+				if (useWfuncs)
+				{
+					auto namez = std.utf.toUTF16z(filename);
+					hFile = CreateFileW(namez,
+							dwDesiredAccess2,
+							dwShareMode,
+							null,
+							dwCreationDisposition,
+							FILE_ATTRIBUTE_NORMAL,
+							cast(HANDLE)null);
+				}
+				else
+				{
+					auto namez = std.file.toMBSz(filename);
+					hFile = CreateFileA(namez,
+							dwDesiredAccess2,
+							dwShareMode,
+							null,
+							dwCreationDisposition,
+							FILE_ATTRIBUTE_NORMAL,
+							cast(HANDLE)null);
+				}
+				if (hFile == INVALID_HANDLE_VALUE)
+					goto err1;
+			}
+			else
+				hFile = null;
+		
+			int hi = cast(int)(size>>32);
+			hFileMap = CreateFileMappingA(hFile, null, flProtect, hi, cast(uint)size, null);
+			if (hFileMap == null)               // mapping failed
+				goto err1;
+		
+			if (size == 0)
+			{
+				uint sizehi;
+				uint sizelow = GetFileSize(hFile,&sizehi);
+				size = (cast(ulong)sizehi << 32) + sizelow;
+			}
+			this.size = size;
+		
+			size_t initial_map = (window && 2*window<size)? 2*window : cast(size_t)size;
+			p = MapViewOfFileEx(hFileMap, dwDesiredAccess, 0, 0, initial_map, address);
+			if (!p) goto err1;
+			data = p[0 .. initial_map];
+		
+			debug (MMFILE) printf("MmFile.this(): p = %p, size = %d\n", p, size);
+			return;
+		
+			err1:
+			if (hFileMap != null)
+				CloseHandle(hFileMap);
+			hFileMap = null;
+		
+			if (hFile != INVALID_HANDLE_VALUE)
+				CloseHandle(hFile);
+			hFile = INVALID_HANDLE_VALUE;
+		
+			errNo();
+		}
+		else version (unix_mm)
+		{
+			char* namez = toStringz(filename);
+			void* p;
+			int oflag;
+			int fmode;
+	
+			switch (mode)
+			{
+				case Mode.Read:
+					flags = MAP_SHARED;
+					prot = PROT_READ;
+					oflag = O_RDONLY;
+					fmode = 0;
+					break;
+	
+				case Mode.ReadWriteNew:
+					assert(size != 0);
+					flags = MAP_SHARED;
+					prot = PROT_READ | PROT_WRITE;
+					oflag = O_CREAT | O_RDWR | O_TRUNC;
+					fmode = 0660;
+					break;
+	
+				case Mode.ReadWrite:
+					flags = MAP_SHARED;
+					prot = PROT_READ | PROT_WRITE;
+					oflag = O_CREAT | O_RDWR;
+					fmode = 0660;
+					break;
+	
+				case Mode.ReadCopyOnWrite:
+					flags = MAP_PRIVATE;
+					prot = PROT_READ | PROT_WRITE;
+					oflag = O_RDWR;
+					fmode = 0;
+					break;
+
+				default:
+					assert(0);
+			}
+	
+			if (filename.length)
+			{	
+				struct_stat statbuf;
+	
+				fd = unix.open(namez, oflag, fmode);
+				if (fd == -1)
+				{
+					// printf("\topen error, errno = %d\n",getErrno());
+					errNo();
+				}
+	
+				if (unix.fstat(fd, &statbuf))
+				{
+					//printf("\tfstat error, errno = %d\n",getErrno());
+					unix.close(fd);
+					errNo();
+				}
+	
+				if (prot & PROT_WRITE && size > statbuf.st_size)
+				{
+					// Need to make the file size bytes big
+					unix.lseek(fd, cast(off_t)(size - 1), SEEK_SET);
+					char c = 0;
+					unix.write(fd, &c, 1);
+				}
+				else if (prot & PROT_READ && size == 0)
+					size = statbuf.st_size;
+			}
+			else
+			{
+				fd = -1;
+				flags |= MAP_ANONYMOUS;
+			}
+			this.size = size;
+			size_t initial_map = (window && 2*window<size)? 2*window : cast(size_t)size;
+			p = mmap(address, initial_map, prot, flags, fd, 0);
+			if (p == MAP_FAILED) {
+			  if (fd != -1)
+			    unix.close(fd);
+			  errNo();
+			}
+
+			data = p[0 .. initial_map];
+		}
+		else static if (! Have_MMFile)
+		{
+		    throw new FileException("This system does support memory mapped files");
+		}
+		else
+		{
+			static assert(0);
+		}
+	}
+
+	/**
+	 * Flushes pending output and closes the memory mapped file.
+	 */
+	~this()
+	{
+		debug (MMFILE) printf("MmFile.~this()\n");
+		unmap();
+		version (Win32)
+		{
+			if (hFileMap != null && CloseHandle(hFileMap) != TRUE)
+				errNo();
+			hFileMap = null;
+
+			if (hFile != INVALID_HANDLE_VALUE && CloseHandle(hFile) != TRUE)
+				errNo();
+			hFile = INVALID_HANDLE_VALUE;
+		}
+		else version (unix_mm)
+		{
+			if (fd != -1 && unix.close(fd) == -1)
+				errNo();
+			fd = -1;
+		}
+		else static if (! Have_MMFile)
+		{
+		} 
+		else
+		{
+			static assert(0);
+		}
+		data = null;
+	}
+
+	/* Flush any pending output.
+	*/
+	void flush()
+	{
+		debug (MMFILE) printf("MmFile.flush()\n");
+		version (Win32)
+		{
+			FlushViewOfFile(data.ptr, data.length);
+		}
+		else version (unix_mm)
+		{
+			int i;
+
+			i = msync(cast(void*)data, data.length, MS_SYNC);	// sys/mman.h
+			if (i != 0)
+				errNo();
+		}
+		else static if (! Have_MMFile)
+		{
+		} 
+		else
+		{
+			static assert(0);
+		}
+	}
+
+	/**
+	 * Gives size in bytes of the memory mapped file.
+	 */
+	ulong length()
+	{
+		debug (MMFILE) printf("MmFile.length()\n");
+		return size;
+	}
+
+	/**
+	 * Read-only property returning the file mode.
+	 */
+	Mode mode()
+	{
+		debug (MMFILE) printf("MmFile.mode()\n");
+		return mMode;
+	}
+
+	/**
+	 * Returns entire file contents as an array.
+	 */
+	void[] opSlice()
+	{
+		debug (MMFILE) printf("MmFile.opSlice()\n");
+		return opSlice(0,size);
+	}
+
+	/**
+	 * Returns slice of file contents as an array.
+	 */
+	void[] opSlice(ulong i1, ulong i2)
+	{
+		debug (MMFILE) printf("MmFile.opSlice(%lld, %lld)\n", i1, i2);
+		ensureMapped(i1,i2);
+		size_t off1 = cast(size_t)(i1-start);
+		size_t off2 = cast(size_t)(i2-start);
+		return data[off1 .. off2];
+	}
+
+	/**
+	 * Returns byte at index i in file.
+	 */
+	ubyte opIndex(ulong i)
+	{
+		debug (MMFILE) printf("MmFile.opIndex(%lld)\n", i);
+		ensureMapped(i);
+		size_t off = cast(size_t)(i-start);
+		return (cast(ubyte[])data)[off];
+	}
+
+	/**
+	 * Sets and returns byte at index i in file to value.
+	 */
+	ubyte opIndexAssign(ubyte value, ulong i)
+	{
+		debug (MMFILE) printf("MmFile.opIndex(%lld, %d)\n", i, value);
+		ensureMapped(i);
+		size_t off = cast(size_t)(i-start);
+		return (cast(ubyte[])data)[off] = value;
+	}
+
+
+	// return true if the given position is currently mapped
+	private int mapped(ulong i) 
+	{
+		debug (MMFILE) printf("MmFile.mapped(%lld, %lld, %d)\n", i,start, 
+				data.length);
+		return i >= start && i < start+data.length;
+	}
+
+	// unmap the current range
+	private void unmap() 
+	{
+		debug (MMFILE) printf("MmFile.unmap()\n");
+		version(Windows) {
+			/* Note that under Windows 95, UnmapViewOfFile() seems to return
+			* random values, not TRUE or FALSE.
+			*/
+			if (data && UnmapViewOfFile(data.ptr) == FALSE &&
+				(dwVersion & 0x80000000) == 0)
+				errNo();
+		} else version (unix_mm) {
+			if (data && munmap(cast(void*)data, data.length) != 0)
+				errNo();
+		}
+		data = null;
+	}
+
+	// map range
+	private void map(ulong start, size_t len) 
+	{
+		debug (MMFILE) printf("MmFile.map(%lld, %d)\n", start, len);
+		void* p;
+		if (start+len > size)
+			len = cast(size_t)(size-start);
+		version(Windows) {
+			uint hi = cast(uint)(start>>32);
+			p = MapViewOfFileEx(hFileMap, dwDesiredAccess, hi, cast(uint)start, len, address);
+			if (!p) errNo();
+		} else version (unix_mm) {
+			p = mmap(address, len, prot, flags, fd, cast(off_t)start);
+			if (p == MAP_FAILED) errNo();
+		}
+		data = p[0 .. len];
+		this.start = start;
+	}
+
+	// ensure a given position is mapped
+	private void ensureMapped(ulong i) 
+	{
+		debug (MMFILE) printf("MmFile.ensureMapped(%lld)\n", i);
+		if (!mapped(i)) {
+			unmap();
+			if (window == 0) {
+				map(0,cast(size_t)size);
+			} else {
+				ulong block = i/window;
+				if (block == 0)
+					map(0,2*window);
+				else 
+					map(window*(block-1),3*window);
+			}
+		}
+	}
+
+	// ensure a given range is mapped
+	private void ensureMapped(ulong i, ulong j) 
+	{
+		debug (MMFILE) printf("MmFile.ensureMapped(%lld, %lld)\n", i, j);
+		if (!mapped(i) || !mapped(j-1)) {
+			unmap();
+			if (window == 0) {
+				map(0,cast(size_t)size);
+			} else {
+				ulong iblock = i/window;
+				ulong jblock = (j-1)/window;
+				if (iblock == 0) {
+					map(0,cast(size_t)(window*(jblock+2)));
+				} else {
+					map(window*(iblock-1),cast(size_t)(window*(jblock-iblock+3)));
+				}
+			}
+		}
+	}
+
+	private:
+	char[] filename;
+	void[] data;
+	ulong  start;
+	size_t window;
+	ulong  size;
+	Mode   mMode;
+	void*  address;
+
+	version (Win32)
+	{
+		HANDLE hFile = INVALID_HANDLE_VALUE;
+		HANDLE hFileMap = null;
+		uint dwDesiredAccess;
+	}
+	else version (unix_mm)
+	{
+		int fd;
+		int prot;
+		int flags;
+		int fmode;
+	}
+	else static if (! Have_MMFile)
+	{
+	}
+	else
+	{
+		static assert(0);
+	}
+
+	// Report error, where errno gives the error number
+	void errNo()
+	{
+		version (Win32)
+		{
+			throw new FileException(filename, GetLastError());
+		}
+		else version (Unix)
+		{
+			throw new FileException(filename, getErrno());
+		}
+		else static if (! Have_MMFile)
+		{
+			throw new FileException(filename, "MMFile unsupported");
+		}
+		else
+		{
+			static assert(0);
+		}
+	}
+}
+
+unittest {
+    static if (Have_MMFile)
+    {
+	const size_t K = 1024;
+	size_t win = 64*K; // assume the page size is 64K
+	version(Win32) {
+		/+ these aren't defined in std.c.windows.windows so let's use the default
+         SYSTEM_INFO sysinfo;
+         GetSystemInfo(&sysinfo);
+         win = sysinfo.dwAllocationGranularity;
+		+/
+	} else version (Unix) {
+		// getpagesize() is not defined in the unix D headers so use the guess
+	}
+	MmFile mf = new MmFile("testing.txt",MmFile.Mode.ReadWriteNew,100*K,null,win);
+	ubyte[] str = cast(ubyte[])"1234567890";
+	ubyte[] data = cast(ubyte[])mf[0 .. 10];
+	data[] = str[];
+	assert( mf[0 .. 10] == str );
+	data = cast(ubyte[])mf[50 .. 60];
+	data[] = str[];
+	assert( mf[50 .. 60] == str );
+	ubyte[] data2 = cast(ubyte[])mf[20*K .. 60*K];
+	assert( data2.length == 40*K );
+	assert( data2[length-1] == 0 );
+	mf[100*K-1] = cast(ubyte)'b';
+	data2 = cast(ubyte[])mf[21*K .. 100*K];
+	assert( data2.length == 79*K );
+	assert( data2[length-1] == 'b' );
+	delete mf;
+	std.file.remove("testing.txt");
+    }
+}
--- a/lphobos/std/moduleinit.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/std/moduleinit.d	Mon Aug 04 19:28:49 2008 +0200
@@ -51,16 +51,12 @@
     debug printf("_moduleCtor()\n");
 	int len = 0;
 
-    ModuleInfo* mrbegin = cast(ModuleInfo*)_d_get_moduleinfo_array();
-    assert(mrbegin !is null);
-
-    ModuleInfo* mr;
-	for (mr = mrbegin; *mr !is null; ++mr)
+	for (auto mr = _Dmodule_ref; mr; mr=mr.next)
 	    len++;
 	_moduleinfo_array = new ModuleInfo[len];
 	len = 0;
-	for (mr = mrbegin; *mr !is null; ++mr)
-	{   _moduleinfo_array[len] = *mr;
+	for (auto mr = _Dmodule_ref; mr; mr=mr.next)
+	{   _moduleinfo_array[len] = mr.mod;
 	    len++;
 	}
 
@@ -97,16 +93,18 @@
 	debug printf("\tmodule[%d] = '%p'\n", i, m);
 	if (!m)
 	    continue;
-	debug printf("\tmodule[%d] = '%.*s'\n", i, m.name);
+	debug printf("\tmodule[%d] = '%.*s'\n", i, m.name.length, m.name.ptr);
 	if (m.flags & MIctordone)
 	    continue;
-	debug printf("\tmodule[%d] = '%.*s', m = x%x\n", i, m.name, m);
+	debug printf("\tmodule[%d] = '%.*s', m = 0x%x\n", i, m.name.length, m.name.ptr, m);
 
 	if (m.ctor || m.dtor)
 	{
 	    if (m.flags & MIctorstart)
 	    {	if (skip || m.flags & MIstandalone)
 		    continue;
+		debug printf("\tmodule[%d] = '%.*s', cyclic dependency!\n", i, m.name.length, m.name.ptr);
+		int x = 0; x /= x;
 		throw new ModuleCtorError(m);
 	    }
 
@@ -160,7 +158,7 @@
 
 extern (C) void _moduleUnitTests()
 {
-    debug printf("_moduleUnitTests()\n");
+    debug printf("_moduleUnitTests() %i\n", _moduleinfo_array.length);
     for (uint i = 0; i < _moduleinfo_array.length; i++)
     {
 	ModuleInfo m = _moduleinfo_array[i];
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/outbuffer.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,368 @@
+// outbuffer.d
+
+/**
+ * Boilerplate:
+ *	$(std_boilerplate.html)
+ * Macros:
+ *	WIKI = Phobos/StdOutbuffer
+ * Copyright:
+ *	Copyright (c) 2001-2005 by Digital Mars
+ *	All Rights Reserved
+ *	www.digitalmars.com
+ */
+
+
+// Written by Walter Bright
+
+/* NOTE: This file has been patched from the original DMD distribution to
+   work with the GDC compiler.
+
+   Modified by David Friedman, September 2004
+*/
+
+module std.outbuffer;
+
+private
+{
+    import std.string;
+    import std.gc;
+    import std.c.stdio;
+    import std.c.stdlib;
+    import std.c.stdarg;
+}
+
+/*********************************************
+ * OutBuffer provides a way to build up an array of bytes out
+ * of raw data. It is useful for things like preparing an
+ * array of bytes to write out to a file.
+ * OutBuffer's byte order is the format native to the computer.
+ * To control the byte order (endianness), use a class derived
+ * from OutBuffer.
+ */
+
+class OutBuffer
+{
+    ubyte data[];
+    size_t offset;
+
+    invariant
+    {
+	//printf("this = %p, offset = %x, data.length = %u\n", this, offset, data.length);
+	assert(offset <= data.length);
+	assert(data.length <= std.gc.capacity(data.ptr));
+    }
+
+    this()
+    {
+	//printf("in OutBuffer constructor\n");
+    }
+
+    /*********************************
+     * Convert to array of bytes.
+     */
+
+    ubyte[] toBytes() { return data[0 .. offset]; }
+
+    /***********************************
+     * Preallocate nbytes more to the size of the internal buffer.
+     *
+     * This is a
+     * speed optimization, a good guess at the maximum size of the resulting
+     * buffer will improve performance by eliminating reallocations and copying.
+     */
+
+
+    void reserve(size_t nbytes)
+	in
+	{
+	    assert(offset + nbytes >= offset);
+	}
+	out
+	{
+	    assert(offset + nbytes <= data.length);
+	    assert(data.length <= std.gc.capacity(data.ptr));
+	}
+	body
+	{
+	    if (data.length < offset + nbytes)
+	    {
+		//std.c.stdio.printf("OutBuffer.reserve: ptr = %p, length = %d, offset = %d, nbytes = %d, capacity = %d\n", data.ptr, data.length, offset, nbytes, std.gc.capacity(data.ptr));
+		data.length = (offset + nbytes) * 2;
+		//std.c.stdio.printf("OutBuffer.reserve: ptr = %p, length = %d, capacity = %d\n", data.ptr, data.length, std.gc.capacity(data.ptr));
+		std.gc.hasPointers(data.ptr);
+	    }
+	}
+
+    /*************************************
+     * Append data to the internal buffer.
+     */
+
+    void write(ubyte[] bytes)
+	{
+	    reserve(bytes.length);
+	    data[offset .. offset + bytes.length] = bytes;
+	    offset += bytes.length;
+	}
+
+    void write(ubyte b)		/// ditto
+	{
+	    reserve(ubyte.sizeof);
+	    this.data[offset] = b;
+	    offset += ubyte.sizeof;
+	}
+
+    void write(byte b) { write(cast(ubyte)b); }		/// ditto
+    void write(char c) { write(cast(ubyte)c); }		/// ditto
+
+    void write(ushort w)		/// ditto
+    {
+	reserve(ushort.sizeof);
+	*cast(ushort *)&data[offset] = w;
+	offset += ushort.sizeof;
+    }
+
+    void write(short s) { write(cast(ushort)s); }		/// ditto
+
+    void write(wchar c)		/// ditto
+    {
+	reserve(wchar.sizeof);
+	*cast(wchar *)&data[offset] = c;
+	offset += wchar.sizeof;
+    }
+
+    void write(uint w)		/// ditto
+    {
+	reserve(uint.sizeof);
+	*cast(uint *)&data[offset] = w;
+	offset += uint.sizeof;
+    }
+
+    void write(int i) { write(cast(uint)i); }		/// ditto
+
+    void write(ulong l)		/// ditto
+    {
+	reserve(ulong.sizeof);
+	*cast(ulong *)&data[offset] = l;
+	offset += ulong.sizeof;
+    }
+
+    void write(long l) { write(cast(ulong)l); }		/// ditto
+
+    void write(float f)		/// ditto
+    {
+	reserve(float.sizeof);
+	*cast(float *)&data[offset] = f;
+	offset += float.sizeof;
+    }
+
+    void write(double f)		/// ditto
+    {
+	reserve(double.sizeof);
+	*cast(double *)&data[offset] = f;
+	offset += double.sizeof;
+    }
+
+    void write(real f)		/// ditto
+    {
+	reserve(real.sizeof);
+	*cast(real *)&data[offset] = f;
+	offset += real.sizeof;
+    }
+
+    void write(char[] s)		/// ditto
+    {
+	write(cast(ubyte[])s);
+    }
+
+    void write(OutBuffer buf)		/// ditto
+    {
+	write(buf.toBytes());
+    }
+
+    /****************************************
+     * Append nbytes of 0 to the internal buffer.
+     */
+
+    void fill0(uint nbytes)
+    {
+	reserve(nbytes);
+	data[offset .. offset + nbytes] = 0;
+	offset += nbytes;
+    }
+
+    /**********************************
+     * 0-fill to align on power of 2 boundary.
+     */
+
+    void alignSize(size_t alignsize)
+    in
+    {
+	assert(alignsize && (alignsize & (alignsize - 1)) == 0);
+    }
+    out
+    {
+	assert((offset & (alignsize - 1)) == 0);
+    }
+    body
+    {   size_t nbytes;
+
+	nbytes = offset & (alignsize - 1);
+	if (nbytes)
+	    fill0(alignsize - nbytes);
+    }
+
+    /****************************************
+     * Optimize common special case alignSize(2)
+     */
+
+    void align2()
+    {
+	if (offset & 1)
+	    write(cast(byte)0);
+    }
+
+    /****************************************
+     * Optimize common special case alignSize(4)
+     */
+
+    void align4()
+    {
+	if (offset & 3)
+	{   size_t nbytes = (4 - offset) & 3;
+	    fill0(nbytes);
+	}
+    }
+
+    /**************************************
+     * Convert internal buffer to array of chars.
+     */
+
+    char[] toString()
+    {
+	//printf("OutBuffer.toString()\n");
+	return cast(char[])data[0 .. offset];
+    }
+
+    /*****************************************
+     * Append output of C's vprintf() to internal buffer.
+     */
+
+    void vprintf(char[] format, va_list args)
+    {
+	char[128] buffer;
+	char* p;
+	char* f;
+	uint psize;
+	int count;
+	va_list args_copy;
+
+	f = toStringz(format);
+	p = buffer.ptr;
+	psize = buffer.length;
+	for (;;)
+	{
+	    va_copy(args_copy, args);
+	    version(Win32)
+	    {
+		count = _vsnprintf(p,psize,f,args_copy);
+		if (count != -1)
+		    break;
+		psize *= 2;
+		p = cast(char *) alloca(psize);	// buffer too small, try again with larger size
+	    }
+	    else version(GNU) {
+		count = vsnprintf(p,psize,f,args_copy);
+		if (count == -1)
+		    psize *= 2;
+		else if (count >= psize)
+		    psize = count + 1;
+		else
+		    break;
+		p = cast(char *) alloca(psize);	// buffer too small, try again with larger size
+	    }
+	    else version(linux)
+	    {
+		count = vsnprintf(p,psize,f,args_copy);
+		if (count == -1)
+		    psize *= 2;
+		else if (count >= psize)
+		    psize = count + 1;
+		else
+		    break;
+		/+
+		if (p != buffer)
+		    c.stdlib.free(p);
+		p = (char *) c.stdlib.malloc(psize);	// buffer too small, try again with larger size
+		+/
+		p = cast(char *) alloca(psize);	// buffer too small, try again with larger size
+	    }
+	}
+	write(p[0 .. count]);
+	/+
+	version (linux)
+	{
+	    if (p != buffer)
+		c.stdlib.free(p);
+	}
+	+/
+    }
+
+    /*****************************************
+     * Append output of C's printf() to internal buffer.
+     */
+
+    void printf(char[] format, ...)
+    {
+	version (GNU)
+	{
+	    vprintf(format, _argptr);
+	}
+	else
+	{
+	    va_list ap;
+	    ap = cast(va_list)&format;
+	    ap += format.sizeof;
+	    vprintf(format, ap);
+	}
+    }
+
+    /*****************************************
+     * At offset index into buffer, create nbytes of space by shifting upwards
+     * all data past index.
+     */
+
+    void spread(size_t index, size_t nbytes)
+	in
+	{
+	    assert(index <= offset);
+	}
+	body
+	{
+	    reserve(nbytes);
+
+	    // This is an overlapping copy - should use memmove()
+	    for (size_t i = offset; i > index; )
+	    {
+		--i;
+		data[i + nbytes] = data[i];
+	    }
+	    offset += nbytes;
+	}
+}
+
+unittest
+{
+    //printf("Starting OutBuffer test\n");
+
+    OutBuffer buf = new OutBuffer();
+
+    //printf("buf = %p\n", buf);
+    //printf("buf.offset = %x\n", buf.offset);
+    assert(buf.offset == 0);
+    buf.write("hello");
+    buf.write(cast(byte)0x20);
+    buf.write("world");
+    buf.printf(" %d", 6);
+    //printf("buf = '%.*s'\n", buf.toString());
+    assert(cmp(buf.toString(), "hello world 6") == 0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/path.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,1252 @@
+
+/**
+ * Macros:
+ *	WIKI = Phobos/StdPath
+ * Copyright:
+ *	Placed into public domain.
+ *	www.digitalmars.com
+ *
+ * Grzegorz Adam Hankiewicz added some documentation.
+ *
+ * This module is used to parse file names. All the operations
+ * work only on strings; they don't perform any input/output
+ * operations. This means that if a path contains a directory name
+ * with a dot, functions like getExt() will work with it just as
+ * if it was a file. To differentiate these cases,
+ * use the std.file module first (i.e. std.file.isDir()).
+ */
+
+/* NOTE: This file has been patched from the original DMD distribution to
+   work with the GDC compiler.
+
+   Modified by David Friedman, March 2006
+*/
+
+module std.path;
+
+//debug=path;		// uncomment to turn on debugging printf's
+//private import std.stdio;
+
+import std.string;
+
+version(Unix)
+{
+    import std.c.stdlib;
+    version(linux) import std.c.linux.linux;
+    else import std.c.unix.unix;
+    import std.outofmemory;
+    /*extern(C) struct passwd
+    {
+        char* pw_name, pw_passwd; uint pw_uid, pw_gid; char* pw_gecos, pw_dir, pw_shell;
+    }*/
+}
+
+version(Windows)
+{
+
+    /** String used to separate directory names in a path. Under
+     *  Windows this is a backslash, under Linux a slash. */
+    const char[1] sep = "\\";
+    /** Alternate version of sep[] used in Windows (a slash). Under
+     *  Linux this is empty. */
+    const char[1] altsep = "/";
+    /** Path separator string. A semi colon under Windows, a colon
+     *  under Linux. */
+    const char[1] pathsep = ";";
+    /** String used to separate lines, \r\n under Windows and \n
+     * under Linux. */
+    const char[2] linesep = "\r\n"; /// String used to separate lines.
+    const char[1] curdir = ".";	 /// String representing the current directory.
+    const char[2] pardir = ".."; /// String representing the parent directory.
+}
+else version(Unix)
+{
+    /** String used to separate directory names in a path. Under
+     *  Windows this is a backslash, under Linux a slash. */
+    const char[1] sep = "/";
+    /** Alternate version of sep[] used in Windows (a slash). Under
+     *  Linux this is empty. */
+    const char[0] altsep;
+    /** Path separator string. A semi colon under Windows, a colon
+     *  under Linux. */
+    const char[1] pathsep = ":";
+    /** String used to separate lines, \r\n under Windows and \n
+     * under Linux. */
+    const char[1] linesep = "\n";
+    const char[1] curdir = ".";	 /// String representing the current directory.
+    const char[2] pardir = ".."; /// String representing the parent directory.
+}
+else
+{
+    static assert(0);
+}
+
+/*****************************
+ * Compare file names.
+ * Returns:
+ *	<table border=1 cellpadding=4 cellspacing=0>
+ *	<tr> <td> &lt; 0	<td> filename1 &lt; filename2
+ *	<tr> <td> = 0	<td> filename1 == filename2
+ *	<tr> <td> &gt; 0	<td> filename1 &gt; filename2
+ *	</table>
+ */
+
+version (Windows) alias std.string.icmp fcmp;
+
+version (Unix) alias std.string.cmp fcmp;
+
+/**************************
+ * Extracts the extension from a filename or path.
+ *
+ * This function will search fullname from the end until the
+ * first dot, path separator or first character of fullname is
+ * reached. Under Windows, the drive letter separator (<i>colon</i>)
+ * also terminates the search.
+ *
+ * Returns: If a dot was found, characters to its right are
+ * returned. If a path separator was found, or fullname didn't
+ * contain any dots or path separators, returns null.
+ *
+ * Throws: Nothing.
+ *
+ * Examples:
+ * -----
+ * version(Win32)
+ * {
+ *     getExt(r"d:\path\foo.bat") // "bat"
+ *     getExt(r"d:\path.two\bar") // null
+ * }
+ * version(linux)
+ * {
+ *     getExt(r"/home/user.name/bar.")  // ""
+ *     getExt(r"d:\\path.two\\bar")     // "two\\bar"
+ *     getExt(r"/home/user/.resource")  // "resource"
+ * }
+ * -----
+ */
+
+char[] getExt(char[] fullname)
+{
+    size_t i;
+
+    i = fullname.length;
+    while (i > 0)
+    {
+	if (fullname[i - 1] == '.')
+	    return fullname[i .. fullname.length];
+	i--;
+	version(Win32)
+	{
+	    if (fullname[i] == ':' || fullname[i] == '\\')
+		break;
+	}
+	else version(Unix)
+	{
+	    if (fullname[i] == '/')
+		break;
+	}
+    }
+    return null;
+}
+
+unittest
+{
+    debug(path) printf("path.getExt.unittest\n");
+    int i;
+    char[] result;
+
+    version (Win32)
+	result = getExt("d:\\path\\foo.bat");
+    version (Unix)
+	result = getExt("/path/foo.bat");
+    i = cmp(result, "bat");
+    assert(i == 0);
+
+    version (Win32)
+	result = getExt("d:\\path\\foo.");
+    version (Unix)
+	result = getExt("d/path/foo.");
+    i = cmp(result, "");
+    assert(i == 0);
+
+    version (Win32)
+	result = getExt("d:\\path\\foo");
+    version (Unix)
+	result = getExt("d/path/foo");
+    i = cmp(result, "");
+    assert(i == 0);
+
+    version (Win32)
+	result = getExt("d:\\path.bar\\foo");
+    version (Unix)
+	result = getExt("/path.bar/foo");
+
+    i = cmp(result, "");
+    assert(i == 0);
+
+    result = getExt("foo");
+    i = cmp(result, "");
+    assert(i == 0);
+}
+
+/**************************
+ * Returns the extensionless version of a filename or path.
+ *
+ * This function will search fullname from the end until the
+ * first dot, path separator or first character of fullname is
+ * reached. Under Windows, the drive letter separator (<i>colon</i>)
+ * also terminates the search.
+ *
+ * Returns: If a dot was found, characters to its left are
+ * returned. If a path separator was found, or fullname didn't
+ * contain any dots or path separators, returns null.
+ *
+ * Throws: Nothing.
+ *
+ * Examples:
+ * -----
+ * version(Win32)
+ * {
+ *     getName(r"d:\path\foo.bat") => "d:\path\foo"
+ *     getName(r"d:\path.two\bar") => null
+ * }
+ * version(linux)
+ * {
+ *     getName("/home/user.name/bar.")  => "/home/user.name/bar"
+ *     getName(r"d:\path.two\bar") => "d:\path"
+ *     getName("/home/user/.resource") => "/home/user/"
+ * }
+ * -----
+ */
+
+char[] getName(char[] fullname)
+{
+    size_t i;
+
+    i = fullname.length;
+    while (i > 0)
+    {
+	if (fullname[i - 1] == '.')
+	    return fullname[0 .. i - 1];
+	i--;
+	version(Win32)
+	{
+	    if (fullname[i] == ':' || fullname[i] == '\\')
+		break;
+	}
+	version(Unix)
+	{
+	    if (fullname[i] == '/')
+		break;
+	}
+    }
+    return null;
+}
+
+unittest
+{
+    debug(path) printf("path.getName.unittest\n");
+    int i;
+    char[] result;
+
+    result = getName("foo.bar");
+    i = cmp(result, "foo");
+    assert(i == 0);
+
+    result = getName("d:\\path.two\\bar");
+    version (Win32)
+	i = cmp(result, null);
+    version (linux)
+	i = cmp(result, "d:\\path");
+    assert(i == 0);
+}
+
+/**************************
+ * Extracts the base name of a path.
+ *
+ * This function will search fullname from the end until the
+ * first path separator or first character of fullname is
+ * reached. Under Windows, the drive letter separator (<i>colon</i>)
+ * also terminates the search.
+ *
+ * Returns: If a path separator was found, all the characters to its
+ * right are returned. Otherwise, fullname is returned.
+ *
+ * Throws: Nothing.
+ *
+ * Examples:
+ * -----
+ * version(Win32)
+ * {
+ *     getBaseName(r"d:\path\foo.bat") => "foo.bat"
+ * }
+ * version(linux)
+ * {
+ *     getBaseName("/home/user.name/bar.")  => "bar."
+ * }
+ * -----
+ */
+
+char[] getBaseName(char[] fullname)
+    out (result)
+    {
+	assert(result.length <= fullname.length);
+    }
+    body
+    {
+	size_t i;
+
+	for (i = fullname.length; i > 0; i--)
+	{
+	    version(Win32)
+	    {
+		if (fullname[i - 1] == ':' || fullname[i - 1] == '\\')
+		    break;
+	    }
+	    else version(Unix)
+	    {
+		if (fullname[i - 1] == '/')
+		    break;
+	    }
+	}
+	return fullname[i .. fullname.length];
+    }
+
+unittest
+{
+    debug(path) printf("path.getBaseName.unittest\n");
+    int i;
+    char[] result;
+
+    version (Windows)
+	result = getBaseName("d:\\path\\foo.bat");
+    version (Unix)
+	result = getBaseName("/path/foo.bat");
+    //printf("result = '%.*s'\n", result);
+    i = cmp(result, "foo.bat");
+    assert(i == 0);
+
+    version (Windows)
+	result = getBaseName("a\\b");
+    version (Unix)
+	result = getBaseName("a/b");
+    i = cmp(result, "b");
+    assert(i == 0);
+}
+
+
+/**************************
+ * Extracts the directory part of a path.
+ *
+ * This function will search fullname from the end until the
+ * first path separator or first character of fullname is
+ * reached. Under Windows, the drive letter separator (<i>colon</i>)
+ * also terminates the search.
+ *
+ * Returns: If a path separator was found, all the characters to its
+ * left are returned. Otherwise, fullname is returned.
+ *
+ * Under Windows, the found path separator will be included in the
+ * returned string if it is preceeded by a colon.
+ *
+ * Throws: Nothing.
+ *
+ * Examples:
+ * -----
+ * version(Win32)
+ * {
+ *     getDirName(r"d:\path\foo.bat") => "d:\path"
+ *     getDirName(getDirName(r"d:\path\foo.bat")) => "d:\"
+ * }
+ * version(linux)
+ * {
+ *     getDirName("/home/user")  => "/home"
+ *     getDirName(getDirName("/home/user"))  => ""
+ * }
+ * -----
+ */
+
+char[] getDirName(char[] fullname)
+    out (result)
+    {
+	assert(result.length <= fullname.length);
+    }
+    body
+    {
+	size_t i;
+
+	for (i = fullname.length; i > 0; i--)
+	{
+	    version(Win32)
+	    {
+		if (fullname[i - 1] == ':')
+		    break;
+		if (fullname[i - 1] == '\\')
+		{   i--;
+		    break;
+		}
+	    }
+	    else version(Unix)
+	    {
+		if (fullname[i - 1] == '/')
+		{   i--;
+		    break;
+		}
+	    }
+	}
+	return fullname[0 .. i];
+    }
+
+
+/********************************
+ * Extracts the drive letter of a path.
+ *
+ * This function will search fullname for a colon from the beginning.
+ *
+ * Returns: If a colon is found, all the characters to its left
+ * plus the colon are returned.  Otherwise, null is returned.
+ *
+ * Under Linux, this function always returns null immediately.
+ *
+ * Throws: Nothing.
+ *
+ * Examples:
+ * -----
+ * getDrive(r"d:\path\foo.bat") => "d:"
+ * -----
+ */
+
+char[] getDrive(char[] fullname)
+    out (result)
+    {
+	assert(result.length <= fullname.length);
+    }
+    body
+    {
+	version(Win32)
+	{
+	    size_t i;
+
+	    for (i = 0; i < fullname.length; i++)
+	    {
+		if (fullname[i] == ':')
+		    return fullname[0 .. i + 1];
+	    }
+	    return null;
+	}
+	else version(Unix)
+	{
+	    return null;
+	}
+    }
+
+/****************************
+ * Appends a default extension to a filename.
+ *
+ * This function first searches filename for an extension and
+ * appends ext if there is none. ext should not have any leading
+ * dots, one will be inserted between filename and ext if filename
+ * doesn't already end with one.
+ *
+ * Returns: filename if it contains an extension, otherwise filename
+ * + ext.
+ *
+ * Throws: Nothing.
+ *
+ * Examples:
+ * -----
+ * defaultExt("foo.txt", "raw") => "foo.txt"
+ * defaultExt("foo.", "raw") => "foo.raw"
+ * defaultExt("bar", "raw") => "bar.raw"
+ * -----
+ */
+
+char[] defaultExt(char[] filename, char[] ext)
+{
+    char[] existing;
+
+    existing = getExt(filename);
+    if (existing.length == 0)
+    {
+	// Check for filename ending in '.'
+	if (filename.length && filename[filename.length - 1] == '.')
+	    filename ~= ext;
+	else
+	    filename = filename ~ "." ~ ext;
+    }
+    return filename;
+}
+
+
+/****************************
+ * Adds or replaces an extension to a filename.
+ *
+ * This function first searches filename for an extension and
+ * replaces it with ext if found.  If there is no extension, ext
+ * will be appended. ext should not have any leading dots, one will
+ * be inserted between filename and ext if filename doesn't already
+ * end with one.
+ *
+ * Returns: filename + ext if filename is extensionless. Otherwise
+ * strips filename's extension off, appends ext and returns the
+ * result.
+ *
+ * Throws: Nothing.
+ *
+ * Examples:
+ * -----
+ * addExt("foo.txt", "raw") => "foo.raw"
+ * addExt("foo.", "raw") => "foo.raw"
+ * addExt("bar", "raw") => "bar.raw"
+ * -----
+ */
+
+char[] addExt(char[] filename, char[] ext)
+{
+    char[] existing;
+
+    existing = getExt(filename);
+    if (existing.length == 0)
+    {
+	// Check for filename ending in '.'
+	if (filename.length && filename[filename.length - 1] == '.')
+	    filename ~= ext;
+	else
+	    filename = filename ~ "." ~ ext;
+    }
+    else
+    {
+	filename = filename[0 .. filename.length - existing.length] ~ ext;
+    }
+    return filename;
+}
+
+
+/*************************************
+ * Checks if path is absolute.
+ *
+ * Returns: non-zero if the path starts from the root directory (Linux) or
+ * drive letter and root directory (Windows),
+ * zero otherwise.
+ *
+ * Throws: Nothing.
+ *
+ * Examples:
+ * -----
+ * version(Win32)
+ * {
+ *     isabs(r"relative\path") => 0
+ *     isabs(r"\relative\path") => 0
+ *     isabs(r"d:\absolute") => 1
+ * }
+ * version(linux)
+ * {
+ *     isabs("/home/user") => 1
+ *     isabs("foo") => 0
+ * }
+ * -----
+ */
+
+int isabs(char[] path)
+{
+    char[] d = getDrive(path);
+
+    version (Windows)
+    {
+	return d.length && d.length < path.length && path[d.length] == sep[0];
+    }
+    else
+	return d.length < path.length && path[d.length] == sep[0];
+}
+
+unittest
+{
+    debug(path) printf("path.isabs.unittest\n");
+
+    version (Windows)
+    {
+	assert(isabs(r"relative\path") == 0);
+	assert(isabs(r"\relative\path") == 0);
+	assert(isabs(r"d:\absolute") == 1);
+    }
+    version (linux)
+    {
+	assert(isabs("/home/user") == 1);
+	assert(isabs("foo") == 0);
+    }
+}
+
+/*************************************
+ * Joins two path components.
+ *
+ * If p1 doesn't have a trailing path separator, one will be appended
+ * to it before concatting p2.
+ *
+ * Returns: p1 ~ p2. However, if p2 is an absolute path, only p2
+ * will be returned.
+ *
+ * Throws: Nothing.
+ *
+ * Examples:
+ * -----
+ * version(Win32)
+ * {
+ *     join(r"c:\foo", "bar") => "c:\foo\bar"
+ *     join("foo", r"d:\bar") => "d:\bar"
+ * }
+ * version(linux)
+ * {
+ *     join("/foo/", "bar") => "/foo/bar"
+ *     join("/foo", "/bar") => "/bar"
+ * }
+ * -----
+ */
+
+char[] join(char[] p1, char[] p2)
+{
+    if (!p2.length)
+	return p1;
+    if (!p1.length)
+	return p2;
+
+    char[] p;
+    char[] d1;
+
+    version(Win32)
+    {
+	if (getDrive(p2))
+	{
+	    p = p2;
+	}
+	else
+	{
+	    d1 = getDrive(p1);
+	    if (p1.length == d1.length)
+	    {
+		p = p1 ~ p2;
+	    }
+	    else if (p2[0] == '\\')
+	    {
+		if (d1.length == 0)
+		    p = p2;
+		else if (p1[p1.length - 1] == '\\')
+		    p = p1 ~ p2[1 .. p2.length];
+		else
+		    p = p1 ~ p2;
+	    }
+	    else if (p1[p1.length - 1] == '\\')
+	    {
+		p = p1 ~ p2;
+	    }
+	    else
+	    {
+		p = p1 ~ sep ~ p2;
+	    }
+	}
+    }
+    else version(Unix)
+    {
+	if (p2[0] == sep[0])
+	{
+	    p = p2;
+	}
+	else if (p1[p1.length - 1] == sep[0])
+	{
+	    p = p1 ~ p2;
+	}
+	else
+	{
+	    p = p1 ~ sep ~ p2;
+	}
+    }
+    return p;
+}
+
+unittest
+{
+    debug(path) printf("path.join.unittest\n");
+
+    char[] p;
+    int i;
+
+    p = join("foo", "bar");
+    version (Win32)
+	i = cmp(p, "foo\\bar");
+    version (Unix)
+	i = cmp(p, "foo/bar");
+    assert(i == 0);
+
+    version (Win32)
+    {	p = join("foo\\", "bar");
+	i = cmp(p, "foo\\bar");
+    }
+    version (Unix)
+    {	p = join("foo/", "bar");
+	i = cmp(p, "foo/bar");
+    }
+    assert(i == 0);
+
+    version (Win32)
+    {	p = join("foo", "\\bar");
+	i = cmp(p, "\\bar");
+    }
+    version (Unix)
+    {	p = join("foo", "/bar");
+	i = cmp(p, "/bar");
+    }
+    assert(i == 0);
+
+    version (Win32)
+    {	p = join("foo\\", "\\bar");
+	i = cmp(p, "\\bar");
+    }
+    version (Unix)
+    {	p = join("foo/", "/bar");
+	i = cmp(p, "/bar");
+    }
+    assert(i == 0);
+
+    version(Win32)
+    {
+	p = join("d:", "bar");
+	i = cmp(p, "d:bar");
+	assert(i == 0);
+
+	p = join("d:\\", "bar");
+	i = cmp(p, "d:\\bar");
+	assert(i == 0);
+
+	p = join("d:\\", "\\bar");
+	i = cmp(p, "d:\\bar");
+	assert(i == 0);
+
+	p = join("d:\\foo", "bar");
+	i = cmp(p, "d:\\foo\\bar");
+	assert(i == 0);
+
+	p = join("d:", "\\bar");
+	i = cmp(p, "d:\\bar");
+	assert(i == 0);
+
+	p = join("foo", "d:");
+	i = cmp(p, "d:");
+	assert(i == 0);
+
+	p = join("foo", "d:\\");
+	i = cmp(p, "d:\\");
+	assert(i == 0);
+
+	p = join("foo", "d:\\bar");
+	i = cmp(p, "d:\\bar");
+	assert(i == 0);
+    }
+}
+
+
+/*********************************
+ * Matches filename characters.
+ *
+ * Under Windows, the comparison is done ignoring case. Under Linux
+ * an exact match is performed.
+ *
+ * Returns: non zero if c1 matches c2, zero otherwise.
+ *
+ * Throws: Nothing.
+ *
+ * Examples:
+ * -----
+ * version(Win32)
+ * {
+ *     fncharmatch('a', 'b') => 0
+ *     fncharmatch('A', 'a') => 1
+ * }
+ * version(linux)
+ * {
+ *     fncharmatch('a', 'b') => 0
+ *     fncharmatch('A', 'a') => 0
+ * }
+ * -----
+ */
+
+int fncharmatch(dchar c1, dchar c2)
+{
+    version (Win32)
+    {
+	if (c1 != c2)
+	{
+	    if ('A' <= c1 && c1 <= 'Z')
+		c1 += cast(char)'a' - 'A';
+	    if ('A' <= c2 && c2 <= 'Z')
+		c2 += cast(char)'a' - 'A';
+	    return c1 == c2;
+	}
+	return true;
+    }
+    else version (Unix)
+    {
+	return c1 == c2;
+    }
+    /* this is filesystem-dependent, figure out the filesystem?
+    else version (GNU)
+    {
+	// %% figure out filesystem?
+	return c1 == c2;
+    }
+    */
+}
+
+/************************************
+ * Matches a pattern against a filename.
+ *
+ * Some characters of pattern have special a meaning (they are
+ * <i>meta-characters</i>) and <b>can't</b> be escaped. These are:
+ * <p><table>
+ * <tr><td><b>*</b></td>
+ *     <td>Matches 0 or more instances of any character.</td></tr>
+ * <tr><td><b>?</b></td>
+ *     <td>Matches exactly one instances of any character.</td></tr>
+ * <tr><td><b>[</b><i>chars</i><b>]</b></td>
+ *     <td>Matches one instance of any character that appears
+ *     between the brackets.</td></tr>
+ * <tr><td><b>[!</b><i>chars</i><b>]</b></td>
+ *     <td>Matches one instance of any character that does not appear
+ *     between the brackets after the exclamation mark.</td></tr>
+ * </table><p>
+ * Internally individual character comparisons are done calling
+ * fncharmatch(), so its rules apply here too. Note that path
+ * separators and dots don't stop a meta-character from matching
+ * further portions of the filename.
+ *
+ * Returns: non zero if pattern matches filename, zero otherwise.
+ *
+ * See_Also: fncharmatch().
+ *
+ * Throws: Nothing.
+ *
+ * Examples:
+ * -----
+ * version(Win32)
+ * {
+ *     fnmatch("foo.bar", "*") => 1
+ *     fnmatch(r"foo/foo\bar", "f*b*r") => 1
+ *     fnmatch("foo.bar", "f?bar") => 0
+ *     fnmatch("Goo.bar", "[fg]???bar") => 1
+ *     fnmatch(r"d:\foo\bar", "d*foo?bar") => 1
+ * }
+ * version(linux)
+ * {
+ *     fnmatch("Go*.bar", "[fg]???bar") => 0
+ *     fnmatch("/foo*home/bar", "?foo*bar") => 1
+ *     fnmatch("foobar", "foo?bar") => 1
+ * }
+ * -----
+ */
+
+int fnmatch(char[] filename, char[] pattern)
+    in
+    {
+	// Verify that pattern[] is valid
+	size_t i;
+	int inbracket = false;
+
+	for (i = 0; i < pattern.length; i++)
+	{
+	    switch (pattern[i])
+	    {
+		case '[':
+		    assert(!inbracket);
+		    inbracket = true;
+		    break;
+
+		case ']':
+		    assert(inbracket);
+		    inbracket = false;
+		    break;
+
+		default:
+		    break;
+	    }
+	}
+    }
+    body
+    {
+	size_t pi;
+	size_t ni;
+	char pc;
+	char nc;
+	size_t j;
+	int not;
+	int anymatch;
+
+	ni = 0;
+	for (pi = 0; pi < pattern.length; pi++)
+	{
+	    pc = pattern[pi];
+	    switch (pc)
+	    {
+		case '*':
+		    if (pi + 1 == pattern.length)
+			goto match;
+		    for (j = ni; j < filename.length; j++)
+		    {
+			if (fnmatch(filename[j .. filename.length], pattern[pi + 1 .. pattern.length]))
+			    goto match;
+		    }
+		    goto nomatch;
+
+		case '?':
+		    if (ni == filename.length)
+			goto nomatch;
+		    ni++;
+		    break;
+
+		case '[':
+		    if (ni == filename.length)
+			goto nomatch;
+		    nc = filename[ni];
+		    ni++;
+		    not = 0;
+		    pi++;
+		    if (pattern[pi] == '!')
+		    {	not = 1;
+			pi++;
+		    }
+		    anymatch = 0;
+		    while (1)
+		    {
+			pc = pattern[pi];
+			if (pc == ']')
+			    break;
+			if (!anymatch && fncharmatch(nc, pc))
+			    anymatch = 1;
+			pi++;
+		    }
+		    if (!(anymatch ^ not))
+			goto nomatch;
+		    break;
+
+		default:
+		    if (ni == filename.length)
+			goto nomatch;
+		    nc = filename[ni];
+		    if (!fncharmatch(pc, nc))
+			goto nomatch;
+		    ni++;
+		    break;
+	    }
+	}
+	if (ni < filename.length)
+	    goto nomatch;
+
+    match:
+	return true;
+
+    nomatch:
+	return false;
+    }
+
+unittest
+{
+    debug(path) printf("path.fnmatch.unittest\n");
+
+    version (Win32)
+	assert(fnmatch("foo", "Foo"));
+    version (Unix)
+	assert(!fnmatch("foo", "Foo"));
+    assert(fnmatch("foo", "*"));
+    assert(fnmatch("foo.bar", "*"));
+    assert(fnmatch("foo.bar", "*.*"));
+    assert(fnmatch("foo.bar", "foo*"));
+    assert(fnmatch("foo.bar", "f*bar"));
+    assert(fnmatch("foo.bar", "f*b*r"));
+    assert(fnmatch("foo.bar", "f???bar"));
+    assert(fnmatch("foo.bar", "[fg]???bar"));
+    assert(fnmatch("foo.bar", "[!gh]*bar"));
+
+    assert(!fnmatch("foo", "bar"));
+    assert(!fnmatch("foo", "*.*"));
+    assert(!fnmatch("foo.bar", "f*baz"));
+    assert(!fnmatch("foo.bar", "f*b*x"));
+    assert(!fnmatch("foo.bar", "[gh]???bar"));
+    assert(!fnmatch("foo.bar", "[!fg]*bar"));
+    assert(!fnmatch("foo.bar", "[fg]???baz"));
+}
+
+/**
+ * Performs tilde expansion in paths.
+ *
+ * There are two ways of using tilde expansion in a path. One
+ * involves using the tilde alone or followed by a path separator. In
+ * this case, the tilde will be expanded with the value of the
+ * environment variable <i>HOME</i>.  The second way is putting
+ * a username after the tilde (i.e. <tt>~john/Mail</tt>). Here,
+ * the username will be searched for in the user database
+ * (i.e. <tt>/etc/passwd</tt> on Unix systems) and will expand to
+ * whatever path is stored there.  The username is considered the
+ * string after the tilde ending at the first instance of a path
+ * separator.
+ *
+ * Note that using the <i>~user</i> syntax may give different
+ * values from just <i>~</i> if the environment variable doesn't
+ * match the value stored in the user database.
+ *
+ * When the environment variable version is used, the path won't
+ * be modified if the environment variable doesn't exist or it
+ * is empty. When the database version is used, the path won't be
+ * modified if the user doesn't exist in the database or there is
+ * not enough memory to perform the query.
+ *
+ * Returns: inputPath with the tilde expanded, or just inputPath
+ * if it could not be expanded.
+ * For Windows, expandTilde() merely returns its argument inputPath.
+ *
+ * Throws: std.outofmemory.OutOfMemoryException if there is not enough
+ * memory to perform
+ * the database lookup for the <i>~user</i> syntax.
+ *
+ * Examples:
+ * -----
+ * import std.path;
+ *
+ * void process_file(char[] filename)
+ * {
+ *     char[] path = expandTilde(filename);
+ *     ...
+ * }
+ * -----
+ *
+ * -----
+ * import std.path;
+ *
+ * const char[] RESOURCE_DIR_TEMPLATE = "~/.applicationrc";
+ * char[] RESOURCE_DIR;    // This gets expanded in main().
+ *
+ * int main(char[][] args)
+ * {
+ *     RESOURCE_DIR = expandTilde(RESOURCE_DIR_TEMPLATE);
+ *     ...
+ * }
+ * -----
+ * Version: Available since v0.143.
+ * Authors: Grzegorz Adam Hankiewicz, Thomas Kühne.
+ */
+
+char[] expandTilde(char[] inputPath)
+{
+    version(Unix)
+    {
+	static assert(sep.length == 1);
+
+        // Return early if there is no tilde in path.
+        if (inputPath.length < 1 || inputPath[0] != '~')
+	    return inputPath;
+
+	if (inputPath.length == 1 || inputPath[1] == sep[0])
+	    return expandFromEnvironment(inputPath);
+        else
+	    return expandFromDatabase(inputPath);
+    }
+    else version(Windows)
+    {
+	// Put here real windows implementation.
+	return inputPath;
+    }
+    else
+    {
+	static assert(0); // Guard. Implement on other platforms.
+    }
+}
+
+
+unittest
+{
+    debug(path) printf("path.expandTilde.unittest\n");
+
+    version (Unix)
+    {
+	// Retrieve the current home variable.
+	char* c_home = getenv("HOME");
+
+	// Testing when there is no environment variable.
+	unsetenv("HOME");
+	assert(expandTilde("~/") == "~/");
+	assert(expandTilde("~") == "~");
+
+	// Testing when an environment variable is set.
+	int ret = setenv("HOME", "dmd/test\0", 1);
+	assert(ret == 0);
+	assert(expandTilde("~/") == "dmd/test/");
+	assert(expandTilde("~") == "dmd/test");
+
+	// The same, but with a variable ending in a slash.
+	ret = setenv("HOME", "dmd/test/\0", 1);
+	assert(ret == 0);
+	assert(expandTilde("~/") == "dmd/test/");
+	assert(expandTilde("~") == "dmd/test");
+
+	// Recover original HOME variable before continuing.
+	if (c_home)
+	    setenv("HOME", c_home, 1);
+	else
+	    unsetenv("HOME");
+
+	// Test user expansion for root. Are there unices without /root?
+	/*
+	assert(expandTilde("~root") == "/root");
+	assert(expandTilde("~root/") == "/root/");
+	*/
+	assert(expandTilde("~Idontexist/hey") == "~Idontexist/hey");
+    }
+}
+
+version (Unix)
+{
+
+/**
+ * Replaces the tilde from path with the environment variable HOME.
+ */
+private char[] expandFromEnvironment(char[] path)
+{
+    assert(path.length >= 1);
+    assert(path[0] == '~');
+    
+    // Get HOME and use that to replace the tilde.
+    char* home = getenv("HOME");
+    if (home == null)
+        return path;
+
+    return combineCPathWithDPath(home, path, 1);
+}
+
+
+/**
+ * Joins a path from a C string to the remainder of path.
+ *
+ * The last path separator from c_path is discarded. The result
+ * is joined to path[char_pos .. length] if char_pos is smaller
+ * than length, otherwise path is not appended to c_path.
+ */
+private char[] combineCPathWithDPath(char* c_path, char[] path, int char_pos)
+{
+    assert(c_path != null);
+    assert(path.length > 0);
+    assert(char_pos >= 0);
+
+    // Search end of C string
+    size_t end = std.string.strlen(c_path);
+
+    // Remove trailing path separator, if any
+    if (end && c_path[end - 1] == sep[0])
+	end--;
+
+    // Create our own copy, as lifetime of c_path is undocumented
+    char[] cp = c_path[0 .. end].dup;
+
+    // Do we append something from path?
+    if (char_pos < path.length)
+	cp ~= path[char_pos .. length];
+
+    return cp;
+}
+
+
+/**
+ * Replaces the tilde from path with the path from the user database.
+ */
+private string expandFromDatabase(string path)
+{
+    assert(path.length > 2 || (path.length == 2 && path[1] != sep[0]));
+    assert(path[0] == '~');
+
+    // Extract username, searching for path separator.
+    string username;
+    ptrdiff_t last_char = find(path, sep[0]);
+
+    if (last_char == -1)
+    {
+        username = path[1 .. length] ~ '\0';
+	last_char = username.length + 1;
+    }
+    else
+    {
+        username = path[1 .. last_char] ~ '\0';
+    }
+    assert(last_char > 1);
+    
+    version (GNU_Unix_Have_getpwnam_r)
+    {
+    
+    // Reserve C memory for the getpwnam_r() function.
+    passwd result;
+    int extra_memory_size = 5 * 1024;
+    void* extra_memory;
+
+    while (1)
+    {
+	extra_memory = std.c.stdlib.malloc(extra_memory_size);
+	if (extra_memory == null)
+	    goto Lerror;
+
+	// Obtain info from database.
+	passwd *verify;
+	std.c.stdlib.setErrno(0);
+	if (getpwnam_r(username.ptr, &result, cast(char*) extra_memory, extra_memory_size,
+		&verify) == 0)
+	{
+	    // Failure if verify doesn't point at result.
+	    if (verify != &result)
+		// username is not found, so return path[]
+		goto Lnotfound;
+	    break;
+	}
+
+	switch (std.c.stdlib.getErrno()) {
+	case 0:
+	case ENOENT:
+	case ESRCH:
+	case EBADF:
+	case EPERM:
+	    goto Lnotfound;
+	case ERANGE:
+	    break;
+	default:
+	    // not just out of memory: EMFILE, ENFILE too
+	    goto Lerror;
+	}
+
+	// extra_memory isn't large enough
+	std.c.stdlib.free(extra_memory);
+	extra_memory_size *= 2;
+    }
+
+    path = combineCPathWithDPath(result.pw_dir, path, last_char);
+
+Lnotfound:
+    std.c.stdlib.free(extra_memory);
+    return path;
+
+Lerror:
+    // Errors are going to be caused by running out of memory
+    if (extra_memory)
+	std.c.stdlib.free(extra_memory);
+    _d_OutOfMemory();
+    return null;
+
+    }
+    else
+    {
+	passwd * result;
+
+	/* This does not guarantee another thread will not
+	   use getpwnam at the same time */
+	synchronized {
+	    result = getpwnam(username.ptr);
+	}
+	
+	if (result)
+	    path = combineCPathWithDPath(result.pw_dir, path, last_char);
+	return path;
+    }
+}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/process.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,293 @@
+
+/*
+ *  Copyright (C) 2003-2004 by Digital Mars, www.digitalmars.com
+ *  Written by Matthew Wilson and Walter Bright
+ *
+ *  Incorporating idea (for execvpe() on Linux) from Russ Lewis
+ *
+ *  Updated: 21st August 2004
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, subject to the following restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+/* NOTE: This file has been patched from the original DMD distribution to
+   work with the GDC compiler.
+
+   Modified by David Friedman, October 2004
+*/
+
+/**
+ * Macros:
+ *	WIKI=Phobos/StdProcess
+ */
+
+
+module std.process;
+
+private import std.c.stdlib;
+private import std.c.string;
+private import std.string;
+private import std.c.process;
+
+/**
+ * Execute command in a _command shell.
+ *
+ * Returns: exit status of command
+ */
+
+int system(char[] command)
+{
+    return std.c.process.system(toStringz(command));
+}
+
+private void toAStringz(char[][] a, char**az)
+{
+    foreach(char[] s; a)
+    {
+        *az++ = toStringz(s);
+    }
+    *az = null;
+}
+
+
+/* ========================================================== */
+
+//version (Windows)
+//{
+//    int spawnvp(int mode, char[] pathname, char[][] argv)
+//    {
+//	char** argv_ = cast(char**)alloca((char*).sizeof * (1 + argv.length));
+//
+//	toAStringz(argv, argv_);
+//
+//	return std.c.process.spawnvp(mode, toStringz(pathname), argv_);
+//    }
+//}
+
+// Incorporating idea (for spawnvp() on linux) from Dave Fladebo
+
+alias std.c.process._P_WAIT P_WAIT;
+alias std.c.process._P_NOWAIT P_NOWAIT;
+
+int spawnvp(int mode, char[] pathname, char[][] argv)
+{
+    char** argv_ = cast(char**)alloca((char*).sizeof * (1 + argv.length));
+
+    toAStringz(argv, argv_);
+
+    version(Unix)
+    {
+        return _spawnvp(mode, toStringz(pathname), argv_);
+    }
+    else
+    {
+        return std.c.process.spawnvp(mode, toStringz(pathname), argv_);
+    }
+}
+
+version(Unix)
+{
+version(linux) import std.c.linux.linux;
+else import std.c.unix.unix;
+int _spawnvp(int mode, char *pathname, char **argv)
+{
+    int retval = 0;
+    pid_t pid = fork();
+
+    if(!pid)
+    {   // child
+        std.c.process.execvp(pathname, argv);
+        goto Lerror;
+    }
+    else if(pid > 0)
+    {   // parent
+        if(mode == _P_NOWAIT)
+        {
+            retval = pid; // caller waits
+        }
+        else
+        {
+            while(1)
+            {
+                int status;
+                pid_t wpid = waitpid(pid, &status, 0);
+                if(exited(status))
+                {
+                    retval = exitstatus(status);
+                    break;
+                }
+                else if(signaled(status))
+                {
+                    retval = -termsig(status);
+                    break;
+                }
+                else if(stopped(status)) // ptrace support
+                    continue;
+                else
+                    goto Lerror;
+            }
+        }
+
+        return retval;
+    }
+
+Lerror:
+    retval = getErrno;
+    throw new Exception(
+        "Cannot spawn " ~ toString(pathname) ~ "; "
+                      ~ toString(strerror(retval))
+                      ~ " [errno " ~ toString(retval) ~ "]");
+}   // _spawnvp
+private
+{
+bool stopped(int status)    { return cast(bool)((status & 0xff) == 0x7f); }
+bool signaled(int status)   { return cast(bool)((cast(char)((status & 0x7f) + 1) >> 1) > 0); }
+int  termsig(int status)    { return status & 0x7f; }
+bool exited(int status)     { return cast(bool)((status & 0x7f) == 0); }
+int  exitstatus(int status) { return (status & 0xff00) >> 8; }
+}   // private
+}   // version(linux)
+
+/* ========================================================== */
+
+/**
+ * Execute program specified by pathname, passing it the arguments (argv)
+ * and the environment (envp), returning the exit status.
+ * The 'p' versions of exec search the PATH environment variable
+ * setting for the program.
+ */
+
+int execv(char[] pathname, char[][] argv)
+{
+    char** argv_ = cast(char**)alloca((char*).sizeof * (1 + argv.length));
+
+    toAStringz(argv, argv_);
+
+    return std.c.process.execv(toStringz(pathname), argv_);
+}
+
+/** ditto */
+int execve(char[] pathname, char[][] argv, char[][] envp)
+{
+    char** argv_ = cast(char**)alloca((char*).sizeof * (1 + argv.length));
+    char** envp_ = cast(char**)alloca((char*).sizeof * (1 + envp.length));
+
+    toAStringz(argv, argv_);
+    toAStringz(envp, envp_);
+
+    return std.c.process.execve(toStringz(pathname), argv_, envp_);
+}
+
+/** ditto */
+int execvp(char[] pathname, char[][] argv)
+{
+    char** argv_ = cast(char**)alloca((char*).sizeof * (1 + argv.length));
+
+    toAStringz(argv, argv_);
+
+    return std.c.process.execvp(toStringz(pathname), argv_);
+}
+
+/** ditto */
+int execvpe(char[] pathname, char[][] argv, char[][] envp)
+{
+version (GNU_Need_execvpe)
+{
+    // Is pathname rooted?
+    if(pathname[0] == '/')
+    {
+        // Yes, so just call execve()
+        return execve(pathname, argv, envp);
+    }
+    else
+    {
+        // No, so must traverse PATHs, looking for first match
+        char[][]    envPaths    =   std.string.split(std.string.toString(std.c.stdlib.getenv("PATH")), ":");
+        int         iRet        =   0;
+
+        // Note: if any call to execve() succeeds, this process will cease 
+        // execution, so there's no need to check the execve() result through
+        // the loop.
+
+        foreach(char[] pathDir; envPaths)
+        {
+            char[]  composite   =   pathDir ~ "/" ~ pathname;
+
+            iRet = execve(composite, argv, envp);
+        }
+        if(0 != iRet)
+        {
+            iRet = execve(pathname, argv, envp);
+        }
+
+        return iRet;
+    }
+}
+else version(Windows)
+{
+    char** argv_ = cast(char**)alloca((char*).sizeof * (1 + argv.length));
+    char** envp_ = cast(char**)alloca((char*).sizeof * (1 + envp.length));
+
+    toAStringz(argv, argv_);
+    toAStringz(envp, envp_);
+
+    return std.c.process.execvpe(toStringz(pathname), argv_, envp_);
+}
+else
+{
+    throw new Exception("Not supported on this platform.");
+} // version
+}
+
+/* ////////////////////////////////////////////////////////////////////////// */
+
+version(MainTest)
+{
+    int main(char[][] args)
+    {
+        if(args.length < 2)
+        {
+            printf("Must supply executable (and optional arguments)\n");
+
+            return 1;
+        }
+        else
+        {
+            char[][]    dummy_env;
+            
+            dummy_env ~= "VAL0=value";
+            dummy_env ~= "VAL1=value";
+
+/+
+            foreach(char[] arg; args)
+            {
+                printf("%.*s\n", arg);
+            }
++/
+
+//          int i = execv(args[1], args[1 .. args.length]);
+//          int i = execvp(args[1], args[1 .. args.length]);
+            int i = execvpe(args[1], args[1 .. args.length], dummy_env);
+
+            printf("exec??() has returned! Error code: %d; errno: %d\n", i, /* std.c.stdlib.getErrno() */-1);
+
+            return 0;
+        }
+    }
+}
+
+/* ////////////////////////////////////////////////////////////////////////// */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/random.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,161 @@
+/**
+ * Macros:
+ *	WIKI = Phobos/StdRandom
+ */
+
+// random.d
+// www.digitalmars.com
+
+/* NOTE: This file has been patched from the original DMD distribution to
+   work with the GDC compiler.
+
+   Modified by David Friedman, September 2007
+*/
+
+module std.random;
+
+// Segments of the code in this file Copyright (c) 1997 by Rick Booth
+// From "Inner Loops" by Rick Booth, Addison-Wesley
+
+version (Win32)
+{
+    extern(Windows) int QueryPerformanceCounter(ulong *count);
+}
+else version (Unix)
+{
+    version(linux) import std.c.linux.linux;
+    else private import std.c.unix.unix;
+}
+
+/* ===================== Random ========================= */
+
+// BUG: not multithreaded
+
+private uint seed;		// starting seed
+private uint index;		// ith random number
+
+/**
+ * The random number generator is seeded at program startup with a random value.
+ This ensures that each program generates a different sequence of random
+ numbers. To generate a repeatable sequence, use rand_seed() to start the
+ sequence. seed and index start it, and each successive value increments index.
+ This means that the $(I n)th random number of the sequence can be directly
+ generated
+ by passing index + $(I n) to rand_seed().
+
+ Note: This is more random, but slower, than C's rand() function.
+ To use C's rand() instead, import std.c.stdlib.
+ */
+
+void rand_seed(uint seed, uint index)
+{
+     .seed = seed;
+     .index = index;
+}
+
+/**
+ * Get the next random number in sequence.
+ * BUGS: shares a global single state, not multithreaded
+ */
+
+uint rand()
+{
+    static uint xormix1[20] =
+    [
+                0xbaa96887, 0x1e17d32c, 0x03bcdc3c, 0x0f33d1b2,
+                0x76a6491d, 0xc570d85d, 0xe382b1e3, 0x78db4362,
+                0x7439a9d4, 0x9cea8ac5, 0x89537c5c, 0x2588f55d,
+                0x415b5e1d, 0x216e3d95, 0x85c662e7, 0x5e8ab368,
+                0x3ea5cc8c, 0xd26a0f74, 0xf3a9222b, 0x48aad7e4
+    ];
+
+    static uint xormix2[20] =
+    [
+                0x4b0f3b58, 0xe874f0c3, 0x6955c5a6, 0x55a7ca46,
+                0x4d9a9d86, 0xfe28a195, 0xb1ca7865, 0x6b235751,
+                0x9a997a61, 0xaa6e95c8, 0xaaa98ee1, 0x5af9154c,
+                0xfc8e2263, 0x390f5e8c, 0x58ffd802, 0xac0a5eba,
+                0xac4874f6, 0xa9df0913, 0x86be4c74, 0xed2c123b
+    ];
+
+    uint hiword, loword, hihold, temp, itmpl, itmph, i;
+
+    loword = seed;
+    hiword = index++;
+    for (i = 0; i < 4; i++)		// loop limit can be 2..20, we choose 4
+    {
+        hihold  = hiword;                           // save hiword for later
+        temp    = hihold ^  xormix1[i];             // mix up bits of hiword
+        itmpl   = temp   &  0xffff;                 // decompose to hi & lo
+        itmph   = temp   >> 16;                     // 16-bit words
+        temp    = itmpl * itmpl + ~(itmph * itmph); // do a multiplicative mix
+        temp    = (temp >> 16) | (temp << 16);      // swap hi and lo halves
+        hiword  = loword ^ ((temp ^ xormix2[i]) + itmpl * itmph); //loword mix
+        loword  = hihold;                           // old hiword is loword
+    }
+    return hiword;
+}
+
+static this()
+{
+    ulong s;
+
+    version(Win32)
+    {
+	QueryPerformanceCounter(&s);
+    }
+    else version(Unix)
+    {
+	// time.h
+	// sys/time.h
+
+	timeval tv;
+
+	if (gettimeofday(&tv, null))
+	{   // Some error happened - try time() instead
+	    s = time(null);
+	}
+	else
+	{
+	    s = cast(ulong)((cast(long)tv.tv_sec << 32) + tv.tv_usec);
+	}
+    }
+    else version(NoSystem)
+    {
+	// nothing
+    }
+    else
+	static assert(false);
+    rand_seed(cast(uint) s, cast(uint)(s >> 32));
+}
+
+
+unittest
+{
+    static uint results[10] =
+    [
+	0x8c0188cb,
+	0xb161200c,
+	0xfc904ac5,
+	0x2702e049,
+	0x9705a923,
+	0x1c139d89,
+	0x346b6d1f,
+	0xf8c33e32,
+	0xdb9fef76,
+	0xa97fcb3f
+    ];
+    int i;
+    uint seedsave = seed;
+    uint indexsave = index;
+
+    rand_seed(1234, 5678);
+    for (i = 0; i < 10; i++)
+    {	uint r = rand();
+	//printf("0x%x,\n", rand());
+	assert(r == results[i]);
+    }
+
+    seed = seedsave;
+    index = indexsave;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/regexp.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,3208 @@
+
+// Regular Expressions
+
+/*
+ *  Copyright (C) 2000-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, subject to the following restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/* NOTE: This file has been patched from the original DMD distribution to
+   work with the GDC compiler.
+
+   Modified by David Friedman, September 2004
+*/
+
+/**********************************************
+ * $(LINK2 http://www.digitalmars.com/ctg/regular.html, Regular expressions)
+ * are a powerful method of string pattern matching.
+ * The regular expression
+ * language used is the same as that commonly used, however, some of the very
+ * advanced forms may behave slightly differently.
+ *
+ * std.regexp is designed to work only with valid UTF strings as input.
+ * To validate untrusted input, use std.utf.validate().
+ *
+ * In the following guide, $(I pattern)[] refers to a
+ * $(LINK2 http://www.digitalmars.com/ctg/regular.html, regular expression).
+ * The $(I attributes)[] refers to
+	a string controlling the interpretation
+	of the regular expression.
+	It consists of a sequence of one or more
+	of the following characters:
+
+	<table border=1 cellspacing=0 cellpadding=5>
+	<caption>Attribute Characters</caption>
+	$(TR $(TH Attribute) $(TH Action))
+	<tr>
+	$(TD $(B g))
+	$(TD global; repeat over the whole input string)
+	</tr>
+	<tr>
+	$(TD $(B i))
+	$(TD case insensitive)
+	</tr>
+	<tr>
+	$(TD $(B m))
+	$(TD treat as multiple lines separated by newlines)
+	</tr>
+	</table>
+ *
+ * The $(I format)[] string has the formatting characters:
+ *
+ *	<table border=1 cellspacing=0 cellpadding=5>
+	<caption>Formatting Characters</caption>
+	$(TR $(TH Format) $(TH Replaced With))
+	$(TR
+	$(TD $(B $$))	$(TD $)
+	)
+	$(TR
+	$(TD $(B $&))	$(TD The matched substring.)
+	)
+	$(TR
+	$(TD $(B $`))	$(TD The portion of string that precedes the matched substring.)
+	)
+	$(TR
+	$(TD $(B $'))	$(TD The portion of string that follows the matched substring.)
+	)
+	$(TR
+	$(TD $(B $(DOLLAR))$(I n)) $(TD The $(I n)th capture, where $(I n)
+			is a single digit 1-9
+			and $$(I n) is not followed by a decimal digit.)
+	)
+	$(TR
+	$(TD $(B $(DOLLAR))$(I nn)) $(TD The $(I nn)th capture, where $(I nn)
+			is a two-digit decimal
+			number 01-99.
+			If $(I nn)th capture is undefined or more than the number
+			of parenthesized subexpressions, use the empty
+			string instead.)
+	)
+	</table>
+
+ *	Any other $ are left as is.
+ *
+ * References:
+ *	$(LINK2 http://en.wikipedia.org/wiki/Regular_expressions, Wikipedia)
+ * Macros:
+ *	WIKI = StdRegexp
+ *	DOLLAR = $
+ */
+
+/*
+	Escape sequences:
+
+	\nnn starts out a 1, 2 or 3 digit octal sequence,
+	where n is an octal digit. If nnn is larger than
+	0377, then the 3rd digit is not part of the sequence
+	and is not consumed.
+	For maximal portability, use exactly 3 digits.
+
+	\xXX starts out a 1 or 2 digit hex sequence. X
+	is a hex character. If the first character after the \x
+	is not a hex character, the value of the sequence is 'x'
+	and the XX are not consumed.
+	For maximal portability, use exactly 2 digits.
+
+	\uUUUU is a unicode sequence. There are exactly
+	4 hex characters after the \u, if any are not, then
+	the value of the sequence is 'u', and the UUUU are not
+	consumed.
+
+	Character classes:
+
+	[a-b], where a is greater than b, will produce
+	an error.
+
+	References:
+
+	http://www.unicode.org/unicode/reports/tr18/
+ */
+
+module std.regexp;
+
+//debug = regexp;		// uncomment to turn on debugging printf's
+
+private
+{
+    import std.c.stdio;
+    import std.c.stdlib;
+    import std.c.string;
+    import std.stdio;
+    import std.string;
+    import std.ctype;
+    import std.outbuffer;
+    import std.bitarray;
+    import std.utf;
+    import std.intrinsic;
+}
+
+/** Regular expression to extract an _email address */
+const char[] email =
+    r"[a-zA-Z]([.]?([[a-zA-Z0-9_]-]+)*)?@([[a-zA-Z0-9_]\-_]+\.)+[a-zA-Z]{2,6}";
+
+/** Regular expression to extract a _url */
+const char[] url = r"(([h|H][t|T]|[f|F])[t|T][p|P]([s|S]?)\:\/\/|~/|/)?([\w]+:\w+@)?(([a-zA-Z]{1}([\w\-]+\.)+([\w]{2,5}))(:[\d]{1,5})?)?((/?\w+/)+|/?)(\w+\.[\w]{3,4})?([,]\w+)*((\?\w+=\w+)?(&\w+=\w+)*([,]\w*)*)?";
+
+/************************************
+ * One of these gets thrown on compilation errors
+ */
+
+class RegExpException : Exception
+{
+    this(char[] msg)
+    {
+	super(msg);
+    }
+}
+
+struct regmatch_t
+{
+    int rm_so;			// index of start of match
+    int rm_eo;			// index past end of match
+}
+
+private alias char rchar;	// so we can make a wchar version
+
+/******************************************************
+ * Search string for matches with regular expression
+ * pattern with attributes.
+ * Replace each match with string generated from format.
+ * Params:
+ *	string = String to search.
+ *	pattern = Regular expression pattern.
+ *	format = Replacement string format.
+ *	attributes = Regular expression attributes.
+ * Returns:
+ *	the resulting string
+ * Example:
+ *	Replace the letters 'a' with the letters 'ZZ'.
+ * ---
+ * s = "Strap a rocket engine on a chicken."
+ * sub(s, "a", "ZZ")        // result: StrZZp a rocket engine on a chicken.
+ * sub(s, "a", "ZZ", "g")   // result: StrZZp ZZ rocket engine on ZZ chicken.
+ * ---
+ *	The replacement format can reference the matches using
+ *	the $&amp;, $$, $', $`, $0 .. $99 notation:
+ * ---
+ * sub(s, "[ar]", "[$&]", "g") // result: St[r][a]p [a] [r]ocket engine on [a] chi
+ * ---
+ */
+
+char[] sub(char[] string, char[] pattern, char[] format, char[] attributes = null)
+{
+    auto r = new RegExp(pattern, attributes);
+    auto result = r.replace(string, format);
+    delete r;
+    return result;
+}
+
+unittest
+{
+    debug(regexp) printf("regexp.sub.unittest\n");
+
+    char[] r = sub("hello", "ll", "ss");
+    assert(r == "hesso");
+}
+
+/*******************************************************
+ * Search string for matches with regular expression
+ * pattern with attributes.
+ * Pass each match to delegate dg.
+ * Replace each match with the return value from dg.
+ * Params:
+ *	string = String to search.
+ *	pattern = Regular expression pattern.
+ *	dg = Delegate
+ *	attributes = Regular expression attributes.
+ * Returns: the resulting string.
+ * Example:
+ * Capitalize the letters 'a' and 'r':
+ * ---
+ * s = "Strap a rocket engine on a chicken.";
+ * sub(s, "[ar]",
+ *    delegate char[] (RegExp m)
+ *    {
+ *         return toupper(m.match(0));
+ *    },
+ *    "g");    // result: StRAp A Rocket engine on A chicken.
+ * ---
+ */
+
+char[] sub(char[] string, char[] pattern, char[] delegate(RegExp) dg, char[] attributes = null)
+{
+    auto r = new RegExp(pattern, attributes);
+    rchar[] result;
+    int lastindex;
+    int offset;
+
+    result = string;
+    lastindex = 0;
+    offset = 0;
+    while (r.test(string, lastindex))
+    {
+	int so = r.pmatch[0].rm_so;
+	int eo = r.pmatch[0].rm_eo;
+
+	rchar[] replacement = dg(r);
+
+	// Optimize by using std.string.replace if possible - Dave Fladebo
+	rchar[] slice = result[offset + so .. offset + eo];
+	if (r.attributes & RegExp.REA.global &&		// global, so replace all
+	    !(r.attributes & RegExp.REA.ignoreCase) &&	// not ignoring case
+	    !(r.attributes & RegExp.REA.multiline) &&	// not multiline
+	    pattern == slice)				// simple pattern (exact match, no special characters) 
+	{
+	    debug(regexp)
+		printf("pattern: %.*s, slice: %.*s, replacement: %.*s\n",
+		    cast(int) pattern.length, pattern.ptr,
+		    cast(int) (eo-so), result.ptr + offset,
+		    cast(int) replacement.length, replacement.ptr);
+	    result = std.string.replace(result,slice,replacement);
+	    break;
+	}
+
+	result = replaceSlice(result, result[offset + so .. offset + eo], replacement);
+
+	if (r.attributes & RegExp.REA.global)
+	{
+	    offset += replacement.length - (eo - so);
+
+	    if (lastindex == eo)
+		lastindex++;		// always consume some source
+	    else
+		lastindex = eo;
+	}
+	else
+	    break;
+    }
+    delete r;
+
+    return result;
+}
+
+unittest
+{
+    debug(regexp) printf("regexp.sub.unittest\n");
+
+    char[] foo(RegExp r) { return "ss"; }
+
+    char[] r = sub("hello", "ll", delegate char[](RegExp r) { return "ss"; });
+    assert(r == "hesso");
+
+    r = sub("hello", "l", delegate char[](RegExp r) { return "l"; }, "g");
+    assert(r == "hello");
+
+    auto s = sub("Strap a rocket engine on a chicken.",
+		 "[ar]",
+	         delegate char[] (RegExp m)
+	         {
+		    return std.string.toupper(m.match(0));
+	         },
+	         "g");
+    assert(s == "StRAp A Rocket engine on A chicken.");
+}
+
+
+/*************************************************
+ * Search string[] for first match with pattern[] with attributes[].
+ * Params:
+ *	string = String to search.
+ *	pattern = Regular expression pattern.
+ *	attributes = Regular expression attributes.
+ * Returns:
+ *	index into string[] of match if found, -1 if no match.
+ * Example:
+ * ---
+ * auto s = "abcabcabab";
+ * std.regexp.find(s, "b");    // match, returns 1
+ * std.regexp.find(s, "f");    // no match, returns -1
+ * ---
+ */
+
+int find(rchar[] string, char[] pattern, char[] attributes = null)
+{
+    int i = -1;
+
+    auto r = new RegExp(pattern, attributes);
+    if (r.test(string))
+    {
+	i = r.pmatch[0].rm_so;
+    }
+    delete r;
+    return i;
+}
+
+unittest
+{
+    debug(regexp) printf("regexp.find.unittest\n");
+
+    int i;
+    i = find("xabcy", "abc");
+    assert(i == 1);
+    i = find("cba", "abc");
+    assert(i == -1);
+}
+
+
+
+/*************************************************
+ * Search string[] for last match with pattern[] with attributes[].
+ * Params:
+ *	string = String to search.
+ *	pattern = Regular expression pattern.
+ *	attributes = Regular expression attributes.
+ * Returns:
+ *	index into string[] of match if found, -1 if no match.
+ * Example:
+ * ---
+ * auto s = "abcabcabab";
+ * std.regexp.find(s, "b");    // match, returns 9
+ * std.regexp.find(s, "f");    // no match, returns -1
+ * ---
+ */
+
+int rfind(rchar[] string, char[] pattern, char[] attributes = null)
+{
+    int i = -1;
+    int lastindex = 0;
+
+    auto r = new RegExp(pattern, attributes);
+    while (r.test(string, lastindex))
+    {   int eo = r.pmatch[0].rm_eo;
+	i = r.pmatch[0].rm_so;
+	if (lastindex == eo)
+	    lastindex++;		// always consume some source
+	else
+	    lastindex = eo;
+    }
+    delete r;
+    return i;
+}
+
+unittest
+{
+    int i;
+
+    debug(regexp) printf("regexp.rfind.unittest\n");
+    i = rfind("abcdefcdef", "c");
+    assert(i == 6);
+    i = rfind("abcdefcdef", "cd");
+    assert(i == 6);
+    i = rfind("abcdefcdef", "x");
+    assert(i == -1);
+    i = rfind("abcdefcdef", "xy");
+    assert(i == -1);
+    i = rfind("abcdefcdef", "");
+    assert(i == 10);
+}
+
+
+/********************************************
+ * Split string[] into an array of strings, using the regular
+ * expression pattern[] with attributes[] as the separator.
+ * Params:
+ *	string = String to search.
+ *	pattern = Regular expression pattern.
+ *	attributes = Regular expression attributes.
+ * Returns:
+ * 	array of slices into string[]
+ * Example:
+ * ---
+ * foreach (s; split("abcabcabab", "C.", "i"))
+ * {
+ *     writefln("s = '%s'", s);
+ * }
+ * // Prints:
+ * // s = 'ab'
+ * // s = 'b'
+ * // s = 'bab'
+ * ---
+ */
+
+char[][] split(char[] string, char[] pattern, char[] attributes = null)
+{
+    auto r = new RegExp(pattern, attributes);
+    auto result = r.split(string);
+    delete r;
+    return result;
+}
+
+unittest
+{
+    debug(regexp) printf("regexp.split.unittest()\n");
+    char[][] result;
+
+    result = split("ab", "a*");
+    assert(result.length == 2);
+    assert(result[0] == "");
+    assert(result[1] == "b");
+
+    foreach (i, s; split("abcabcabab", "C.", "i"))
+    {
+	writefln("s[%d] = '%s'", i, s);
+	if (i == 0) assert(s == "ab");
+	else if (i == 1) assert(s == "b");
+	else if (i == 2) assert(s == "bab");
+	else assert(0);
+    }
+}
+
+/****************************************************
+ * Search string[] for first match with pattern[] with attributes[].
+ * Params:
+ *	string = String to search.
+ *	pattern = Regular expression pattern.
+ *	attributes = Regular expression attributes.
+ * Returns:
+ *	corresponding RegExp if found, null if not.
+ * Example:
+ * ---
+ * import std.stdio;
+ * import std.regexp;
+ *
+ * void main()
+ * {
+ *     if (auto m = std.regexp.search("abcdef", "c"))
+ *     {
+ *         writefln("%s[%s]%s", m.pre, m.match(0), m.post);
+ *     }
+ * }
+ * // Prints:
+ * // ab[c]def
+ * ---
+ */
+
+RegExp search(char[] string, char[] pattern, char[] attributes = null)
+{
+    auto r = new RegExp(pattern, attributes);
+
+    if (r.test(string))
+    {
+    }
+    else
+    {	delete r;
+	r = null;
+    }
+    return r;
+}
+
+unittest
+{
+    debug(regexp) printf("regexp.string.unittest()\n");
+
+    if (auto m = std.regexp.search("abcdef", "c()"))
+    {
+	auto result = std.string.format("%s[%s]%s", m.pre, m.match(0), m.post);
+	assert(result == "ab[c]def");
+	assert(m.match(1) == null);
+	assert(m.match(2) == null);
+    }
+    else
+	assert(0);
+
+    if (auto n = std.regexp.search("abcdef", "g"))
+    {
+	assert(0);
+    }
+}
+
+
+/* ********************************* RegExp ******************************** */
+
+/*****************************
+ * RegExp is a class to handle regular expressions.
+ *
+ * It is the core foundation for adding powerful string pattern matching
+ * capabilities to programs like grep, text editors, awk, sed, etc.
+ */
+class RegExp
+{
+    /*****
+     * Construct a RegExp object. Compile pattern
+     * with <i>attributes</i> into
+     * an internal form for fast execution.
+     * Params:
+     *	pattern = regular expression
+     *  attributes = _attributes
+     * Throws: RegExpException if there are any compilation errors.
+     * Example:
+     *  Declare two variables and assign to them a RegExp object:
+     * ---
+     * auto r = new RegExp("pattern");
+     * auto s = new RegExp(r"p[1-5]\s*");
+     * ---
+     */
+    public this(rchar[] pattern, rchar[] attributes = null)
+    {
+	pmatch = (&gmatch)[0 .. 1];
+	compile(pattern, attributes);
+    }
+
+    /*****
+     * Generate instance of RegExp.
+     * Params:
+     *	pattern = regular expression
+     *  attributes = _attributes
+     * Throws: RegExpException if there are any compilation errors.
+     * Example:
+     *  Declare two variables and assign to them a RegExp object:
+     * ---
+     * auto r = RegExp("pattern");
+     * auto s = RegExp(r"p[1-5]\s*");
+     * ---
+     */
+    public static RegExp opCall(rchar[] pattern, rchar[] attributes = null)
+    {
+	return new RegExp(pattern, attributes);
+    }
+
+    unittest
+    {
+	debug(regexp) printf("regexp.opCall.unittest()\n");
+	auto r1 = RegExp("hello", "m");
+	char[] msg;
+	try
+	{
+	    auto r2 = RegExp("hello", "q");
+	    assert(0);
+	}
+	catch (RegExpException ree)
+	{
+	    msg = ree.toString();
+	    //writefln("message: %s", ree);
+	}
+	assert(msg == "unrecognized attribute");
+    }
+
+    /************************************
+     * Set up for start of foreach loop.
+     * Returns:
+     *	search() returns instance of RegExp set up to _search string[].
+     * Example:
+     * ---
+     * import std.stdio;
+     * import std.regexp;
+     *
+     * void main()
+     * {
+     *     foreach(m; RegExp("ab").search("abcabcabab"))
+     *     {
+     *         writefln("%s[%s]%s", m.pre, m.match(0), m.post);
+     *     }
+     * }
+     * // Prints:
+     * // [ab]cabcabab
+     * // abc[ab]cabab
+     * // abcabc[ab]ab
+     * // abcabcab[ab]
+     * ---
+     */
+
+    public RegExp search(rchar[] string)
+    {
+	input = string;
+	pmatch[0].rm_eo = 0;
+	return this;
+    }
+
+    /** ditto */
+    public int opApply(int delegate(inout RegExp) dg)
+    {
+	int result;
+	RegExp r = this;
+
+	while (test())
+	{
+	    result = dg(r);
+	    if (result)
+		break;
+	}
+
+	return result;
+    }
+
+    unittest
+    {
+	debug(regexp) printf("regexp.search.unittest()\n");
+
+	int i;
+	foreach(m; RegExp("ab").search("abcabcabab"))
+	{
+	    auto s = std.string.format("%s[%s]%s", m.pre, m.match(0), m.post);
+	    if (i == 0) assert(s == "[ab]cabcabab");
+	    else if (i == 1) assert(s == "abc[ab]cabab");
+	    else if (i == 2) assert(s == "abcabc[ab]ab");
+	    else if (i == 3) assert(s == "abcabcab[ab]");
+	    else assert(0);
+	    i++;
+	}
+    }
+
+    /******************
+     * Retrieve match n.
+     *
+     * n==0 means the matched substring, n>0 means the
+     * n'th parenthesized subexpression.
+     * if n is larger than the number of parenthesized subexpressions,
+     * null is returned.
+     */
+    public char[] match(size_t n)
+    {
+	if (n >= pmatch.length)
+	    return null;
+	else
+	{   size_t rm_so, rm_eo;
+	    rm_so = pmatch[n].rm_so;
+	    rm_eo = pmatch[n].rm_eo;
+	    if (rm_so == rm_eo)
+		return null;
+	    return input[rm_so .. rm_eo];
+	}
+    }
+
+    /*******************
+     * Return the slice of the input that precedes the matched substring.
+     */
+    public char[] pre()
+    {
+	return input[0 .. pmatch[0].rm_so];
+    }
+
+    /*******************
+     * Return the slice of the input that follows the matched substring.
+     */
+    public char[] post()
+    {
+	return input[pmatch[0].rm_eo .. $];
+    }
+
+    uint re_nsub;		// number of parenthesized subexpression matches
+    regmatch_t[] pmatch;	// array [re_nsub + 1]
+
+    rchar[] input;		// the string to search
+
+    // per instance:
+
+    rchar[] pattern;		// source text of the regular expression
+
+    rchar[] flags;		// source text of the attributes parameter
+
+    int errors;
+
+    uint attributes;
+
+    enum REA
+    {
+	global		= 1,	// has the g attribute
+	ignoreCase	= 2,	// has the i attribute
+	multiline	= 4,	// if treat as multiple lines separated
+				// by newlines, or as a single line
+	dotmatchlf	= 8,	// if . matches \n
+    }
+
+
+private:
+    size_t src;			// current source index in input[]
+    size_t src_start;		// starting index for match in input[]
+    size_t p;			// position of parser in pattern[]
+    regmatch_t gmatch;		// match for the entire regular expression
+				// (serves as storage for pmatch[0])
+
+    ubyte[] program;		// pattern[] compiled into regular expression program
+    OutBuffer buf;
+
+
+
+
+/******************************************/
+
+// Opcodes
+
+enum : ubyte
+{
+    REend,		// end of program
+    REchar,		// single character
+    REichar,		// single character, case insensitive
+    REdchar,		// single UCS character
+    REidchar,		// single wide character, case insensitive
+    REanychar,		// any character
+    REanystar,		// ".*"
+    REstring,		// string of characters
+    REistring,		// string of characters, case insensitive
+    REtestbit,		// any in bitmap, non-consuming
+    REbit,		// any in the bit map
+    REnotbit,		// any not in the bit map
+    RErange,		// any in the string
+    REnotrange,		// any not in the string
+    REor,		// a | b
+    REplus,		// 1 or more
+    REstar,		// 0 or more
+    REquest,		// 0 or 1
+    REnm,		// n..m
+    REnmq,		// n..m, non-greedy version
+    REbol,		// beginning of line
+    REeol,		// end of line
+    REparen,		// parenthesized subexpression
+    REgoto,		// goto offset
+
+    REwordboundary,
+    REnotwordboundary,
+    REdigit,
+    REnotdigit,
+    REspace,
+    REnotspace,
+    REword,
+    REnotword,
+    REbackref,
+};
+
+// BUG: should this include '$'?
+private int isword(dchar c) { return isalnum(c) || c == '_'; }
+
+private uint inf = ~0u;
+
+/* ********************************
+ * Throws RegExpException on error
+ */
+
+public void compile(rchar[] pattern, rchar[] attributes)
+{
+    //printf("RegExp.compile('%.*s', '%.*s')\n", pattern, attributes);
+
+    this.attributes = 0;
+    foreach (rchar c; attributes)
+    {   REA att;
+
+	switch (c)
+	{
+	    case 'g': att = REA.global;		break;
+	    case 'i': att = REA.ignoreCase;	break;
+	    case 'm': att = REA.multiline;	break;
+	    default:
+		error("unrecognized attribute");
+		return;
+	}
+	if (this.attributes & att)
+	{   error("redundant attribute");
+	    return;
+	}
+	this.attributes |= att;
+    }
+
+    input = null;
+
+    this.pattern = pattern;
+    this.flags = attributes;
+
+    uint oldre_nsub = re_nsub;
+    re_nsub = 0;
+    errors = 0;
+
+    buf = new OutBuffer();
+    buf.reserve(pattern.length * 8);
+    p = 0;
+    parseRegexp();
+    if (p < pattern.length)
+    {	error("unmatched ')'");
+    }
+    optimize();
+    program = buf.data;
+    buf.data = null;
+    delete buf;
+
+    if (re_nsub > oldre_nsub)
+    {
+	if (pmatch.ptr is &gmatch)
+	    pmatch = null;
+	pmatch.length = re_nsub + 1;
+    }
+    pmatch[0].rm_so = 0;
+    pmatch[0].rm_eo = 0;
+}
+
+/********************************************
+ * Split string[] into an array of strings, using the regular
+ * expression as the separator.
+ * Returns:
+ * 	array of slices into string[]
+ */
+
+public rchar[][] split(rchar[] string)
+{
+    debug(regexp) printf("regexp.split()\n");
+
+    rchar[][] result;
+
+    if (string.length)
+    {
+	int p = 0;
+	int q;
+	for (q = p; q != string.length;)
+	{
+	    if (test(string, q))
+	    {	int e;
+
+		q = pmatch[0].rm_so;
+		e = pmatch[0].rm_eo;
+		if (e != p)
+		{
+		    result ~= string[p .. q];
+		    for (int i = 1; i < pmatch.length; i++)
+		    {
+			int so = pmatch[i].rm_so;
+			int eo = pmatch[i].rm_eo;
+			if (so == eo)
+			{   so = 0;	// -1 gives array bounds error
+			    eo = 0;
+			}
+			result ~= string[so .. eo];
+		    }
+		    q = p = e;
+		    continue;
+		}
+	    }
+	    q++;
+	}
+	result ~= string[p .. string.length];
+    }
+    else if (!test(string))
+	result ~= string;
+    return result;
+}
+
+unittest
+{
+    debug(regexp) printf("regexp.split.unittest()\n");
+
+    auto r = new RegExp("a*?", null);
+    rchar[][] result;
+    rchar[] j;
+    int i;
+
+    result = r.split("ab");
+
+    assert(result.length == 2);
+    i = std.string.cmp(result[0], "a");
+    assert(i == 0);
+    i = std.string.cmp(result[1], "b");
+    assert(i == 0);
+
+    r = new RegExp("a*", null);
+    result = r.split("ab");
+    assert(result.length == 2);
+    i = std.string.cmp(result[0], "");
+    assert(i == 0);
+    i = std.string.cmp(result[1], "b");
+    assert(i == 0);
+
+    r = new RegExp("<(\\/)?([^<>]+)>", null);
+    result = r.split("a<b>font</b>bar<TAG>hello</TAG>");
+
+    for (i = 0; i < result.length; i++)
+    {
+	//debug(regexp) printf("result[%d] = '%.*s'\n", i, result[i]);
+    }
+
+    j = join(result, ",");
+    //printf("j = '%.*s'\n", j);
+    i = std.string.cmp(j, "a,,b,font,/,b,bar,,TAG,hello,/,TAG,");
+    assert(i == 0);
+
+    r = new RegExp("a[bc]", null);
+    result = r.match("123ab");
+    j = join(result, ",");
+    i = std.string.cmp(j, "ab");
+    assert(i == 0);
+    
+    result = r.match("ac");
+    j = join(result, ",");
+    i = std.string.cmp(j, "ac");
+    assert(i == 0);
+}
+
+/*************************************************
+ * Search string[] for match with regular expression.
+ * Returns:
+ *	index of match if successful, -1 if not found
+ */
+
+public int find(rchar[] string)
+{
+    int i;
+
+    i = test(string);
+    if (i)
+	i = pmatch[0].rm_so;
+    else
+	i = -1;			// no match
+    return i;
+}
+
+//deprecated alias find search;
+
+unittest
+{
+    debug(regexp) printf("regexp.find.unittest()\n");
+
+    int i;
+    RegExp r = new RegExp("abc", null);
+    i = r.find("xabcy");
+    assert(i == 1);
+    i = r.find("cba");
+    assert(i == -1);
+}
+
+
+/*************************************************
+ * Search string[] for match.
+ * Returns:
+ *	If global attribute, return same value as exec(string).
+ *	If not global attribute, return array of all matches.
+ */
+
+public rchar[][] match(rchar[] string)
+{
+    rchar[][] result;
+
+    if (attributes & REA.global)
+    {
+	int lastindex = 0;
+
+	while (test(string, lastindex))
+	{   int eo = pmatch[0].rm_eo;
+
+	    result ~= input[pmatch[0].rm_so .. eo];
+	    if (lastindex == eo)
+		lastindex++;		// always consume some source
+	    else
+		lastindex = eo;
+	}
+    }
+    else
+    {
+	result = exec(string);
+    }
+    return result;
+}
+
+unittest
+{
+    debug(regexp) printf("regexp.match.unittest()\n");
+
+    int i;
+    rchar[][] result;
+    rchar[] j;
+    RegExp r;
+
+    r = new RegExp("a[bc]", null);
+    result = r.match("1ab2ac3");
+    j = join(result, ",");
+    i = std.string.cmp(j, "ab");
+    assert(i == 0);
+
+    r = new RegExp("a[bc]", "g");
+    result = r.match("1ab2ac3");
+    j = join(result, ",");
+    i = std.string.cmp(j, "ab,ac");
+    assert(i == 0);
+}
+
+
+/*************************************************
+ * Find regular expression matches in string[]. Replace those matches
+ * with a new _string composed of format[] merged with the result of the
+ * matches.
+ * If global, replace all matches. Otherwise, replace first match.
+ * Returns: the new _string
+ */
+
+public rchar[] replace(rchar[] string, rchar[] format)
+{
+    rchar[] result;
+    int lastindex;
+    int offset;
+
+    result = string;
+    lastindex = 0;
+    offset = 0;
+    for (;;)
+    {
+	if (!test(string, lastindex))
+	    break;
+
+	int so = pmatch[0].rm_so;
+	int eo = pmatch[0].rm_eo;
+
+	rchar[] replacement = replace(format);
+
+	// Optimize by using std.string.replace if possible - Dave Fladebo
+	rchar[] slice = result[offset + so .. offset + eo];
+	if (attributes & REA.global &&		// global, so replace all
+	   !(attributes & REA.ignoreCase) &&	// not ignoring case
+	   !(attributes & REA.multiline) &&	// not multiline
+	   pattern == slice &&			// simple pattern (exact match, no special characters) 
+	   format == replacement)		// simple format, not $ formats
+	{
+	    debug(regexp)
+		printf("pattern: %.*s, slice: %.*s, format: %.*s, replacement: %.*s\n",
+		    cast(int) pattern.length, pattern.ptr,
+		    cast(int) (eo-so), result.ptr + offset,
+		    cast(int) format.length, format.ptr,
+		    cast(int) replacement.length, replacement.ptr);
+	    result = std.string.replace(result,slice,replacement);
+	    break;
+	}
+
+	result = replaceSlice(result, result[offset + so .. offset + eo], replacement);
+
+	if (attributes & REA.global)
+	{
+	    offset += replacement.length - (eo - so);
+
+	    if (lastindex == eo)
+		lastindex++;		// always consume some source
+	    else
+		lastindex = eo;
+	}
+	else
+	    break;
+    }
+
+    return result;
+}
+
+unittest
+{
+    debug(regexp) printf("regexp.replace.unittest()\n");
+
+    int i;
+    rchar[] result;
+    RegExp r;
+
+    r = new RegExp("a[bc]", "g");
+    result = r.replace("1ab2ac3", "x$&y");
+    i = std.string.cmp(result, "1xaby2xacy3");
+    assert(i == 0);
+
+    r = new RegExp("ab", "g");
+    result = r.replace("1ab2ac3", "xy");
+    i = std.string.cmp(result, "1xy2ac3");
+    assert(i == 0);
+}
+
+
+/*************************************************
+ * Search string[] for match.
+ * Returns:
+ *	array of slices into string[] representing matches
+ */
+
+public rchar[][] exec(rchar[] string)
+{
+    debug(regexp) printf("regexp.exec(string = '%.*s')\n",
+	cast(int) string.length, string.ptr);
+    input = string;
+    pmatch[0].rm_so = 0;
+    pmatch[0].rm_eo = 0;
+    return exec();
+}
+
+/*************************************************
+ * Pick up where last exec(string) or exec() left off,
+ * searching string[] for next match.
+ * Returns:
+ *	array of slices into string[] representing matches
+ */
+
+public rchar[][] exec()
+{
+    if (!test())
+	return null;
+
+    auto result = new rchar[][pmatch.length];
+    for (int i = 0; i < pmatch.length; i++)
+    {
+	if (pmatch[i].rm_so == pmatch[i].rm_eo)
+	    result[i] = null;
+	else
+	    result[i] = input[pmatch[i].rm_so .. pmatch[i].rm_eo];
+    }
+
+    return result;
+}
+
+/************************************************
+ * Search string[] for match.
+ * Returns: 0 for no match, !=0 for match
+ * Example:
+---
+import std.stdio;
+import std.regexp;
+import std.string;
+
+int grep(int delegate(char[]) pred, char[][] list)
+{
+  int count;
+  foreach (s; list)
+  {  if (pred(s))
+       ++count;
+  }
+  return count;
+}
+
+void main()
+{
+  auto x = grep(&RegExp("[Ff]oo").test,
+                std.string.split("mary had a foo lamb"));
+  writefln(x);
+}
+---
+ * which prints: 1
+ */
+
+public int test(rchar[] string)
+{
+    return test(string, 0 /*pmatch[0].rm_eo*/);
+}
+
+/************************************************
+ * Pick up where last test(string) or test() left off, and search again.
+ * Returns: 0 for no match, !=0 for match
+ */
+
+public int test()
+{
+    return test(input, pmatch[0].rm_eo);
+}
+
+/************************************************
+ * Test string[] starting at startindex against regular expression.
+ * Returns: 0 for no match, !=0 for match
+ */
+
+public int test(char[] string, int startindex)
+{
+    char firstc;
+    uint si;
+
+    input = string;
+    debug (regexp) printf("RegExp.test(input[] = '%.*s', startindex = %d)\n",
+	cast(int) input.length, input.ptr, startindex);
+    pmatch[0].rm_so = 0;
+    pmatch[0].rm_eo = 0;
+    if (startindex < 0 || startindex > input.length)
+    {
+	return 0;			// fail
+    }
+    //debug(regexp) printProgram(program);
+
+    // First character optimization
+    firstc = 0;
+    if (program[0] == REchar)
+    {
+	firstc = program[1];
+	if (attributes & REA.ignoreCase && isalpha(firstc))
+	    firstc = 0;
+    }
+
+    for (si = startindex; ; si++)
+    {
+	if (firstc)
+	{
+	    if (si == input.length)
+		break;			// no match
+	    if (input[si] != firstc)
+	    {
+		si++;
+		if (!chr(si, firstc))	// if first character not found
+		    break;		// no match
+	    }
+	}
+	for (int i = 0; i < re_nsub + 1; i++)
+	{
+	    pmatch[i].rm_so = -1;
+	    pmatch[i].rm_eo = -1;
+	}
+	src_start = src = si;
+	if (trymatch(0, program.length))
+	{
+	    pmatch[0].rm_so = si;
+	    pmatch[0].rm_eo = src;
+	    //debug(regexp) printf("start = %d, end = %d\n", gmatch.rm_so, gmatch.rm_eo);
+	    return 1;
+	}
+	// If possible match must start at beginning, we are done
+	if (program[0] == REbol || program[0] == REanystar)
+	{
+	    if (attributes & REA.multiline)
+	    {
+		// Scan for the next \n
+		if (!chr(si, '\n'))
+		    break;		// no match if '\n' not found
+	    }
+	    else
+		break;
+	}
+	if (si == input.length)
+	    break;
+	//debug(regexp) printf("Starting new try: '%.*s'\n", input[si + 1 .. input.length]);
+    }
+    return 0;		// no match
+}
+
+int chr(inout uint si, rchar c)
+{
+    for (; si < input.length; si++)
+    {
+	if (input[si] == c)
+	    return 1;
+    }
+    return 0;
+}
+
+
+void printProgram(ubyte[] prog)
+{
+  //debug(regexp)
+  {
+    uint pc;
+    uint len;
+    uint n;
+    uint m;
+    ushort *pu;
+    uint *puint;
+    ubyte[] s;
+
+    printf("printProgram()\n");
+    for (pc = 0; pc < prog.length; )
+    {
+	printf("%3d: ", pc);
+
+	//printf("prog[pc] = %d, REchar = %d, REnmq = %d\n", prog[pc], REchar, REnmq);
+	switch (prog[pc])
+	{
+	    case REchar:
+		printf("\tREchar '%c'\n", prog[pc + 1]);
+		pc += 1 + char.sizeof;
+		break;
+
+	    case REichar:
+		printf("\tREichar '%c'\n", prog[pc + 1]);
+		pc += 1 + char.sizeof;
+		break;
+
+	    case REdchar:
+		printf("\tREdchar '%c'\n", *cast(dchar *)&prog[pc + 1]);
+		pc += 1 + dchar.sizeof;
+		break;
+
+	    case REidchar:
+		printf("\tREidchar '%c'\n", *cast(dchar *)&prog[pc + 1]);
+		pc += 1 + dchar.sizeof;
+		break;
+
+	    case REanychar:
+		printf("\tREanychar\n");
+		pc++;
+		break;
+
+	    case REstring:
+		len = *cast(uint *)&prog[pc + 1];
+		s = (&prog[pc + 1 + uint.sizeof])[0 .. len];
+		printf("\tREstring x%x, '%.*s'\n", len,
+		    cast(int) s.length, s.ptr);
+		pc += 1 + uint.sizeof + len * rchar.sizeof;
+		break;
+
+	    case REistring:
+		len = *cast(uint *)&prog[pc + 1];
+		s = (&prog[pc + 1 + uint.sizeof])[0 .. len];
+		printf("\tREistring x%x, '%.*s'\n", len,
+		    cast(int) s.length, s.ptr);
+		pc += 1 + uint.sizeof + len * rchar.sizeof;
+		break;
+
+	    case REtestbit:
+		pu = cast(ushort *)&prog[pc + 1];
+		printf("\tREtestbit %d, %d\n", pu[0], pu[1]);
+		len = pu[1];
+		pc += 1 + 2 * ushort.sizeof + len;
+		break;
+
+	    case REbit:
+		pu = cast(ushort *)&prog[pc + 1];
+		len = pu[1];
+		printf("\tREbit cmax=%02x, len=%d:", pu[0], len);
+		for (n = 0; n < len; n++)
+		    printf(" %02x", prog[pc + 1 + 2 * ushort.sizeof + n]);
+		printf("\n");
+		pc += 1 + 2 * ushort.sizeof + len;
+		break;
+
+	    case REnotbit:
+		pu = cast(ushort *)&prog[pc + 1];
+		printf("\tREnotbit %d, %d\n", pu[0], pu[1]);
+		len = pu[1];
+		pc += 1 + 2 * ushort.sizeof + len;
+		break;
+
+	    case RErange:
+		len = *cast(uint *)&prog[pc + 1];
+		printf("\tRErange %d\n", len);
+		// BUG: REAignoreCase?
+		pc += 1 + uint.sizeof + len;
+		break;
+
+	    case REnotrange:
+		len = *cast(uint *)&prog[pc + 1];
+		printf("\tREnotrange %d\n", len);
+		// BUG: REAignoreCase?
+		pc += 1 + uint.sizeof + len;
+		break;
+
+	    case REbol:
+		printf("\tREbol\n");
+		pc++;
+		break;
+
+	    case REeol:
+		printf("\tREeol\n");
+		pc++;
+		break;
+
+	    case REor:
+		len = *cast(uint *)&prog[pc + 1];
+		printf("\tREor %d, pc=>%d\n", len, pc + 1 + uint.sizeof + len);
+		pc += 1 + uint.sizeof;
+		break;
+
+	    case REgoto:
+		len = *cast(uint *)&prog[pc + 1];
+		printf("\tREgoto %d, pc=>%d\n", len, pc + 1 + uint.sizeof + len);
+		pc += 1 + uint.sizeof;
+		break;
+
+	    case REanystar:
+		printf("\tREanystar\n");
+		pc++;
+		break;
+
+	    case REnm:
+	    case REnmq:
+		// len, n, m, ()
+		puint = cast(uint *)&prog[pc + 1];
+		len = puint[0];
+		n = puint[1];
+		m = puint[2];
+		printf("\tREnm%s len=%d, n=%u, m=%u, pc=>%d\n",
+		    (prog[pc] == REnmq) ? cast(char*)"q" : cast(char*)" ",
+		    len, n, m, pc + 1 + uint.sizeof * 3 + len);
+		pc += 1 + uint.sizeof * 3;
+		break;
+
+	    case REparen:
+		// len, n, ()
+		puint = cast(uint *)&prog[pc + 1];
+		len = puint[0];
+		n = puint[1];
+		printf("\tREparen len=%d n=%d, pc=>%d\n", len, n, pc + 1 + uint.sizeof * 2 + len);
+		pc += 1 + uint.sizeof * 2;
+		break;
+
+	    case REend:
+		printf("\tREend\n");
+		return;
+
+	    case REwordboundary:
+		printf("\tREwordboundary\n");
+		pc++;
+		break;
+
+	    case REnotwordboundary:
+		printf("\tREnotwordboundary\n");
+		pc++;
+		break;
+
+	    case REdigit:
+		printf("\tREdigit\n");
+		pc++;
+		break;
+
+	    case REnotdigit:
+		printf("\tREnotdigit\n");
+		pc++;
+		break;
+
+	    case REspace:
+		printf("\tREspace\n");
+		pc++;
+		break;
+
+	    case REnotspace:
+		printf("\tREnotspace\n");
+		pc++;
+		break;
+
+	    case REword:
+		printf("\tREword\n");
+		pc++;
+		break;
+
+	    case REnotword:
+		printf("\tREnotword\n");
+		pc++;
+		break;
+
+	    case REbackref:
+		printf("\tREbackref %d\n", prog[1]);
+		pc += 2;
+		break;
+
+	    default:
+		assert(0);
+	}
+    }
+  }
+}
+
+
+/**************************************************
+ * Match input against a section of the program[].
+ * Returns:
+ *	1 if successful match
+ *	0 no match
+ */
+
+int trymatch(int pc, int pcend)
+{   int srcsave;
+    uint len;
+    uint n;
+    uint m;
+    uint count;
+    uint pop;
+    uint ss;
+    regmatch_t *psave;
+    uint c1;
+    uint c2;
+    ushort* pu;
+    uint* puint;
+
+    debug(regexp)
+    {
+	char[] s = input[src .. input.length];
+	printf("RegExp.trymatch(pc = %d, src = '%.*s', pcend = %d)\n",
+	    pc, cast(int) s.length, s.ptr, pcend);
+    }
+    srcsave = src;
+    psave = null;
+    for (;;)
+    {
+	if (pc == pcend)		// if done matching
+	{   debug(regex) printf("\tprogend\n");
+	    return 1;
+	}
+
+	//printf("\top = %d\n", program[pc]);
+	switch (program[pc])
+	{
+	    case REchar:
+		if (src == input.length)
+		    goto Lnomatch;
+		debug(regexp) printf("\tREchar '%c', src = '%c'\n", program[pc + 1], input[src]);
+		if (program[pc + 1] != input[src])
+		    goto Lnomatch;
+		src++;
+		pc += 1 + char.sizeof;
+		break;
+
+	    case REichar:
+		if (src == input.length)
+		    goto Lnomatch;
+		debug(regexp) printf("\tREichar '%c', src = '%c'\n", program[pc + 1], input[src]);
+		c1 = program[pc + 1];
+		c2 = input[src];
+		if (c1 != c2)
+		{
+		    if (islower(cast(rchar)c2))
+			c2 = std.ctype.toupper(cast(rchar)c2);
+		    else
+			goto Lnomatch;
+		    if (c1 != c2)
+			goto Lnomatch;
+		}
+		src++;
+		pc += 1 + char.sizeof;
+		break;
+
+	    case REdchar:
+		debug(regexp) printf("\tREdchar '%c', src = '%c'\n", *(cast(dchar *)&program[pc + 1]), input[src]);
+		if (src == input.length)
+		    goto Lnomatch;
+		if (*(cast(dchar *)&program[pc + 1]) != input[src])
+		    goto Lnomatch;
+		src++;
+		pc += 1 + dchar.sizeof;
+		break;
+
+	    case REidchar:
+		debug(regexp) printf("\tREidchar '%c', src = '%c'\n", *(cast(dchar *)&program[pc + 1]), input[src]);
+		if (src == input.length)
+		    goto Lnomatch;
+		c1 = *(cast(dchar *)&program[pc + 1]);
+		c2 = input[src];
+		if (c1 != c2)
+		{
+		    if (islower(cast(rchar)c2))
+			c2 = std.ctype.toupper(cast(rchar)c2);
+		    else
+			goto Lnomatch;
+		    if (c1 != c2)
+			goto Lnomatch;
+		}
+		src++;
+		pc += 1 + dchar.sizeof;
+		break;
+
+	    case REanychar:
+		debug(regexp) printf("\tREanychar\n");
+		if (src == input.length)
+		    goto Lnomatch;
+		if (!(attributes & REA.dotmatchlf) && input[src] == cast(rchar)'\n')
+		    goto Lnomatch;
+		src += std.utf.stride(input, src);
+		//src++;
+		pc++;
+		break;
+
+	    case REstring:
+		len = *cast(uint *)&program[pc + 1];
+		debug(regexp)
+		{
+		    char[] s = (&program[pc + 1 + uint.sizeof])[0 .. len];
+		    printf("\tREstring x%x, '%.*s'\n", len,
+			cast(int) s.length, s.ptr);
+		}
+		if (src + len > input.length)
+		    goto Lnomatch;
+		if (memcmp(&program[pc + 1 + uint.sizeof], &input[src], len * rchar.sizeof))
+		    goto Lnomatch;
+		src += len;
+		pc += 1 + uint.sizeof + len * rchar.sizeof;
+		break;
+
+	    case REistring:
+		len = *cast(uint *)&program[pc + 1];
+		debug(regexp)
+		{
+		    char[] s = (&program[pc + 1 + uint.sizeof])[0 .. len];
+		    printf("\tREistring x%x, '%.*s'\n", len,
+			cast(int) s.length, s.ptr);
+		}
+		if (src + len > input.length)
+		    goto Lnomatch;
+		version (Win32)
+		{
+		    if (memicmp(cast(char*)&program[pc + 1 + uint.sizeof], &input[src], len * rchar.sizeof))
+			goto Lnomatch;
+		}
+		else
+		{
+		    if (icmp((cast(char*)&program[pc + 1 + uint.sizeof])[0..len],
+			     input[src .. src + len]))
+			goto Lnomatch;
+		}
+		src += len;
+		pc += 1 + uint.sizeof + len * rchar.sizeof;
+		break;
+
+	    case REtestbit:
+		pu = (cast(ushort *)&program[pc + 1]);
+		debug(regexp) printf("\tREtestbit %d, %d, '%c', x%02x\n",
+		    pu[0], pu[1], input[src], input[src]);
+		if (src == input.length)
+		    goto Lnomatch;
+		len = pu[1];
+		c1 = input[src];
+		//printf("[x%02x]=x%02x, x%02x\n", c1 >> 3, ((&program[pc + 1 + 4])[c1 >> 3] ), (1 << (c1 & 7)));
+		if (c1 <= pu[0] &&
+		    !bt(cast(uint*)&(program[pc + 1 + 4]), c1)) // assumes BitArray implementation
+		    goto Lnomatch;
+		pc += 1 + 2 * ushort.sizeof + len;
+		break;
+
+	    case REbit:
+		pu = (cast(ushort *)&program[pc + 1]);
+		debug(regexp) printf("\tREbit %d, %d, '%c'\n",
+		    pu[0], pu[1], input[src]);
+		if (src == input.length)
+		    goto Lnomatch;
+		len = pu[1];
+		c1 = input[src];
+		if (c1 > pu[0])
+		    goto Lnomatch;
+		if (!bt(cast(uint*)&(program[pc + 1 + 4]), c1)) // assumes BitArray implementation
+		    goto Lnomatch;
+		src++;
+		pc += 1 + 2 * ushort.sizeof + len;
+		break;
+
+	    case REnotbit:
+		pu = (cast(ushort *)&program[pc + 1]);
+		debug(regexp) printf("\tREnotbit %d, %d, '%c'\n",
+		    pu[0], pu[1], input[src]);
+		if (src == input.length)
+		    goto Lnomatch;
+		len = pu[1];
+		c1 = input[src];
+		if (c1 <= pu[0] &&
+		    bt(cast(uint*)&(program[pc + 1 + 4]), c1)) // assumes BitArray implementation
+		    goto Lnomatch;
+		src++;
+		pc += 1 + 2 * ushort.sizeof + len;
+		break;
+
+	    case RErange:
+		len = *cast(uint *)&program[pc + 1];
+		debug(regexp) printf("\tRErange %d\n", len);
+		if (src == input.length)
+		    goto Lnomatch;
+		// BUG: REA.ignoreCase?
+		if (memchr(cast(char*)&program[pc + 1 + uint.sizeof], input[src], len) == null)
+		    goto Lnomatch;
+		src++;
+		pc += 1 + uint.sizeof + len;
+		break;
+
+	    case REnotrange:
+		len = *cast(uint *)&program[pc + 1];
+		debug(regexp) printf("\tREnotrange %d\n", len);
+		if (src == input.length)
+		    goto Lnomatch;
+		// BUG: REA.ignoreCase?
+		if (memchr(cast(char*)&program[pc + 1 + uint.sizeof], input[src], len) != null)
+		    goto Lnomatch;
+		src++;
+		pc += 1 + uint.sizeof + len;
+		break;
+
+	    case REbol:
+		debug(regexp) printf("\tREbol\n");
+		if (src == 0)
+		{
+		}
+		else if (attributes & REA.multiline)
+		{
+		    if (input[src - 1] != '\n')
+			goto Lnomatch;
+		}
+		else
+		    goto Lnomatch;
+		pc++;
+		break;
+
+	    case REeol:
+		debug(regexp) printf("\tREeol\n");
+		if (src == input.length)
+		{
+		}
+		else if (attributes & REA.multiline && input[src] == '\n')
+		    src++;
+		else
+		    goto Lnomatch;
+		pc++;
+		break;
+
+	    case REor:
+		len = (cast(uint *)&program[pc + 1])[0];
+		debug(regexp) printf("\tREor %d\n", len);
+		pop = pc + 1 + uint.sizeof;
+		ss = src;
+		if (trymatch(pop, pcend))
+		{
+		    if (pcend != program.length)
+		    {	int s;
+
+			s = src;
+			if (trymatch(pcend, program.length))
+			{   debug(regexp) printf("\tfirst operand matched\n");
+			    src = s;
+			    return 1;
+			}
+			else
+			{
+			    // If second branch doesn't match to end, take first anyway
+			    src = ss;
+			    if (!trymatch(pop + len, program.length))
+			    {
+				debug(regexp) printf("\tfirst operand matched\n");
+				src = s;
+				return 1;
+			    }
+			}
+			src = ss;
+		    }
+		    else
+		    {	debug(regexp) printf("\tfirst operand matched\n");
+			return 1;
+		    }
+		}
+		pc = pop + len;		// proceed with 2nd branch
+		break;
+
+	    case REgoto:
+		debug(regexp) printf("\tREgoto\n");
+		len = (cast(uint *)&program[pc + 1])[0];
+		pc += 1 + uint.sizeof + len;
+		break;
+
+	    case REanystar:
+		debug(regexp) printf("\tREanystar\n");
+		pc++;
+		for (;;)
+		{   int s1;
+		    int s2;
+
+		    s1 = src;
+		    if (src == input.length)
+			break;
+		    if (!(attributes & REA.dotmatchlf) && input[src] == '\n')
+			break;
+		    src++;
+		    s2 = src;
+
+		    // If no match after consumption, but it
+		    // did match before, then no match
+		    if (!trymatch(pc, program.length))
+		    {
+			src = s1;
+			// BUG: should we save/restore pmatch[]?
+			if (trymatch(pc, program.length))
+			{
+			    src = s1;		// no match
+			    break;
+			}
+		    }
+		    src = s2;
+		}
+		break;
+
+	    case REnm:
+	    case REnmq:
+		// len, n, m, ()
+		puint = cast(uint *)&program[pc + 1];
+		len = puint[0];
+		n = puint[1];
+		m = puint[2];
+		debug(regexp) printf("\tREnm%s len=%d, n=%u, m=%u\n", (program[pc] == REnmq) ? cast(char*)"q" : cast(char*)"", len, n, m);
+		pop = pc + 1 + uint.sizeof * 3;
+		for (count = 0; count < n; count++)
+		{
+		    if (!trymatch(pop, pop + len))
+			goto Lnomatch;
+		}
+		if (!psave && count < m)
+		{
+		    //version (Win32)
+			psave = cast(regmatch_t *)alloca((re_nsub + 1) * regmatch_t.sizeof);
+		    //else
+			//psave = new regmatch_t[re_nsub + 1];
+		}
+		if (program[pc] == REnmq)	// if minimal munch
+		{
+		    for (; count < m; count++)
+		    {   int s1;
+
+			memcpy(psave, pmatch.ptr, (re_nsub + 1) * regmatch_t.sizeof);
+			s1 = src;
+
+			if (trymatch(pop + len, program.length))
+			{
+			    src = s1;
+			    memcpy(pmatch.ptr, psave, (re_nsub + 1) * regmatch_t.sizeof);
+			    break;
+			}
+
+			if (!trymatch(pop, pop + len))
+			{   debug(regexp) printf("\tdoesn't match subexpression\n");
+			    break;
+			}
+
+			// If source is not consumed, don't
+			// infinite loop on the match
+			if (s1 == src)
+			{   debug(regexp) printf("\tsource is not consumed\n");
+			    break;
+			}
+		    }
+		}
+		else	// maximal munch
+		{
+		    for (; count < m; count++)
+		    {   int s1;
+			int s2;
+
+			memcpy(psave, pmatch.ptr, (re_nsub + 1) * regmatch_t.sizeof);
+			s1 = src;
+			if (!trymatch(pop, pop + len))
+			{   debug(regexp) printf("\tdoesn't match subexpression\n");
+			    break;
+			}
+			s2 = src;
+
+			// If source is not consumed, don't
+			// infinite loop on the match
+			if (s1 == s2)
+			{   debug(regexp) printf("\tsource is not consumed\n");
+			    break;
+			}
+
+			// If no match after consumption, but it
+			// did match before, then no match
+			if (!trymatch(pop + len, program.length))
+			{
+			    src = s1;
+			    if (trymatch(pop + len, program.length))
+			    {
+				src = s1;		// no match
+				memcpy(pmatch.ptr, psave, (re_nsub + 1) * regmatch_t.sizeof);
+				break;
+			    }
+			}
+			src = s2;
+		    }
+		}
+		debug(regexp) printf("\tREnm len=%d, n=%u, m=%u, DONE count=%d\n", len, n, m, count);
+		pc = pop + len;
+		break;
+
+	    case REparen:
+		// len, ()
+		debug(regexp) printf("\tREparen\n");
+		puint = cast(uint *)&program[pc + 1];
+		len = puint[0];
+		n = puint[1];
+		pop = pc + 1 + uint.sizeof * 2;
+		ss = src;
+		if (!trymatch(pop, pop + len))
+		    goto Lnomatch;
+		pmatch[n + 1].rm_so = ss;
+		pmatch[n + 1].rm_eo = src;
+		pc = pop + len;
+		break;
+
+	    case REend:
+		debug(regexp) printf("\tREend\n");
+		return 1;		// successful match
+
+	    case REwordboundary:
+		debug(regexp) printf("\tREwordboundary\n");
+		if (src > 0 && src < input.length)
+		{
+		    c1 = input[src - 1];
+		    c2 = input[src];
+		    if (!(
+			  (isword(cast(rchar)c1) && !isword(cast(rchar)c2)) ||
+			  (!isword(cast(rchar)c1) && isword(cast(rchar)c2))
+			 )
+		       )
+			goto Lnomatch;
+		}
+		pc++;
+		break;
+
+	    case REnotwordboundary:
+		debug(regexp) printf("\tREnotwordboundary\n");
+		if (src == 0 || src == input.length)
+		    goto Lnomatch;
+		c1 = input[src - 1];
+		c2 = input[src];
+		if (
+		    (isword(cast(rchar)c1) && !isword(cast(rchar)c2)) ||
+		    (!isword(cast(rchar)c1) && isword(cast(rchar)c2))
+		   )
+		    goto Lnomatch;
+		pc++;
+		break;
+
+	    case REdigit:
+		debug(regexp) printf("\tREdigit\n");
+		if (src == input.length)
+		    goto Lnomatch;
+		if (!isdigit(input[src]))
+		    goto Lnomatch;
+		src++;
+		pc++;
+		break;
+
+	    case REnotdigit:
+		debug(regexp) printf("\tREnotdigit\n");
+		if (src == input.length)
+		    goto Lnomatch;
+		if (isdigit(input[src]))
+		    goto Lnomatch;
+		src++;
+		pc++;
+		break;
+
+	    case REspace:
+		debug(regexp) printf("\tREspace\n");
+		if (src == input.length)
+		    goto Lnomatch;
+		if (!isspace(input[src]))
+		    goto Lnomatch;
+		src++;
+		pc++;
+		break;
+
+	    case REnotspace:
+		debug(regexp) printf("\tREnotspace\n");
+		if (src == input.length)
+		    goto Lnomatch;
+		if (isspace(input[src]))
+		    goto Lnomatch;
+		src++;
+		pc++;
+		break;
+
+	    case REword:
+		debug(regexp) printf("\tREword\n");
+		if (src == input.length)
+		    goto Lnomatch;
+		if (!isword(input[src]))
+		    goto Lnomatch;
+		src++;
+		pc++;
+		break;
+
+	    case REnotword:
+		debug(regexp) printf("\tREnotword\n");
+		if (src == input.length)
+		    goto Lnomatch;
+		if (isword(input[src]))
+		    goto Lnomatch;
+		src++;
+		pc++;
+		break;
+
+	    case REbackref:
+	    {
+		n = program[pc + 1];
+		debug(regexp) printf("\tREbackref %d\n", n);
+
+		int so = pmatch[n + 1].rm_so;
+		int eo = pmatch[n + 1].rm_eo;
+		len = eo - so;
+		if (src + len > input.length)
+		    goto Lnomatch;
+		else if (attributes & REA.ignoreCase)
+		{
+		    if (icmp(input[src .. src + len], input[so .. eo]))
+			goto Lnomatch;
+		}
+		else if (memcmp(&input[src], &input[so], len * rchar.sizeof))
+		    goto Lnomatch;
+		src += len;
+		pc += 2;
+		break;
+	    }
+
+	    default:
+		assert(0);
+	}
+    }
+
+Lnomatch:
+    debug(regexp) printf("\tnomatch pc=%d\n", pc);
+    src = srcsave;
+    return 0;
+}
+
+/* =================== Compiler ================== */
+
+int parseRegexp()
+{   uint offset;
+    uint gotooffset;
+    uint len1;
+    uint len2;
+
+    //printf("parseRegexp() '%.*s'\n", pattern[p .. pattern.length]);
+    offset = buf.offset;
+    for (;;)
+    {
+	assert(p <= pattern.length);
+	if (p == pattern.length)
+	{   buf.write(REend);
+	    return 1;
+	}
+	switch (pattern[p])
+	{
+	    case ')':
+		return 1;
+
+	    case '|':
+		p++;
+		gotooffset = buf.offset;
+		buf.write(REgoto);
+		buf.write(cast(uint)0);
+		len1 = buf.offset - offset;
+		buf.spread(offset, 1 + uint.sizeof);
+		gotooffset += 1 + uint.sizeof;
+		parseRegexp();
+		len2 = buf.offset - (gotooffset + 1 + uint.sizeof);
+		buf.data[offset] = REor;
+		(cast(uint *)&buf.data[offset + 1])[0] = len1;
+		(cast(uint *)&buf.data[gotooffset + 1])[0] = len2;
+		break;
+
+	    default:
+		parsePiece();
+		break;
+	}
+    }
+    assert(0);
+}
+
+int parsePiece()
+{   uint offset;
+    uint len;
+    uint n;
+    uint m;
+    ubyte op;
+    int plength = pattern.length;
+
+    //printf("parsePiece() '%.*s'\n", pattern[p .. pattern.length]);
+    offset = buf.offset;
+    parseAtom();
+    if (p == plength)
+	return 1;
+    switch (pattern[p])
+    {
+	case '*':
+	    // Special optimization: replace .* with REanystar
+	    if (buf.offset - offset == 1 &&
+		buf.data[offset] == REanychar &&
+		p + 1 < plength &&
+		pattern[p + 1] != '?')
+	    {
+		buf.data[offset] = REanystar;
+		p++;
+		break;
+	    }
+
+	    n = 0;
+	    m = inf;
+	    goto Lnm;
+
+	case '+':
+	    n = 1;
+	    m = inf;
+	    goto Lnm;
+
+	case '?':
+	    n = 0;
+	    m = 1;
+	    goto Lnm;
+
+	case '{':	// {n} {n,} {n,m}
+	    p++;
+	    if (p == plength || !isdigit(pattern[p]))
+		goto Lerr;
+	    n = 0;
+	    do
+	    {
+		// BUG: handle overflow
+		n = n * 10 + pattern[p] - '0';
+		p++;
+		if (p == plength)
+		    goto Lerr;
+	    } while (isdigit(pattern[p]));
+	    if (pattern[p] == '}')		// {n}
+	    {	m = n;
+		goto Lnm;
+	    }
+	    if (pattern[p] != ',')
+		goto Lerr;
+	    p++;
+	    if (p == plength)
+		goto Lerr;
+	    if (pattern[p] == /*{*/ '}')	// {n,}
+	    {	m = inf;
+		goto Lnm;
+	    }
+	    if (!isdigit(pattern[p]))
+		goto Lerr;
+	    m = 0;			// {n,m}
+	    do
+	    {
+		// BUG: handle overflow
+		m = m * 10 + pattern[p] - '0';
+		p++;
+		if (p == plength)
+		    goto Lerr;
+	    } while (isdigit(pattern[p]));
+	    if (pattern[p] != /*{*/ '}')
+		goto Lerr;
+	    goto Lnm;
+
+	Lnm:
+	    p++;
+	    op = REnm;
+	    if (p < plength && pattern[p] == '?')
+	    {	op = REnmq;	// minimal munch version
+		p++;
+	    }
+	    len = buf.offset - offset;
+	    buf.spread(offset, 1 + uint.sizeof * 3);
+	    buf.data[offset] = op;
+	    uint* puint = cast(uint *)&buf.data[offset + 1];
+	    puint[0] = len;
+	    puint[1] = n;
+	    puint[2] = m;
+	    break;
+
+	default:
+	    break;
+    }
+    return 1;
+
+Lerr:
+    error("badly formed {n,m}");
+    assert(0);
+}
+
+int parseAtom()
+{   ubyte op;
+    uint offset;
+    rchar c;
+
+    //printf("parseAtom() '%.*s'\n", pattern[p .. pattern.length]);
+    if (p < pattern.length)
+    {
+	c = pattern[p];
+	switch (c)
+	{
+	    case '*':
+	    case '+':
+	    case '?':
+		error("*+? not allowed in atom");
+		p++;
+		return 0;
+
+	    case '(':
+		p++;
+		buf.write(REparen);
+		offset = buf.offset;
+		buf.write(cast(uint)0);		// reserve space for length
+		buf.write(re_nsub);
+		re_nsub++;
+		parseRegexp();
+		*cast(uint *)&buf.data[offset] =
+		    buf.offset - (offset + uint.sizeof * 2);
+		if (p == pattern.length || pattern[p] != ')')
+		{
+		    error("')' expected");
+		    return 0;
+		}
+		p++;
+		break;
+
+	    case '[':
+		if (!parseRange())
+		    return 0;
+		break;
+
+	    case '.':
+		p++;
+		buf.write(REanychar);
+		break;
+
+	    case '^':
+		p++;
+		buf.write(REbol);
+		break;
+
+	    case '$':
+		p++;
+		buf.write(REeol);
+		break;
+
+	    case '\\':
+		p++;
+		if (p == pattern.length)
+		{   error("no character past '\\'");
+		    return 0;
+		}
+		c = pattern[p];
+		switch (c)
+		{
+		    case 'b':    op = REwordboundary;	 goto Lop;
+		    case 'B':    op = REnotwordboundary; goto Lop;
+		    case 'd':    op = REdigit;		 goto Lop;
+		    case 'D':    op = REnotdigit;	 goto Lop;
+		    case 's':    op = REspace;		 goto Lop;
+		    case 'S':    op = REnotspace;	 goto Lop;
+		    case 'w':    op = REword;		 goto Lop;
+		    case 'W':    op = REnotword;	 goto Lop;
+
+		    Lop:
+			buf.write(op);
+			p++;
+			break;
+
+		    case 'f':
+		    case 'n':
+		    case 'r':
+		    case 't':
+		    case 'v':
+		    case 'c':
+		    case 'x':
+		    case 'u':
+		    case '0':
+			c = cast(char)escape();
+			goto Lbyte;
+
+		    case '1': case '2': case '3':
+		    case '4': case '5': case '6':
+		    case '7': case '8': case '9':
+			c -= '1';
+			if (c < re_nsub)
+			{   buf.write(REbackref);
+			    buf.write(cast(ubyte)c);
+			}
+			else
+			{   error("no matching back reference");
+			    return 0;
+			}
+			p++;
+			break;
+
+		    default:
+			p++;
+			goto Lbyte;
+		}
+		break;
+
+	    default:
+		p++;
+	    Lbyte:
+		op = REchar;
+		if (attributes & REA.ignoreCase)
+		{
+		    if (isalpha(c))
+		    {
+			op = REichar;
+			c = cast(char)std.ctype.toupper(c);
+		    }
+		}
+		if (op == REchar && c <= 0xFF)
+		{
+		    // Look ahead and see if we can make this into
+		    // an REstring
+		    int q;
+		    int len;
+
+		    for (q = p; q < pattern.length; ++q)
+		    {	rchar qc = pattern[q];
+
+			switch (qc)
+			{
+			    case '{':
+			    case '*':
+			    case '+':
+			    case '?':
+				if (q == p)
+				    goto Lchar;
+				q--;
+				break;
+
+			    case '(':	case ')':
+			    case '|':
+			    case '[':	case ']':
+			    case '.':	case '^':
+			    case '$':	case '\\':
+			    case '}':
+				break;
+
+			    default:
+				continue;
+			}
+			break;
+		    }
+		    len = q - p;
+		    if (len > 0)
+		    {
+			debug(regexp) printf("writing string len %d, c = '%c', pattern[p] = '%c'\n", len+1, c, pattern[p]);
+			buf.reserve(5 + (1 + len) * rchar.sizeof);
+			buf.write((attributes & REA.ignoreCase) ? REistring : REstring);
+			buf.write(len + 1);
+			buf.write(c);
+			buf.write(pattern[p .. p + len]);
+			p = q;
+			break;
+		    }
+		}
+		if (c >= 0x80)
+		{
+		    // Convert to dchar opcode
+		    op = (op == REchar) ? REdchar : REidchar;
+		    buf.write(op);
+		    buf.write(c);
+		}
+		else
+		{
+		 Lchar:
+		    debug(regexp) printf("It's an REchar '%c'\n", c);
+		    buf.write(op);
+		    buf.write(cast(char)c);
+		}
+		break;
+	}
+    }
+    return 1;
+}
+
+private:
+class Range
+{
+    uint maxc;
+    uint maxb;
+    OutBuffer buf;
+    ubyte* base;
+    BitArray bits;
+
+    this(OutBuffer buf)
+    {
+	this.buf = buf;
+	if (buf.data.length)
+	    this.base = &buf.data[buf.offset];
+    }
+
+    void setbitmax(uint u)
+    {   uint b;
+
+	//printf("setbitmax(x%x), maxc = x%x\n", u, maxc);
+	if (u > maxc)
+	{
+	    maxc = u;
+	    b = u / 8;
+	    if (b >= maxb)
+	    {	uint u2;
+
+		u2 = base ? base - &buf.data[0] : 0;
+		++b;
+		version (BigEndian)
+		{
+		    while (b & (uint.sizeof-1))
+			++b;
+		}
+		
+		buf.fill0(b - maxb);
+		base = &buf.data[u2];
+		maxb = b;
+		// %% moved array recreate out of this condition
+		bits.ptr = cast(uint*)this.base;
+ 	    }
+	    //bits = (cast(bit*)this.base)[0 .. maxc + 1];
+	    bits.len = maxc + 1;
+	}
+    }
+
+    void setbit2(uint u)
+    {
+	setbitmax(u + 1);
+	//printf("setbit2 [x%02x] |= x%02x\n", u >> 3, 1 << (u & 7));
+	bits[u] = 1;
+    }
+
+};
+
+int parseRange()
+{   ubyte op;
+    int c;
+    int c2;
+    uint i;
+    uint cmax;
+    uint offset;
+
+    cmax = 0x7F;
+    p++;
+    op = REbit;
+    if (p == pattern.length)
+	goto Lerr;
+    if (pattern[p] == '^')
+    {   p++;
+	op = REnotbit;
+	if (p == pattern.length)
+	    goto Lerr;
+    }
+    buf.write(op);
+    offset = buf.offset;
+    buf.write(cast(uint)0);		// reserve space for length
+    buf.reserve(128 / 8);
+    auto r = new Range(buf);
+    if (op == REnotbit)
+	r.setbit2(0);
+    switch (pattern[p])
+    {
+	case ']':
+	case '-':
+	    c = pattern[p];
+	    p++;
+	    r.setbit2(c);
+	    break;
+
+	default:
+	    break;
+    }
+
+    enum RS { start, rliteral, dash };
+    RS rs;
+
+    rs = RS.start;
+    for (;;)
+    {
+	if (p == pattern.length)
+	    goto Lerr;
+	switch (pattern[p])
+	{
+	    case ']':
+		switch (rs)
+		{   case RS.dash:
+			r.setbit2('-');
+		    case RS.rliteral:
+			r.setbit2(c);
+			break;
+		    case RS.start:
+			break;
+		    default:
+			assert(0);
+		}
+		p++;
+		break;
+
+	    case '\\':
+		p++;
+		r.setbitmax(cmax);
+		if (p == pattern.length)
+		    goto Lerr;
+		switch (pattern[p])
+		{
+		    case 'd':
+			for (i = '0'; i <= '9'; i++)
+			    r.bits[i] = 1;
+			goto Lrs;
+
+		    case 'D':
+			for (i = 1; i < '0'; i++)
+			    r.bits[i] = 1;
+			for (i = '9' + 1; i <= cmax; i++)
+			    r.bits[i] = 1;
+			goto Lrs;
+
+		    case 's':
+			for (i = 0; i <= cmax; i++)
+			    if (isspace(i))
+				r.bits[i] = 1;
+			goto Lrs;
+
+		    case 'S':
+			for (i = 1; i <= cmax; i++)
+			    if (!isspace(i))
+				r.bits[i] = 1;
+			goto Lrs;
+
+		    case 'w':
+			for (i = 0; i <= cmax; i++)
+			    if (isword(cast(rchar)i))
+				r.bits[i] = 1;
+			goto Lrs;
+
+		    case 'W':
+			for (i = 1; i <= cmax; i++)
+			    if (!isword(cast(rchar)i))
+				r.bits[i] = 1;
+			goto Lrs;
+
+		    Lrs:
+			switch (rs)
+			{   case RS.dash:
+				r.setbit2('-');
+			    case RS.rliteral:
+				r.setbit2(c);
+				break;
+			    default:
+				break;
+			}
+			rs = RS.start;
+			continue;
+
+		    default:
+			break;
+		}
+		c2 = escape();
+		goto Lrange;
+
+	    case '-':
+		p++;
+		if (rs == RS.start)
+		    goto Lrange;
+		else if (rs == RS.rliteral)
+		    rs = RS.dash;
+		else if (rs == RS.dash)
+		{
+		    r.setbit2(c);
+		    r.setbit2('-');
+		    rs = RS.start;
+		}
+		continue;
+
+	    default:
+		c2 = pattern[p];
+		p++;
+	    Lrange:
+		switch (rs)
+		{   case RS.rliteral:
+			r.setbit2(c);
+		    case RS.start:
+			c = c2;
+			rs = RS.rliteral;
+			break;
+
+		    case RS.dash:
+			if (c > c2)
+			{   error("inverted range in character class");
+			    return 0;
+			}
+			r.setbitmax(c2);
+			//printf("c = %x, c2 = %x\n",c,c2);
+			for (; c <= c2; c++)
+			    r.bits[c] = 1;
+			rs = RS.start;
+			break;
+
+		    default:
+			assert(0);
+		}
+		continue;
+	}
+	break;
+    }
+    if (attributes & REA.ignoreCase)
+    {
+	// BUG: what about dchar?
+	r.setbitmax(0x7F);
+	for (c = 'a'; c <= 'z'; c++)
+	{
+	    if (r.bits[c])
+		r.bits[c + 'A' - 'a'] = 1;
+	    else if (r.bits[c + 'A' - 'a'])
+		r.bits[c] = 1;
+	}
+    }
+    //printf("maxc = %d, maxb = %d\n",r.maxc,r.maxb);
+    (cast(ushort *)&buf.data[offset])[0] = cast(ushort)r.maxc;
+    (cast(ushort *)&buf.data[offset])[1] = cast(ushort)r.maxb;
+    return 1;
+
+Lerr:
+    error("invalid range");
+    return 0;
+}
+
+void error(char[] msg)
+{
+    errors++;
+    debug(regexp) printf("error: %.*s\n", cast(int) msg.length, msg.ptr);
+//assert(0);
+//*(char*)0=0;
+    throw new RegExpException(msg);
+}
+
+// p is following the \ char
+int escape()
+in
+{
+    assert(p < pattern.length);
+}
+body
+{   int c;
+    int i;
+    rchar tc;
+
+    c = pattern[p];		// none of the cases are multibyte
+    switch (c)
+    {
+	case 'b':    c = '\b';	break;
+	case 'f':    c = '\f';	break;
+	case 'n':    c = '\n';	break;
+	case 'r':    c = '\r';	break;
+	case 't':    c = '\t';	break;
+	case 'v':    c = '\v';	break;
+
+	// BUG: Perl does \a and \e too, should we?
+
+	case 'c':
+	    ++p;
+	    if (p == pattern.length)
+		goto Lretc;
+	    c = pattern[p];
+	    // Note: we are deliberately not allowing dchar letters
+	    if (!(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')))
+	    {
+	     Lcerr:
+		error("letter expected following \\c");
+		return 0;
+	    }
+	    c &= 0x1F;
+	    break;
+
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	    c -= '0';
+	    for (i = 0; i < 2; i++)
+	    {
+		p++;
+		if (p == pattern.length)
+		    goto Lretc;
+		tc = pattern[p];
+		if ('0' <= tc && tc <= '7')
+		{   c = c * 8 + (tc - '0');
+		    // Treat overflow as if last
+		    // digit was not an octal digit
+		    if (c >= 0xFF)
+		    {	c >>= 3;
+			return c;
+		    }
+		}
+		else
+		    return c;
+	    }
+	    break;
+
+	case 'x':
+	    c = 0;
+	    for (i = 0; i < 2; i++)
+	    {
+		p++;
+		if (p == pattern.length)
+		    goto Lretc;
+		tc = pattern[p];
+		if ('0' <= tc && tc <= '9')
+		    c = c * 16 + (tc - '0');
+		else if ('a' <= tc && tc <= 'f')
+		    c = c * 16 + (tc - 'a' + 10);
+		else if ('A' <= tc && tc <= 'F')
+		    c = c * 16 + (tc - 'A' + 10);
+		else if (i == 0)	// if no hex digits after \x
+		{
+		    // Not a valid \xXX sequence
+		    return 'x';
+		}
+		else
+		    return c;
+	    }
+	    break;
+
+	case 'u':
+	    c = 0;
+	    for (i = 0; i < 4; i++)
+	    {
+		p++;
+		if (p == pattern.length)
+		    goto Lretc;
+		tc = pattern[p];
+		if ('0' <= tc && tc <= '9')
+		    c = c * 16 + (tc - '0');
+		else if ('a' <= tc && tc <= 'f')
+		    c = c * 16 + (tc - 'a' + 10);
+		else if ('A' <= tc && tc <= 'F')
+		    c = c * 16 + (tc - 'A' + 10);
+		else
+		{
+		    // Not a valid \uXXXX sequence
+		    p -= i;
+		    return 'u';
+		}
+	    }
+	    break;
+
+	default:
+	    break;
+    }
+    p++;
+Lretc:
+    return c;
+}
+
+/* ==================== optimizer ======================= */
+
+void optimize()
+{   ubyte[] prog;
+
+    debug(regexp) printf("RegExp.optimize()\n");
+    prog = buf.toBytes();
+    for (size_t i = 0; 1;)
+    {
+	//printf("\tprog[%d] = %d, %d\n", i, prog[i], REstring);
+	switch (prog[i])
+	{
+	    case REend:
+	    case REanychar:
+	    case REanystar:
+	    case REbackref:
+	    case REeol:
+	    case REchar:
+	    case REichar:
+	    case REdchar:
+	    case REidchar:
+	    case REstring:
+	    case REistring:
+	    case REtestbit:
+	    case REbit:
+	    case REnotbit:
+	    case RErange:
+	    case REnotrange:
+	    case REwordboundary:
+	    case REnotwordboundary:
+	    case REdigit:
+	    case REnotdigit:
+	    case REspace:
+	    case REnotspace:
+	    case REword:
+	    case REnotword:
+		return;
+
+	    case REbol:
+		i++;
+		continue;
+
+	    case REor:
+	    case REnm:
+	    case REnmq:
+	    case REparen:
+	    case REgoto:
+	    {
+		auto bitbuf = new OutBuffer;
+		auto r = new Range(bitbuf);
+		uint offset;
+
+		offset = i;
+		if (starrchars(r, prog[i .. prog.length]))
+		{
+		    debug(regexp) printf("\tfilter built\n");
+		    buf.spread(offset, 1 + 4 + r.maxb);
+		    buf.data[offset] = REtestbit;
+		    (cast(ushort *)&buf.data[offset + 1])[0] = cast(ushort)r.maxc;
+		    (cast(ushort *)&buf.data[offset + 1])[1] = cast(ushort)r.maxb;
+		    i = offset + 1 + 4;
+		    buf.data[i .. i + r.maxb] = r.base[0 .. r.maxb];
+		}
+		return;
+	    }
+	    default:
+		assert(0);
+	}
+    }
+}
+
+/////////////////////////////////////////
+// OR the leading character bits into r.
+// Limit the character range from 0..7F,
+// trymatch() will allow through anything over maxc.
+// Return 1 if success, 0 if we can't build a filter or
+// if there is no point to one.
+
+int starrchars(Range r, ubyte[] prog)
+{   rchar c;
+    uint maxc;
+    uint maxb;
+    uint len;
+    uint b;
+    uint n;
+    uint m;
+    ubyte* pop;
+
+    //printf("RegExp.starrchars(prog = %p, progend = %p)\n", prog, progend);
+    for (size_t i = 0; i < prog.length;)
+    {
+	switch (prog[i])
+	{
+	    case REchar:
+		c = prog[i + 1];
+		if (c <= 0x7F)
+		    r.setbit2(c);
+		return 1;
+
+	    case REichar:
+		c = prog[i + 1];
+		if (c <= 0x7F)
+		{   r.setbit2(c);
+		    r.setbit2(std.ctype.tolower(cast(rchar)c));
+		}
+		return 1;
+
+	    case REdchar:
+	    case REidchar:
+		return 1;
+
+	    case REanychar:
+		return 0;		// no point
+
+	    case REstring:
+		len = *cast(uint *)&prog[i + 1];
+		assert(len);
+		c = *cast(rchar *)&prog[i + 1 + uint.sizeof];
+		debug(regexp) printf("\tREstring %d, '%c'\n", len, c);
+		if (c <= 0x7F)
+		    r.setbit2(c);
+		return 1;
+
+	    case REistring:
+		len = *cast(uint *)&prog[i + 1];
+		assert(len);
+		c = *cast(rchar *)&prog[i + 1 + uint.sizeof];
+		debug(regexp) printf("\tREistring %d, '%c'\n", len, c);
+		if (c <= 0x7F)
+		{   r.setbit2(std.ctype.toupper(cast(rchar)c));
+		    r.setbit2(std.ctype.tolower(cast(rchar)c));
+		}
+		return 1;
+
+	    case REtestbit:
+	    case REbit:
+		maxc = (cast(ushort *)&prog[i + 1])[0];
+		maxb = (cast(ushort *)&prog[i + 1])[1];
+		if (maxc <= 0x7F)
+		    r.setbitmax(maxc);
+		else
+		    maxb = r.maxb;
+		for (b = 0; b < maxb; b++)
+		    r.base[b] |= prog[i + 1 + 4 + b];
+		return 1;
+
+	    case REnotbit:
+		maxc = (cast(ushort *)&prog[i + 1])[0];
+		maxb = (cast(ushort *)&prog[i + 1])[1];
+		if (maxc <= 0x7F)
+		    r.setbitmax(maxc);
+		else
+		    maxb = r.maxb;
+		for (b = 0; b < maxb; b++)
+		    r.base[b] |= ~prog[i + 1 + 4 + b];
+		return 1;
+
+	    case REbol:
+	    case REeol:
+		return 0;
+
+	    case REor:
+		len = (cast(uint *)&prog[i + 1])[0];
+		return starrchars(r, prog[i + 1 + uint.sizeof .. prog.length]) &&
+		       starrchars(r, prog[i + 1 + uint.sizeof + len .. prog.length]);
+
+	    case REgoto:
+		len = (cast(uint *)&prog[i + 1])[0];
+		i += 1 + uint.sizeof + len;
+		break;
+
+	    case REanystar:
+		return 0;
+
+	    case REnm:
+	    case REnmq:
+		// len, n, m, ()
+		len = (cast(uint *)&prog[i + 1])[0];
+		n   = (cast(uint *)&prog[i + 1])[1];
+		m   = (cast(uint *)&prog[i + 1])[2];
+		pop = &prog[i + 1 + uint.sizeof * 3];
+		if (!starrchars(r, pop[0 .. len]))
+		    return 0;
+		if (n)
+		    return 1;
+		i += 1 + uint.sizeof * 3 + len;
+		break;
+
+	    case REparen:
+		// len, ()
+		len = (cast(uint *)&prog[i + 1])[0];
+		n   = (cast(uint *)&prog[i + 1])[1];
+		pop = &prog[0] + i + 1 + uint.sizeof * 2;
+		return starrchars(r, pop[0 .. len]);
+
+	    case REend:
+		return 0;
+
+	    case REwordboundary:
+	    case REnotwordboundary:
+		return 0;
+
+	    case REdigit:
+		r.setbitmax('9');
+		for (c = '0'; c <= '9'; c++)
+		    r.bits[c] = 1;
+		return 1;
+
+	    case REnotdigit:
+		r.setbitmax(0x7F);
+		for (c = 0; c <= '0'; c++)
+		    r.bits[c] = 1;
+		for (c = '9' + 1; c <= r.maxc; c++)
+		    r.bits[c] = 1;
+		return 1;
+
+	    case REspace:
+		r.setbitmax(0x7F);
+		for (c = 0; c <= r.maxc; c++)
+		    if (isspace(c))
+			r.bits[c] = 1;
+		return 1;
+
+	    case REnotspace:
+		r.setbitmax(0x7F);
+		for (c = 0; c <= r.maxc; c++)
+		    if (!isspace(c))
+			r.bits[c] = 1;
+		return 1;
+
+	    case REword:
+		r.setbitmax(0x7F);
+		for (c = 0; c <= r.maxc; c++)
+		    if (isword(cast(rchar)c))
+			r.bits[c] = 1;
+		return 1;
+
+	    case REnotword:
+		r.setbitmax(0x7F);
+		for (c = 0; c <= r.maxc; c++)
+		    if (!isword(cast(rchar)c))
+			r.bits[c] = 1;
+		return 1;
+
+	    case REbackref:
+		return 0;
+
+	    default:
+		assert(0);
+	}
+    }
+    return 1;
+}
+
+/* ==================== replace ======================= */
+
+/***********************
+ * After a match is found with test(), this function
+ * will take the match results and, using the format
+ * string, generate and return a new string.
+ */
+
+public rchar[] replace(rchar[] format)
+{
+    return replace3(format, input, pmatch[0 .. re_nsub + 1]);
+}
+
+// Static version that doesn't require a RegExp object to be created
+
+public static rchar[] replace3(rchar[] format, rchar[] input, regmatch_t[] pmatch)
+{
+    rchar[] result;
+    uint c2;
+    int rm_so;
+    int rm_eo;
+    int i;
+
+//    printf("replace3(format = '%.*s', input = '%.*s')\n", format, input);
+    result.length = format.length;
+    result.length = 0;
+    for (size_t f = 0; f < format.length; f++)
+    {
+	auto c = format[f];
+      L1:
+	if (c != '$')
+	{
+	    result ~= c;
+	    continue;
+	}
+	++f;
+	if (f == format.length)
+	{
+	    result ~= '$';
+	    break;
+	}
+	c = format[f];
+	switch (c)
+	{
+	    case '&':
+		rm_so = pmatch[0].rm_so;
+		rm_eo = pmatch[0].rm_eo;
+		goto Lstring;
+
+	    case '`':
+		rm_so = 0;
+		rm_eo = pmatch[0].rm_so;
+		goto Lstring;
+
+	    case '\'':
+		rm_so = pmatch[0].rm_eo;
+		rm_eo = input.length;
+		goto Lstring;
+
+	    case '0': case '1': case '2': case '3': case '4':
+	    case '5': case '6': case '7': case '8': case '9':
+		i = c - '0';
+		if (f + 1 == format.length)
+		{
+		    if (i == 0)
+		    {
+			result ~= '$';
+			result ~= c;
+			continue;
+		    }
+		}
+		else
+		{
+		    c2 = format[f + 1];
+		    if (c2 >= '0' && c2 <= '9')
+		    {   i = (c - '0') * 10 + (c2 - '0');
+			f++;
+		    }
+		    if (i == 0)
+		    {
+			result ~= '$';
+			result ~= c;
+			c = cast(char)c2;
+			goto L1;
+		    }
+		}
+
+		if (i < pmatch.length)
+		{   rm_so = pmatch[i].rm_so;
+		    rm_eo = pmatch[i].rm_eo;
+		    goto Lstring;
+		}
+		break;
+
+	    Lstring:
+		if (rm_so != rm_eo)
+		    result ~= input[rm_so .. rm_eo];
+		break;
+
+	    default:
+		result ~= '$';
+		result ~= c;
+		break;
+	}
+    }
+    return result;
+}
+
+/************************************
+ * Like replace(char[] format), but uses old style formatting:
+		<table border=1 cellspacing=0 cellpadding=5>
+		<th>Format
+		<th>Description
+		<tr>
+		<td><b>&</b>
+		<td>replace with the match
+		</tr>
+		<tr>
+		<td><b>\</b><i>n</i>
+		<td>replace with the <i>n</i>th parenthesized match, <i>n</i> is 1..9
+		</tr>
+		<tr>
+		<td><b>\</b><i>c</i>
+		<td>replace with char <i>c</i>.
+		</tr>
+		</table>
+ */
+
+public rchar[] replaceOld(rchar[] format)
+{
+    rchar[] result;
+
+//printf("replace: this = %p so = %d, eo = %d\n", this, pmatch[0].rm_so, pmatch[0].rm_eo);
+//printf("3input = '%.*s'\n", input);
+    result.length = format.length;
+    result.length = 0;
+    for (size_t i; i < format.length; i++)
+    {
+	auto c = format[i];
+	switch (c)
+	{
+	    case '&':
+//printf("match = '%.*s'\n", input[pmatch[0].rm_so .. pmatch[0].rm_eo]);
+		result ~= input[pmatch[0].rm_so .. pmatch[0].rm_eo];
+		break;
+
+	    case '\\':
+		if (i + 1 < format.length)
+		{
+		    c = format[++i];
+		    if (c >= '1' && c <= '9')
+		    {   uint j;
+
+			j = c - '0';
+			if (j <= re_nsub && pmatch[j].rm_so != pmatch[j].rm_eo)
+			    result ~= input[pmatch[j].rm_so .. pmatch[j].rm_eo];
+			break;
+		    }
+		}
+		result ~= c;
+		break;
+
+	    default:
+		result ~= c;
+		break;
+	}
+    }
+    return result;
+}
+
+}
+
+unittest
+{   // Created and placed in public domain by Don Clugston
+
+    auto m = search("aBC r s", `bc\x20r[\40]s`, "i");
+    assert(m.pre=="a");
+    assert(m.match(0)=="BC r s");
+    auto m2 = search("7xxyxxx", `^\d([a-z]{2})\D\1`);
+    assert(m2.match(0)=="7xxyxx");
+    // Just check the parsing.
+    auto m3 = search("dcbxx", `ca|b[\d\]\D\s\S\w-\W]`);
+    auto m4 = search("xy", `[^\ca-\xFa\r\n\b\f\t\v\0123]{2,485}$`);
+    auto m5 = search("xxx", `^^\r\n\b{13,}\f{4}\t\v\u02aF3a\w\W`);
+    auto m6 = search("xxy", `.*y`);
+    assert(m6.match(0)=="xxy");
+    auto m7 = search("QWDEfGH", "(ca|b|defg)+", "i");
+    assert(m7.match(0)=="DEfG");
+    auto m8 = search("dcbxx", `a?\B\s\S`);
+    auto m9 = search("dcbxx", `[-w]`);
+    auto m10 = search("dcbsfd", `aB[c-fW]dB|\d|\D|\u012356|\w|\W|\s|\S`, "i");
+    auto m11 = search("dcbsfd", `[]a-]`);
+    m.replaceOld(`a&b\1c`);
+    m.replace(`a$&b$'$1c`);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/socket.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,1666 @@
+// Written in the D programming language
+
+/*
+	Copyright (C) 2004-2005 Christopher E. Miller
+	
+	This software is provided 'as-is', without any express or implied
+	warranty.  In no event will the authors be held liable for any damages
+	arising from the use of this software.
+	
+	Permission is granted to anyone to use this software for any purpose,
+	including commercial applications, and to alter it and redistribute it
+	freely, subject to the following restrictions:
+	
+	1. The origin of this software must not be misrepresented; you must not
+	   claim that you wrote the original software. If you use this software
+	   in a product, an acknowledgment in the product documentation would be
+	   appreciated but is not required.
+	2. Altered source versions must be plainly marked as such, and must not
+	   be misrepresented as being the original software.
+	3. This notice may not be removed or altered from any source
+	   distribution.
+	
+	socket.d 1.3
+	Jan 2005
+	
+	Thanks to Benjamin Herr for his assistance.
+*/
+
+/* NOTE: This file has been patched from the original DMD distribution to
+   work with the GDC compiler.
+
+   Modified by David Friedman, April 2005
+*/
+
+/**
+ * Notes: For Win32 systems, link with ws2_32.lib. 
+ * Example: See /dmd/samples/d/listener.d.
+ * Authors: Christopher E. Miller 
+ * Macros:
+ *	WIKI=Phobos/StdSocket
+ */
+
+module std.socket;
+
+private import std.string, std.stdint, std.c.string, std.c.stdlib;
+
+
+version(Unix) version = BsdSockets;
+
+version (skyos) { /* nothging */ }
+else
+{
+    version = have_getservbyport;
+    version = have_getprotobynumber;
+}
+
+    
+version(Win32)
+{
+	private import std.c.windows.windows, std.c.windows.winsock;
+	private alias std.c.windows.winsock.timeval _ctimeval;
+	
+	typedef SOCKET socket_t = INVALID_SOCKET;
+	private const int _SOCKET_ERROR = SOCKET_ERROR;
+	
+	
+	private int _lasterr()
+	{
+		return WSAGetLastError();
+	}
+}
+else version(BsdSockets)
+{
+	version (Unix)
+	{
+		version(linux) {
+			import std.c.linux.socket, std.c.linux.linux;
+			const AF_UNSPEC=0, AF_UNIX=1, AF_INET=2, AF_IPX=4, AF_APPLETALK=5;
+			const MSG_NOSIGNAL=16384;
+			const FD_SETSIZE=64;
+			alias std.c.linux.linux.timeval _ctimeval;
+		} else {
+			import std.c.unix.unix;
+			alias std.c.unix.unix.timeval _ctimeval;
+		}
+	}
+	
+	typedef int32_t socket_t = -1;
+	private const int _SOCKET_ERROR = -1;
+	
+	
+	private int _lasterr()
+	{
+		return getErrno();
+	}
+}
+else
+{
+	static assert(0); // No socket support yet.
+}
+
+
+extern(C) char* strerror_r(int errnum, char* buf, size_t buflen);
+/// Base exception thrown from a Socket.
+class SocketException: Exception
+{
+	int errorCode; /// Platform-specific error code.
+	
+	this(string msg, int err = 0)
+	{
+		errorCode = err;
+		
+		version(Unix)
+		{
+			if(errorCode > 0)
+			{
+				char[80] buf;
+				auto cs = strerror_r(errorCode, buf.ptr, buf.length);
+				auto len = strlen(cs);
+				
+				if(cs[len - 1] == '\n')
+					len--;
+				if(cs[len - 1] == '\r')
+					len--;
+				msg = msg ~ ": " ~ cs[0 .. len];
+			}
+		}
+		
+		super(msg);
+	}
+}
+
+
+static this()
+{
+	version(Win32)
+	{
+		WSADATA wd;
+		
+		// Winsock will still load if an older version is present.
+		// The version is just a request.
+		int val;
+		val = WSAStartup(0x2020, &wd);
+		if(val) // Request Winsock 2.2 for IPv6.
+			throw new SocketException("Unable to initialize socket library", val);
+	}
+}
+
+
+static ~this()
+{
+	version(Win32)
+	{
+		WSACleanup();
+	}
+}
+
+/**
+ * The communication domain used to resolve an address.
+ */
+enum AddressFamily: int
+{
+	UNSPEC =     AF_UNSPEC,	///
+	UNIX =       AF_UNIX,	/// local communication
+	INET =       AF_INET,	/// internet protocol version 4
+	IPX =        AF_IPX,	/// novell IPX
+	APPLETALK =  AF_APPLETALK,	/// appletalk
+	INET6 =      AF_INET6,	// internet protocol version 6
+}
+
+
+/**
+ * Communication semantics
+ */
+enum SocketType: int
+{
+	STREAM =     SOCK_STREAM,	/// sequenced, reliable, two-way communication-based byte streams
+	DGRAM =      SOCK_DGRAM,	/// connectionless, unreliable datagrams with a fixed maximum length; data may be lost or arrive out of order
+	RAW =        SOCK_RAW,		/// raw protocol access
+	RDM =        SOCK_RDM,		/// reliably-delivered message datagrams
+	SEQPACKET =  SOCK_SEQPACKET,	/// sequenced, reliable, two-way connection-based datagrams with a fixed maximum length
+}
+
+
+/**
+ * Protocol
+ */
+enum ProtocolType: int
+{
+	IP =    IPPROTO_IP,	/// internet protocol version 4
+	ICMP =  IPPROTO_ICMP,	/// internet control message protocol
+	IGMP =  IPPROTO_IGMP,	/// internet group management protocol
+	GGP =   IPPROTO_GGP,	/// gateway to gateway protocol
+	TCP =   IPPROTO_TCP,	/// transmission control protocol
+	PUP =   IPPROTO_PUP,	/// PARC universal packet protocol
+	UDP =   IPPROTO_UDP,	/// user datagram protocol
+	IDP =   IPPROTO_IDP,	/// Xerox NS protocol
+	IPV6 =  IPPROTO_IPV6,	/// internet protocol version 6
+}
+
+
+/**
+ * Protocol is a class for retrieving protocol information.
+ */
+class Protocol
+{
+	ProtocolType type;	/// These members are populated when one of the following functions are called without failure:
+	string name;		/// ditto
+	string[] aliases;	/// ditto
+	
+	
+	void populate(protoent* proto)
+	{
+		type = cast(ProtocolType)proto.p_proto;
+		name = std.string.toString(proto.p_name).dup;
+		
+		int i;
+		for(i = 0;; i++)
+		{
+			if(!proto.p_aliases[i])
+				break;
+		}
+		
+		if(i)
+		{
+			aliases = new string[i];
+			for(i = 0; i != aliases.length; i++)
+			{
+				aliases[i] = std.string.toString(proto.p_aliases[i]).dup;
+			}
+		}
+		else
+		{
+			aliases = null;
+		}
+	}
+	
+	/** Returns false on failure */
+	bool getProtocolByName(string name)
+	{
+		protoent* proto;
+		proto = getprotobyname(toStringz(name));
+		if(!proto)
+			return false;
+		populate(proto);
+		return true;
+	}
+	
+	
+	/** Returns false on failure */
+	// Same as getprotobynumber().
+	bool getProtocolByType(ProtocolType type)
+	{
+	    version (have_getprotobynumber)
+	    {
+		protoent* proto;
+		proto = getprotobynumber(type);
+		if(!proto)
+			return false;
+		populate(proto);
+		return true;
+	    }
+	    else
+		return false;
+	}
+}
+
+
+unittest
+{
+	Protocol proto = new Protocol;
+	assert(proto.getProtocolByType(ProtocolType.TCP));
+	printf("About protocol TCP:\n\tName: %.*s\n",
+	    cast(int) proto.name.length, proto.name.ptr);
+	foreach(string s; proto.aliases)
+	{
+	        printf("\tAlias: %.*s\n", cast(int) s.length, s.ptr);
+	}
+}
+
+
+/**
+ * Service is a class for retrieving service information.
+ */
+class Service
+{
+	/** These members are populated when one of the following functions are called without failure: */
+	string name;
+	string[] aliases;	/// ditto
+	ushort port;		/// ditto
+	string protocolName;	/// ditto
+	
+	
+	void populate(servent* serv)
+	{
+		name = std.string.toString(serv.s_name).dup;
+		port = ntohs(cast(ushort)serv.s_port);
+		protocolName = std.string.toString(serv.s_proto).dup;
+		
+		int i;
+		for(i = 0;; i++)
+		{
+			if(!serv.s_aliases[i])
+				break;
+		}
+		
+		if(i)
+		{
+			aliases = new string[i];
+			for(i = 0; i != aliases.length; i++)
+			{
+				aliases[i] = std.string.toString(serv.s_aliases[i]).dup;
+			}
+		}
+		else
+		{
+			aliases = null;
+		}
+	}
+	
+	/**
+	 * If a protocol name is omitted, any protocol will be matched.
+	 * Returns: false on failure.
+	 */
+	bool getServiceByName(string name, string protocolName)
+	{
+		servent* serv;
+		serv = getservbyname(toStringz(name), toStringz(protocolName));
+		if(!serv)
+			return false;
+		populate(serv);
+		return true;
+	}
+	
+	
+	// Any protocol name will be matched.
+	/// ditto
+	bool getServiceByName(string name)
+	{
+		servent* serv;
+		serv = getservbyname(toStringz(name), null);
+		if(!serv)
+			return false;
+		populate(serv);
+		return true;
+	}
+	
+	
+	/// ditto
+	bool getServiceByPort(ushort port, string protocolName)
+	{
+	    version (have_getservbyport)
+	    {
+		servent* serv;
+		serv = getservbyport(port, toStringz(protocolName));
+		if(!serv)
+			return false;
+		populate(serv);
+		return true;
+	    }
+	    else
+		return false;
+	}
+	
+	
+	// Any protocol name will be matched.
+	/// ditto
+	bool getServiceByPort(ushort port)
+	{
+	    version (have_getservbyport)
+	    {
+		servent* serv;
+		serv = getservbyport(port, null);
+		if(!serv)
+			return false;
+		populate(serv);
+		return true;
+	    }
+	    else
+		return false;
+	}
+}
+
+
+unittest
+{
+	Service serv = new Service;
+	if(serv.getServiceByName("epmap", "tcp"))
+	{
+		printf("About service epmap:\n\tService: %.*s\n\tPort: %d\n\tProtocol: %.*s\n",
+		        cast(int) serv.name.length, serv.name.ptr, serv.port,
+		        cast(int) serv.protocolName.length, serv.protocolName.ptr);
+		foreach(char[] s; serv.aliases)
+		{
+		        printf("\tAlias: %.*s\n", cast(int) s.length, s.ptr);
+		}
+	}
+	else
+	{
+		printf("No service for epmap.\n");
+	}
+}
+
+
+/**
+ * Base exception thrown from an InternetHost.
+ */
+class HostException: Exception
+{
+	int errorCode;	/// Platform-specific error code.
+	
+	
+	this(string msg, int err = 0)
+	{
+		errorCode = err;
+		super(msg);
+	}
+}
+
+/**
+ * InternetHost is a class for resolving IPv4 addresses.
+ */
+class InternetHost
+{
+	/** These members are populated when one of the following functions are called without failure: */
+	string name;
+	string[] aliases;	/// ditto
+	uint32_t[] addrList;	/// ditto
+	
+	
+	void validHostent(hostent* he)
+	{
+		if(he.h_addrtype != cast(int)AddressFamily.INET || he.h_length != 4)
+			throw new HostException("Address family mismatch", _lasterr());
+	}
+	
+	
+	void populate(hostent* he)
+	{
+		int i;
+		char* p;
+		
+		name = std.string.toString(he.h_name).dup;
+		
+		for(i = 0;; i++)
+		{
+			p = he.h_aliases[i];
+			if(!p)
+				break;
+		}
+		
+		if(i)
+		{
+			aliases = new string[i];
+			for(i = 0; i != aliases.length; i++)
+			{
+				aliases[i] = std.string.toString(he.h_aliases[i]).dup;
+			}
+		}
+		else
+		{
+			aliases = null;
+		}
+		
+		for(i = 0;; i++)
+		{
+			p = he.h_addr_list[i];
+			if(!p)
+				break;
+		}
+		
+		if(i)
+		{
+			addrList = new uint32_t[i];
+			for(i = 0; i != addrList.length; i++)
+			{
+				addrList[i] = ntohl(*(cast(uint32_t*)he.h_addr_list[i]));
+			}
+		}
+		else
+		{
+			addrList = null;
+		}
+	}
+	
+	/**
+	 * Resolve host name. Returns false if unable to resolve.
+	 */	
+	bool getHostByName(string name)
+	{
+		hostent* he;
+                synchronized(this.classinfo) he = gethostbyname(toStringz(name));
+		if(!he)
+			return false;
+		validHostent(he);
+		populate(he);
+		return true;
+	}
+	
+	
+	/**
+	 * Resolve IPv4 address number. Returns false if unable to resolve.
+	 */	
+	bool getHostByAddr(uint addr)
+	{
+		uint x = htonl(addr);
+		hostent* he;
+                synchronized(this.classinfo) he = gethostbyaddr(&x, 4, cast(int)AddressFamily.INET);
+		if(!he)
+			return false;
+		validHostent(he);
+		populate(he);
+		return true;
+	}
+	
+	
+	/**
+	 * Same as previous, but addr is an IPv4 address string in the
+	 * dotted-decimal form $(I a.b.c.d).
+	 * Returns false if unable to resolve.
+	 */	
+	bool getHostByAddr(string addr)
+	{
+		uint x = inet_addr(std.string.toStringz(addr));
+		hostent* he;
+                synchronized(this.classinfo) he = gethostbyaddr(&x, 4, cast(int)AddressFamily.INET);
+		if(!he)
+			return false;
+		validHostent(he);
+		populate(he);
+		return true;
+	}
+}
+
+
+unittest
+{
+	InternetHost ih = new InternetHost;
+	assert(ih.getHostByName("www.digitalmars.com"));
+	printf("addrList.length = %d\n", ih.addrList.length);
+	assert(ih.addrList.length);
+	InternetAddress ia = new InternetAddress(ih.addrList[0], InternetAddress.PORT_ANY);
+	char[] sia = ia.toAddrString();
+	printf("IPaddress = %.*s\nname = %.*s\n", cast(int) sia.length, sia.ptr,
+	    cast(int) ih.name.length, ih.name.ptr);
+	foreach(int i, string s; ih.aliases)
+	{
+	        printf("aliases[%d] = %.*s\n", i, cast(int) s.length, s.ptr);
+	}
+	
+	printf("---\n");
+	
+	assert(ih.getHostByAddr(ih.addrList[0]));
+	printf("name = %.*s\n", cast(int) ih.name.length, ih.name.ptr);
+	foreach(int i, string s; ih.aliases)
+	{
+	        printf("aliases[%d] = %.*s\n", i, cast(int) s.length, s.ptr);
+	}
+}
+
+
+/**
+ * Base exception thrown from an Address.
+ */
+class AddressException: Exception
+{
+	this(string msg)
+	{
+		super(msg);
+	}
+}
+
+
+/**
+ * Address is an abstract class for representing a network addresses.
+ */
+abstract class Address
+{
+	protected sockaddr* name();
+	protected int nameLen();
+	AddressFamily addressFamily();	/// Family of this address.
+	string toString();		/// Human readable string representing this address.
+}
+
+/**
+ *
+ */
+class UnknownAddress: Address
+{
+	protected:
+	sockaddr sa;
+	
+	
+	sockaddr* name()
+	{
+		return &sa;
+	}
+	
+	
+	int nameLen()
+	{
+		return sa.sizeof;
+	}
+	
+	
+	public:
+	AddressFamily addressFamily()
+	{
+		return cast(AddressFamily)sa.sa_family;
+	}
+	
+	
+	string toString()
+	{
+		return "Unknown";
+	}
+}
+
+
+/**
+ * InternetAddress is a class that represents an IPv4 (internet protocol version
+ * 4) address and port.
+ */
+class InternetAddress: Address
+{
+	protected:
+	sockaddr_in sin;
+
+
+	sockaddr* name()
+	{
+		return cast(sockaddr*)&sin;
+	}
+	
+	
+	int nameLen()
+	{
+		return sin.sizeof;
+	}
+	
+	
+	this()
+	{
+	}
+	
+	
+	public:
+	const uint ADDR_ANY = INADDR_ANY;	/// Any IPv4 address number.
+	const uint ADDR_NONE = INADDR_NONE;	/// An invalid IPv4 address number.
+	const ushort PORT_ANY = 0;		/// Any IPv4 port number.
+	
+	/// Overridden to return AddressFamily.INET.
+	AddressFamily addressFamily()
+	{
+		return cast(AddressFamily)AddressFamily.INET;
+	}
+	
+	/// Returns the IPv4 port number.
+	ushort port()
+	{
+		return ntohs(sin.sin_port);
+	}
+	
+	/// Returns the IPv4 address number.
+	uint addr()
+	{
+		return ntohl(sin.sin_addr.s_addr);
+	}
+	
+	/**
+	 * Params:
+	 *   addr = an IPv4 address string in the dotted-decimal form a.b.c.d,
+	 *          or a host name that will be resolved using an InternetHost
+	 *          object.
+	 *   port = may be PORT_ANY as stated below.
+	 */
+	this(string addr, ushort port)
+	{
+		uint uiaddr = parse(addr);
+		if(ADDR_NONE == uiaddr)
+		{
+			InternetHost ih = new InternetHost;
+			if(!ih.getHostByName(addr))
+				//throw new AddressException("Invalid internet address");
+				throw new AddressException("Unable to resolve host '" ~ addr ~ "'");
+			uiaddr = ih.addrList[0];
+		}
+		sin.sin_addr.s_addr = htonl(uiaddr);
+		sin.sin_port = htons(port);
+	}
+	
+	/**
+	 * Construct a new Address. addr may be ADDR_ANY (default) and port may
+	 * be PORT_ANY, and the actual numbers may not be known until a connection
+	 * is made.
+	 */
+	this(uint addr, ushort port)
+	{
+		sin.sin_addr.s_addr = htonl(addr);
+		sin.sin_port = htons(port);
+	}
+	
+	/// ditto	
+	this(ushort port)
+	{
+		sin.sin_addr.s_addr = 0; //any, "0.0.0.0"
+		sin.sin_port = htons(port);
+	}
+	
+	/// Human readable string representing the IPv4 address in dotted-decimal form.	
+	string toAddrString()
+	{
+		return std.string.toString(inet_ntoa(sin.sin_addr)).dup;
+	}
+	
+	/// Human readable string representing the IPv4 port.
+	string toPortString()
+	{
+		return std.string.toString(port());
+	}
+	
+	/// Human readable string representing the IPv4 address and port in the form $(I a.b.c.d:e).
+	string toString()
+	{
+		return toAddrString() ~ ":" ~ toPortString();
+	}
+	
+	/**
+	 * Parse an IPv4 address string in the dotted-decimal form $(I a.b.c.d)
+	 * and return the number.
+	 * If the string is not a legitimate IPv4 address,
+	 * ADDR_NONE is returned.
+	 */
+	static uint parse(string addr)
+	{
+		return ntohl(inet_addr(std.string.toStringz(addr)));
+	}
+}
+
+
+unittest
+{
+	InternetAddress ia = new InternetAddress("63.105.9.61", 80);
+	assert(ia.toString() == "63.105.9.61:80");
+}
+
+
+/** */
+class SocketAcceptException: SocketException
+{
+	this(string msg, int err = 0)
+	{
+		super(msg, err);
+	}
+}
+
+/// How a socket is shutdown:
+enum SocketShutdown: int
+{
+	RECEIVE =  SD_RECEIVE,	/// socket receives are disallowed
+	SEND =     SD_SEND,	/// socket sends are disallowed
+	BOTH =     SD_BOTH,	/// both RECEIVE and SEND
+}
+
+
+/// Flags may be OR'ed together:
+enum SocketFlags: int
+{
+	NONE =       0,             /// no flags specified 
+	
+	OOB =        MSG_OOB,       /// out-of-band stream data
+	PEEK =       MSG_PEEK,      /// peek at incoming data without removing it from the queue, only for receiving
+	DONTROUTE =  MSG_DONTROUTE, /// data should not be subject to routing; this flag may be ignored. Only for sending
+        NOSIGNAL =   MSG_NOSIGNAL,  /// don't send SIGPIPE signal on socket write error and instead return EPIPE
+}
+
+
+/// Duration timeout value.
+extern(C) struct timeval
+{
+	// D interface
+	int seconds;		/// Number of seconds.
+	int microseconds;	/// Number of additional microseconds.
+	
+	// C interface
+	deprecated
+	{
+		alias seconds tv_sec;
+		alias microseconds tv_usec;
+	}
+}
+
+
+/// A collection of sockets for use with Socket.select.
+class SocketSet
+{
+	private:
+	uint maxsockets; /// max desired sockets, the fd_set might be capable of holding more
+	fd_set set;
+	
+	
+	version(Win32)
+	{
+		uint count()
+		{
+			return set.fd_count;
+		}
+	}
+	else version(BsdSockets)
+	{
+		int maxfd;
+		uint count;
+	}
+	
+	
+	public:
+
+	/// Set the maximum amount of sockets that may be added.
+	this(uint max)
+	{
+		maxsockets = max;
+		reset();
+	}
+	
+	/// Uses the default maximum for the system.
+	this()
+	{
+		this(FD_SETSIZE);
+	}
+	
+	/// Reset the SocketSet so that there are 0 Sockets in the collection.	
+	void reset()
+	{
+		FD_ZERO(&set);
+		
+		version(BsdSockets)
+ 		{
+ 			maxfd = -1;
+			count = 0;
+ 		}
+	}
+	
+	
+	void add(socket_t s)
+	in
+	{
+		// Make sure too many sockets don't get added.
+		assert(count < maxsockets);
+		version(BsdSockets)
+		{
+			version(GNU)
+			{
+			    // Tries to account for little and big endian..er needs work
+			    // assert((s/NFDBITS+1)*NFDBITS/8 <= nbytes);
+			}
+			else
+			{
+				assert(FDELT(s) < (FD_SETSIZE / NFDBITS));
+			}
+		}
+	}
+	body
+	{
+		FD_SET(s, &set);
+		
+		version(BsdSockets)
+		{
+			++count;
+			if(s > maxfd)
+				maxfd = s;
+		}
+	}
+	
+	/// Add a Socket to the collection. Adding more than the maximum has dangerous side affects.
+	void add(Socket s)
+	{
+		add(s.sock);
+	}
+	
+	void remove(socket_t s)
+	{
+		FD_CLR(s, &set);
+		version(BsdSockets)
+		{
+			--count;
+			// note: adjusting maxfd would require scanning the set, not worth it
+		}
+	}
+	
+	
+	/// Remove this Socket from the collection.
+	void remove(Socket s)
+	{
+		remove(s.sock);
+	}
+	
+	int isSet(socket_t s)
+	{
+		return FD_ISSET(s, &set);
+	}
+	
+	
+	/// Returns nonzero if this Socket is in the collection.
+	int isSet(Socket s)
+	{
+		return isSet(s.sock);
+	}
+	
+
+	/// Return maximum amount of sockets that can be added, like FD_SETSIZE.
+	uint max()
+	{
+		return maxsockets;
+	}
+	
+	
+	fd_set* toFd_set()
+	{
+		return &set;
+	}
+	
+	
+	int selectn()
+	{
+		version(Win32)
+		{
+			return count;
+		}
+		else version(BsdSockets)
+		{
+			return maxfd + 1;
+		}
+	}
+}
+
+
+/// The level at which a socket option is defined:
+enum SocketOptionLevel: int
+{
+	SOCKET =  SOL_SOCKET,		/// socket level
+	IP =      ProtocolType.IP,	/// internet protocol version 4 level
+	ICMP =    ProtocolType.ICMP,	///
+	IGMP =    ProtocolType.IGMP,	///
+	GGP =     ProtocolType.GGP,	///
+	TCP =     ProtocolType.TCP,	/// transmission control protocol level
+	PUP =     ProtocolType.PUP,	///
+	UDP =     ProtocolType.UDP,	/// user datagram protocol level
+	IDP =     ProtocolType.IDP,	///
+	IPV6 =    ProtocolType.IPV6,	/// internet protocol version 6 level
+}
+
+
+/// Linger information for use with SocketOption.LINGER.
+extern(C) struct linger
+{
+	version (BsdSockets)
+	    version (GNU)
+	    {
+		private alias std.c.unix.unix.linger __unix_linger;
+		static assert(linger.sizeof == __unix_linger.sizeof);
+	    }
+	// D interface
+	version(Win32)
+	{
+		uint16_t on;	/// Nonzero for on.
+		uint16_t time;	/// Linger time.
+	}
+	else version(BsdSockets)
+	{
+		version (GNU)
+		{
+		    
+		    typeof(__unix_linger.l_onoff) on;
+		    typeof(__unix_linger.l_linger) time;
+		    
+		}
+		else
+		{
+		    int32_t on;
+		    int32_t time;
+		}
+	}
+	
+	// C interface
+	deprecated
+	{
+		alias on l_onoff;
+		alias time l_linger;
+	}
+}
+
+
+/// Specifies a socket option:
+enum SocketOption: int
+{
+	DEBUG =                SO_DEBUG,	/// record debugging information
+	BROADCAST =            SO_BROADCAST,	/// allow transmission of broadcast messages
+	REUSEADDR =            SO_REUSEADDR,	/// allow local reuse of address
+	LINGER =               SO_LINGER,	/// linger on close if unsent data is present
+	OOBINLINE =            SO_OOBINLINE,	/// receive out-of-band data in band
+	SNDBUF =               SO_SNDBUF,	/// send buffer size
+	RCVBUF =               SO_RCVBUF,	/// receive buffer size
+	DONTROUTE =            SO_DONTROUTE,	/// do not route
+	
+	// SocketOptionLevel.TCP:
+	TCP_NODELAY =          .TCP_NODELAY,	/// disable the Nagle algorithm for send coalescing
+	
+	// SocketOptionLevel.IPV6:
+	IPV6_UNICAST_HOPS =    .IPV6_UNICAST_HOPS,	///
+	IPV6_MULTICAST_IF =    .IPV6_MULTICAST_IF,	///
+	IPV6_MULTICAST_LOOP =  .IPV6_MULTICAST_LOOP,	///
+	IPV6_JOIN_GROUP =      .IPV6_JOIN_GROUP,	///
+	IPV6_LEAVE_GROUP =     .IPV6_LEAVE_GROUP,	///
+}
+
+
+/**
+ *  Socket is a class that creates a network communication endpoint using the
+ * Berkeley sockets interface.
+ */
+class Socket
+{
+	private:
+	socket_t sock;
+	AddressFamily _family;
+	
+	version(Win32)
+	    bool _blocking = false;	/// Property to get or set whether the socket is blocking or nonblocking.
+	
+	
+	// For use with accepting().
+	protected this()
+	{
+	}
+	
+	
+	public:
+
+	/**
+	 * Create a blocking socket. If a single protocol type exists to support
+	 * this socket type within the address family, the ProtocolType may be
+	 * omitted.
+	 */
+	this(AddressFamily af, SocketType type, ProtocolType protocol)
+	{
+		sock = cast(socket_t)socket(af, type, protocol);
+		if(sock == socket_t.init)
+			throw new SocketException("Unable to create socket", _lasterr());
+		_family = af;
+	}
+	
+	
+	// A single protocol exists to support this socket type within the
+	// protocol family, so the ProtocolType is assumed.
+	/// ditto
+	this(AddressFamily af, SocketType type)
+	{
+		this(af, type, cast(ProtocolType)0); // Pseudo protocol number.
+	}
+	
+	
+	/// ditto
+	this(AddressFamily af, SocketType type, string protocolName)
+	{
+		protoent* proto;
+		proto = getprotobyname(toStringz(protocolName));
+		if(!proto)
+			throw new SocketException("Unable to find the protocol", _lasterr());
+		this(af, type, cast(ProtocolType)proto.p_proto);
+	}
+	
+	
+	~this()
+	{
+		close();
+	}
+	
+	
+	/// Get underlying socket handle.
+	socket_t handle()
+	{
+		return sock;
+	}
+
+	/**
+	 * Get/set socket's blocking flag.
+	 *
+	 * When a socket is blocking, calls to receive(), accept(), and send()
+	 * will block and wait for data/action.
+	 * A non-blocking socket will immediately return instead of blocking. 
+	 */
+	bool blocking()
+	{
+		version(Win32)
+		{
+			return _blocking;
+		}
+		else version(BsdSockets)
+		{
+			return !(fcntl(handle, F_GETFL, 0) & O_NONBLOCK);
+		}
+	}
+	
+	/// ditto
+	void blocking(bool byes)
+	{
+		version(Win32)
+		{
+			uint num = !byes;
+			if(_SOCKET_ERROR == ioctlsocket(sock, FIONBIO, &num))
+				goto err;
+			_blocking = byes;
+		}
+		else version(BsdSockets)
+		{
+			int x = fcntl(sock, F_GETFL, 0);
+			if(-1 == x)
+				goto err;
+			if(byes)
+				x &= ~O_NONBLOCK;
+			else
+				x |= O_NONBLOCK;
+			if(-1 == fcntl(sock, F_SETFL, x))
+				goto err;
+		}
+		return; // Success.
+		
+		err:
+		throw new SocketException("Unable to set socket blocking", _lasterr());
+	}
+	
+
+	/// Get the socket's address family.	
+	AddressFamily addressFamily() // getter
+	{
+		return _family;
+	}
+	
+	/// Property that indicates if this is a valid, alive socket.
+	bool isAlive() // getter
+	{
+		int type, typesize = type.sizeof;
+		return !getsockopt(sock, SOL_SOCKET, SO_TYPE, cast(char*)&type, &typesize);
+	}
+	
+	/// Associate a local address with this socket.
+	void bind(Address addr)
+	{
+		if(_SOCKET_ERROR == .bind(sock, addr.name(), addr.nameLen()))
+			throw new SocketException("Unable to bind socket", _lasterr());
+	}
+	
+	/**
+	 * Establish a connection. If the socket is blocking, connect waits for
+	 * the connection to be made. If the socket is nonblocking, connect
+	 * returns immediately and the connection attempt is still in progress.
+	 */
+	void connect(Address to)
+	{
+		if(_SOCKET_ERROR == .connect(sock, to.name(), to.nameLen()))
+		{
+			int err;
+			err = _lasterr();
+			
+			if(!blocking)
+			{
+				version(Win32)
+				{
+					if(WSAEWOULDBLOCK == err)
+						return;
+				}
+				else version(Unix)
+				{
+					if(EINPROGRESS == err)
+						return;
+				}
+				else
+				{
+					static assert(0);
+				}
+			}
+			throw new SocketException("Unable to connect socket", err);
+		}
+	}
+	
+	/**
+	 * Listen for an incoming connection. bind must be called before you can
+	 * listen. The backlog is a request of how many pending incoming
+	 * connections are queued until accept'ed.
+	 */
+	void listen(int backlog)
+	{
+		if(_SOCKET_ERROR == .listen(sock, backlog))
+			throw new SocketException("Unable to listen on socket", _lasterr());
+	}
+	
+	/**
+	 * Called by accept when a new Socket must be created for a new
+	 * connection. To use a derived class, override this method and return an
+	 * instance of your class. The returned Socket's handle must not be set;
+	 * Socket has a protected constructor this() to use in this situation.
+	 */
+	// Override to use a derived class.
+	// The returned socket's handle must not be set.
+	protected Socket accepting()
+	{
+		return new Socket;
+	}
+	
+	/**
+	 * Accept an incoming connection. If the socket is blocking, accept
+	 * waits for a connection request. Throws SocketAcceptException if unable
+	 * to accept. See accepting for use with derived classes.
+	 */
+	Socket accept()
+	{
+		socket_t newsock;
+		//newsock = cast(socket_t).accept(sock, null, null); // DMD 0.101 error: found '(' when expecting ';' following 'statement
+		alias .accept topaccept;
+		newsock = cast(socket_t)topaccept(sock, null, null);
+		if(socket_t.init == newsock)
+			throw new SocketAcceptException("Unable to accept socket connection", _lasterr());
+		
+		Socket newSocket;
+		try
+		{
+			newSocket = accepting();
+			assert(newSocket.sock == socket_t.init);
+			
+			newSocket.sock = newsock;
+			version(Win32)
+				newSocket._blocking = _blocking; //inherits blocking mode
+			newSocket._family = _family; //same family
+		}
+		catch(Object o)
+		{
+			_close(newsock);
+			throw o;
+		}
+		
+		return newSocket;
+	}
+	
+	/// Disables sends and/or receives.
+	void shutdown(SocketShutdown how)
+	{
+		.shutdown(sock, cast(int)how);
+	}
+	
+	
+	private static void _close(socket_t sock)
+	{
+		version(Win32)
+		{
+			.closesocket(sock);
+		}
+		else version(BsdSockets)
+		{
+			.close(sock);
+		}
+	}
+	
+
+	/**
+	 * Immediately drop any connections and release socket resources.
+	 * Calling shutdown before close is recommended for connection-oriented
+	 * sockets. The Socket object is no longer usable after close.
+	 */
+	//calling shutdown() before this is recommended
+	//for connection-oriented sockets
+	void close()
+	{
+		_close(sock);
+		sock = socket_t.init;
+	}
+	
+	
+	private Address newFamilyObject()
+	{
+		Address result;
+		switch(_family)
+		{
+			case cast(AddressFamily)AddressFamily.INET:
+				result = new InternetAddress;
+				break;
+			
+			default:
+				result = new UnknownAddress;
+		}
+		return result;
+	}
+	
+	
+	/// Returns the local machine's host name. Idea from mango.
+	static string hostName() // getter
+	{
+		char[256] result; // Host names are limited to 255 chars.
+		if(_SOCKET_ERROR == .gethostname(result.ptr, result.length))
+			throw new SocketException("Unable to obtain host name", _lasterr());
+		return std.string.toString(cast(char*)result).dup;
+	}
+	
+	/// Remote endpoint Address.
+	Address remoteAddress()
+	{
+		Address addr = newFamilyObject();
+		int nameLen = addr.nameLen();
+		if(_SOCKET_ERROR == .getpeername(sock, addr.name(), &nameLen))
+			throw new SocketException("Unable to obtain remote socket address", _lasterr());
+		assert(addr.addressFamily() == _family);
+		return addr;
+	}
+	
+	/// Local endpoint Address.
+	Address localAddress()
+	{
+		Address addr = newFamilyObject();
+		int nameLen = addr.nameLen();
+		if(_SOCKET_ERROR == .getsockname(sock, addr.name(), &nameLen))
+			throw new SocketException("Unable to obtain local socket address", _lasterr());
+		assert(addr.addressFamily() == _family);
+		return addr;
+	}
+	
+	/// Send or receive error code.
+	const int ERROR = _SOCKET_ERROR;
+	
+	/**
+	 * Send data on the connection. Returns the number of bytes actually
+	 * sent, or ERROR on failure. If the socket is blocking and there is no
+	 * buffer space left, send waits.
+	 */
+	//returns number of bytes actually sent, or -1 on error
+	int send(void[] buf, SocketFlags flags)
+	{
+                flags |= SocketFlags.NOSIGNAL;
+		int sent = .send(sock, buf.ptr, buf.length, cast(int)flags);
+		return sent;
+	}
+	
+	/// ditto
+	int send(void[] buf)
+	{
+		return send(buf, SocketFlags.NOSIGNAL);
+	}
+	
+	/**
+	 * Send data to a specific destination Address. If the destination address is not specified, a connection must have been made and that address is used. If the socket is blocking and there is no buffer space left, sendTo waits.
+	 */
+	int sendTo(void[] buf, SocketFlags flags, Address to)
+	{
+                flags |= SocketFlags.NOSIGNAL;
+		int sent = .sendto(sock, buf.ptr, buf.length, cast(int)flags, to.name(), to.nameLen());
+		return sent;
+	}
+	
+	/// ditto
+	int sendTo(void[] buf, Address to)
+	{
+		return sendTo(buf, SocketFlags.NONE, to);
+	}
+	
+	
+	//assumes you connect()ed
+	/// ditto
+	int sendTo(void[] buf, SocketFlags flags)
+	{
+                flags |= SocketFlags.NOSIGNAL;
+		int sent = .sendto(sock, buf.ptr, buf.length, cast(int)flags, null, 0);
+		return sent;
+	}
+	
+	
+	//assumes you connect()ed
+	/// ditto
+	int sendTo(void[] buf)
+	{
+		return sendTo(buf, SocketFlags.NONE);
+	}
+	
+
+	/**
+	 * Receive data on the connection. Returns the number of bytes actually
+	 * received, 0 if the remote side has closed the connection, or ERROR on
+	 * failure. If the socket is blocking, receive waits until there is data
+	 * to be received.
+	 */
+	//returns number of bytes actually received, 0 on connection closure, or -1 on error
+	int receive(void[] buf, SocketFlags flags)
+	{
+		if(!buf.length) //return 0 and don't think the connection closed
+			return 0;
+		int read = .recv(sock, buf.ptr, buf.length, cast(int)flags);
+		// if(!read) //connection closed
+		return read;
+	}
+	
+	/// ditto
+	int receive(void[] buf)
+	{
+		return receive(buf, SocketFlags.NONE);
+	}
+	
+	/**
+	 * Receive data and get the remote endpoint Address.
+	 * If the socket is blocking, receiveFrom waits until there is data to
+	 * be received.
+	 * Returns: the number of bytes actually received,
+	 * 0 if the remote side has closed the connection, or ERROR on failure.
+	 */
+	int receiveFrom(void[] buf, SocketFlags flags, out Address from)
+	{
+		if(!buf.length) //return 0 and don't think the connection closed
+			return 0;
+		from = newFamilyObject();
+		int nameLen = from.nameLen();
+		int read = .recvfrom(sock, buf.ptr, buf.length, cast(int)flags, from.name(), &nameLen);
+		assert(from.addressFamily() == _family);
+		// if(!read) //connection closed
+		return read;
+	}
+	
+	
+	/// ditto
+	int receiveFrom(void[] buf, out Address from)
+	{
+		return receiveFrom(buf, SocketFlags.NONE, from);
+	}
+	
+	
+	//assumes you connect()ed
+	/// ditto
+	int receiveFrom(void[] buf, SocketFlags flags)
+	{
+		if(!buf.length) //return 0 and don't think the connection closed
+			return 0;
+		int read = .recvfrom(sock, buf.ptr, buf.length, cast(int)flags, null, null);
+		// if(!read) //connection closed
+		return read;
+	}
+	
+	
+	//assumes you connect()ed
+	/// ditto
+	int receiveFrom(void[] buf)
+	{
+		return receiveFrom(buf, SocketFlags.NONE);
+	}
+	
+
+	/// Get a socket option. Returns the number of bytes written to result.	
+	//returns the length, in bytes, of the actual result - very different from getsockopt()
+	int getOption(SocketOptionLevel level, SocketOption option, void[] result)
+	{
+		int len = result.length;
+		if(_SOCKET_ERROR == .getsockopt(sock, cast(int)level, cast(int)option, result.ptr, &len))
+			throw new SocketException("Unable to get socket option", _lasterr());
+		return len;
+	}
+	
+
+	/// Common case of getting integer and boolean options.	
+	int getOption(SocketOptionLevel level, SocketOption option, out int32_t result)
+	{
+		return getOption(level, option, (&result)[0 .. 1]);
+	}
+
+
+	/// Get the linger option.	
+	int getOption(SocketOptionLevel level, SocketOption option, out linger result)
+	{
+		//return getOption(cast(SocketOptionLevel)SocketOptionLevel.SOCKET, SocketOption.LINGER, (&result)[0 .. 1]);
+		return getOption(level, option, (&result)[0 .. 1]); 
+	}
+	
+	// Set a socket option.
+	void setOption(SocketOptionLevel level, SocketOption option, void[] value)
+	{
+		if(_SOCKET_ERROR == .setsockopt(sock, cast(int)level, cast(int)option, value.ptr, value.length))
+			throw new SocketException("Unable to set socket option", _lasterr());
+	}
+	
+	
+	/// Common case for setting integer and boolean options.
+	void setOption(SocketOptionLevel level, SocketOption option, int32_t value)
+	{
+		setOption(level, option, (&value)[0 .. 1]);
+	}
+
+
+	/// Set the linger option.
+	void setOption(SocketOptionLevel level, SocketOption option, linger value)
+	{
+		//setOption(cast(SocketOptionLevel)SocketOptionLevel.SOCKET, SocketOption.LINGER, (&value)[0 .. 1]);
+		setOption(level, option, (&value)[0 .. 1]);
+	}
+	
+
+	/**
+	 * Wait for a socket to change status. A wait timeout timeval or int microseconds may be specified; if a timeout is not specified or the timeval is null, the maximum timeout is used. The timeval timeout has an unspecified value when select returns. Returns the number of sockets with status changes, 0 on timeout, or -1 on interruption. If the return value is greater than 0, the SocketSets are updated to only contain the sockets having status changes. For a connecting socket, a write status change means the connection is established and it's able to send. For a listening socket, a read status change means there is an incoming connection request and it's able to accept.
+	 */
+	//SocketSet's updated to include only those sockets which an event occured
+	//returns the number of events, 0 on timeout, or -1 on interruption
+	//for a connect()ing socket, writeability means connected
+	//for a listen()ing socket, readability means listening
+	//Winsock: possibly internally limited to 64 sockets per set
+	static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, timeval* tv)
+	in
+	{
+		//make sure none of the SocketSet's are the same object
+		if(checkRead)
+		{
+			assert(checkRead !is checkWrite);
+			assert(checkRead !is checkError);
+		}
+		if(checkWrite)
+		{
+			assert(checkWrite !is checkError);
+		}
+	}
+	body
+	{
+		fd_set* fr, fw, fe;
+		int n = 0;
+		
+		version(Win32)
+		{
+			// Windows has a problem with empty fd_set`s that aren't null.
+			fr = (checkRead && checkRead.count()) ? checkRead.toFd_set() : null;
+			fw = (checkWrite && checkWrite.count()) ? checkWrite.toFd_set() : null;
+			fe = (checkError && checkError.count()) ? checkError.toFd_set() : null;
+		}
+		else
+		{
+			if(checkRead)
+			{
+				fr = checkRead.toFd_set();
+				n = checkRead.selectn();
+			}
+			else
+			{
+				fr = null;
+			}
+			
+			if(checkWrite)
+			{
+				fw = checkWrite.toFd_set();
+				int _n;
+				_n = checkWrite.selectn();
+				if(_n > n)
+					n = _n;
+			}
+			else
+			{
+				fw = null;
+			}
+			
+			if(checkError)
+			{
+				fe = checkError.toFd_set();
+				int _n;
+				_n = checkError.selectn();
+				if(_n > n)
+					n = _n;
+			}
+			else
+			{
+				fe = null;
+			}
+		}
+		
+		int result = .select(n, fr, fw, fe, cast(_ctimeval*)tv);
+		
+		version(Win32)
+		{
+			if(_SOCKET_ERROR == result && WSAGetLastError() == WSAEINTR)
+				return -1;
+		}
+		else version(Unix)
+		{
+			if(_SOCKET_ERROR == result && getErrno() == EINTR)
+				return -1;
+		}
+		else
+		{
+			static assert(0);
+		}
+		
+		if(_SOCKET_ERROR == result)
+			throw new SocketException("Socket select error", _lasterr());
+		
+		return result;
+	}
+
+
+	/// ditto
+	static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, int microseconds)
+	{
+		timeval tv;
+		tv.seconds = 0;
+		tv.microseconds = microseconds;
+		return select(checkRead, checkWrite, checkError, &tv);
+	}
+	
+	
+	/// ditto
+	//maximum timeout
+	static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError)
+	{
+		return select(checkRead, checkWrite, checkError, null);
+	}
+	
+	
+	/+
+	bool poll(events)
+	{
+		int WSAEventSelect(socket_t s, WSAEVENT hEventObject, int lNetworkEvents); // Winsock 2 ?
+		int poll(pollfd* fds, int nfds, int timeout); // Unix ?
+	}
+	+/
+}
+
+
+/// TcpSocket is a shortcut class for a TCP Socket.
+class TcpSocket: Socket
+{
+	/// Constructs a blocking TCP Socket.
+	this(AddressFamily family)
+	{
+		super(family, SocketType.STREAM, ProtocolType.TCP);
+	}
+	
+	/// Constructs a blocking TCP Socket.
+	this()
+	{
+		this(cast(AddressFamily)AddressFamily.INET);
+	}
+	
+	
+	//shortcut
+	/// Constructs a blocking TCP Socket and connects to an InternetAddress.
+	this(Address connectTo)
+	{
+		this(connectTo.addressFamily());
+		connect(connectTo);
+	}
+}
+
+
+/// UdpSocket is a shortcut class for a UDP Socket.
+class UdpSocket: Socket
+{
+	/// Constructs a blocking UDP Socket.
+	this(AddressFamily family)
+	{
+		super(family, SocketType.DGRAM, ProtocolType.UDP);
+	}
+	
+	
+	/// Constructs a blocking UDP Socket.
+	this()
+	{
+		this(cast(AddressFamily)AddressFamily.INET);
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/stream.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,2961 @@
+/**
+ * Macros:
+ *	WIKI = Phobos/StdStream
+ */
+
+/*
+ * Copyright (c) 2001-2005
+ * Pavel "EvilOne" Minayev
+ *  with buffering and endian support added by Ben Hinkle
+ *  with buffered readLine performance improvements by Dave Fladebo
+ *  with opApply inspired by (and mostly copied from) Regan Heath
+ *  with bug fixes and MemoryStream/SliceStream enhancements by Derick Eddington
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation.  Author makes no representations about
+ * the suitability of this software for any purpose. It is provided
+ * "as is" without express or implied warranty.
+ */
+
+/* NOTE: This file has been patched from the original DMD distribution to
+   work with the GDC compiler.
+
+   Modified by David Friedman, April 2005
+*/
+
+module std.stream;
+
+/* Class structure:
+ *  InputStream       interface for reading
+ *  OutputStream      interface for writing
+ *  Stream            abstract base of stream implementations
+ *    File            an OS file stream
+ *    FilterStream    a base-class for wrappers around another stream
+ *      BufferedStream  a buffered stream wrapping another stream
+ *        BufferedFile  a buffered File
+ *      EndianStream    a wrapper stream for swapping byte order and BOMs
+ *      SliceStream     a portion of another stream
+ *    MemoryStream    a stream entirely stored in main memory
+ *    TArrayStream    a stream wrapping an array-like buffer
+ */
+
+/// A base class for stream exceptions.
+class StreamException: Exception {
+  /// Construct a StreamException with given error message.
+  this(char[] msg) { super(msg); }
+}
+
+/// Thrown when unable to read data from Stream.
+class ReadException: StreamException {
+  /// Construct a ReadException with given error message.
+  this(char[] msg) { super(msg); }
+}
+
+/// Thrown when unable to write data to Stream.
+class WriteException: StreamException {
+  /// Construct a WriteException with given error message.
+  this(char[] msg) { super(msg); }
+}
+
+/// Thrown when unable to move Stream pointer.
+class SeekException: StreamException {
+  /// Construct a SeekException with given error message.
+  this(char[] msg) { super(msg); }
+}
+
+// seek whence...
+enum SeekPos {
+  Set,
+  Current,
+  End
+}
+
+private {
+  import std.format;
+  import std.system;    // for Endian enumeration
+  import std.intrinsic; // for bswap
+  import std.utf;
+  import std.stdarg;
+}
+
+version (Windows) {
+  private import std.file;
+}
+
+/// InputStream is the interface for readable streams.
+
+interface InputStream {
+
+  /***
+   * Read exactly size bytes into the buffer.
+   *
+   * Throws a ReadException if it is not correct.
+   */
+  void readExact(void* buffer, size_t size);
+
+  /***
+   * Read a block of data big enough to fill the given array buffer.
+   *
+   * Returns: the actual number of bytes read. Unfilled bytes are not modified. 
+   */
+  size_t read(ubyte[] buffer);
+
+  /***
+   * Read a basic type or counted string.
+   *
+   * Throw a ReadException if it could not be read.
+   * Outside of byte, ubyte, and char, the format is
+   * implementation-specific and should not be used except as opposite actions
+   * to write.
+   */
+  void read(out byte x);
+  void read(out ubyte x);	/// ditto
+  void read(out short x);	/// ditto
+  void read(out ushort x);	/// ditto
+  void read(out int x);		/// ditto
+  void read(out uint x);	/// ditto
+  void read(out long x);	/// ditto
+  void read(out ulong x);	/// ditto
+  void read(out float x);	/// ditto
+  void read(out double x);	/// ditto
+  void read(out real x);	/// ditto
+  void read(out ifloat x);	/// ditto
+  void read(out idouble x);	/// ditto
+  void read(out ireal x);	/// ditto
+  void read(out cfloat x);	/// ditto
+  void read(out cdouble x);	/// ditto
+  void read(out creal x);	/// ditto
+  void read(out char x);	/// ditto
+  void read(out wchar x);	/// ditto
+  void read(out dchar x);	/// ditto
+
+  // reads a string, written earlier by write()
+  void read(out char[] s);	/// ditto
+
+  // reads a Unicode string, written earlier by write()
+  void read(out wchar[] s);	/// ditto
+
+  /***
+   * Read a line that is terminated with some combination of carriage return and
+   * line feed or end-of-file.
+   *
+   * The terminators are not included. The wchar version
+   * is identical. The optional buffer parameter is filled (reallocating
+   * it if necessary) and a slice of the result is returned. 
+   */
+  char[] readLine();
+  char[] readLine(char[] result);	/// ditto
+  wchar[] readLineW();			/// ditto
+  wchar[] readLineW(wchar[] result);	/// ditto
+
+  /***
+   * Overload foreach statements to read the stream line by line and call the
+   * supplied delegate with each line or with each line with line number.
+   *
+   * The string passed in line may be reused between calls to the delegate.
+   * Line numbering starts at 1.
+   * Breaking out of the foreach will leave the stream
+   * position at the beginning of the next line to be read.
+   * For example, to echo a file line-by-line with line numbers run:
+   * ------------------------------------
+   * Stream file = new BufferedFile("sample.txt");
+   * foreach(ulong n, char[] line; file) {
+   *   stdout.writefln("line %d: %s",n,line);
+   * }
+   * file.close();
+   * ------------------------------------
+   */
+
+  // iterate through the stream line-by-line
+  int opApply(int delegate(inout char[] line) dg);
+  int opApply(int delegate(inout ulong n, inout char[] line) dg);  /// ditto
+  int opApply(int delegate(inout wchar[] line) dg);		   /// ditto
+  int opApply(int delegate(inout ulong n, inout wchar[] line) dg); /// ditto
+
+  /// Read a string of the given length,
+  /// throwing ReadException if there was a problem.
+  char[] readString(size_t length);
+
+  /***
+   * Read a string of the given length, throwing ReadException if there was a
+   * problem.
+   *
+   * The file format is implementation-specific and should not be used
+   * except as opposite actions to <b>write</b>.
+   */
+
+  wchar[] readStringW(size_t length);
+
+  /***
+   * Read and return the next character in the stream.
+   *
+   * This is the only method that will handle ungetc properly.
+   * getcw's format is implementation-specific.
+   * If EOF is reached then getc returns char.init and getcw returns wchar.init.
+   */
+
+  // pushes back character c into the stream; only has
+  // effect on further calls to getc() and getcw()
+  char getc();
+  wchar getcw(); /// ditto
+
+  /***
+   * Push a character back onto the stream.
+   *
+   * They will be returned in first-in last-out order from getc/getcw.
+   * Only has effect on further calls to getc() and getcw().
+   */
+  char ungetc(char c);
+  wchar ungetcw(wchar c); /// ditto
+
+  /***
+   * Scan a string from the input using a similar form to C's scanf
+   * and <a href="std_format.html">std.format</a>.
+   *
+   * An argument of type char[] is interpreted as a format string.
+   * All other arguments must be pointer types.
+   * If a format string is not present a default will be supplied computed from
+   * the base type of the pointer type. An argument of type char[]* is filled
+   * (possibly with appending characters) and a slice of the result is assigned
+   * back into the argument. For example the following readf statements
+   * are equivalent:
+   * --------------------------
+   * int x;
+   * double y;
+   * char[] s;
+   * file.readf(&x, " hello ", &y, &s);
+   * file.readf("%d hello %f %s", &x, &y, &s);
+   * file.readf("%d hello %f", &x, &y, "%s", &s);
+   * --------------------------
+   */
+  int vreadf(TypeInfo[] arguments, va_list args);
+  int readf(...); /// ditto
+
+  /// Retrieve the number of bytes available for immediate reading.
+  size_t available();
+
+  /***
+   * Return whether the current file position is the same as the end of the
+   * file.
+   *
+   * This does not require actually reading past the end, as with stdio. For
+   * non-seekable streams this might only return true after attempting to read
+   * past the end.
+   */
+
+  bool eof();
+
+  bool isOpen();	/// Return true if the stream is currently open.
+}
+
+/// Interface for writable streams.
+interface OutputStream {
+
+  /***
+   * Write exactly size bytes from buffer, or throw a WriteException if that
+   * could not be done.
+   */
+  void writeExact(void* buffer, size_t size);
+
+  /***
+   * Write as much of the buffer as possible,
+   * returning the number of bytes written.
+   */
+  size_t write(ubyte[] buffer);
+
+  /***
+   * Write a basic type.
+   *
+   * Outside of byte, ubyte, and char, the format is implementation-specific
+   * and should only be used in conjunction with read.
+   * Throw WriteException on error.
+   */
+  void write(byte x);
+  void write(ubyte x);		/// ditto
+  void write(short x);		/// ditto
+  void write(ushort x);		/// ditto
+  void write(int x);		/// ditto
+  void write(uint x);		/// ditto
+  void write(long x);		/// ditto
+  void write(ulong x);		/// ditto
+  void write(float x);		/// ditto
+  void write(double x);		/// ditto
+  void write(real x);		/// ditto
+  void write(ifloat x);		/// ditto
+  void write(idouble x);	/// ditto
+  void write(ireal x);		/// ditto
+  void write(cfloat x);		/// ditto
+  void write(cdouble x);	/// ditto
+  void write(creal x);		/// ditto
+  void write(char x);		/// ditto
+  void write(wchar x);		/// ditto
+  void write(dchar x);		/// ditto
+
+  /***
+   * Writes a string, together with its length.
+   *
+   * The format is implementation-specific
+   * and should only be used in conjunction with read.
+   * Throw WriteException on error.
+   */
+  void write(char[] s);
+  void write(wchar[] s);	/// ditto
+
+  /***
+   * Write a line of text,
+   * appending the line with an operating-system-specific line ending.
+   *
+   * Throws WriteException on error.
+   */
+  void writeLine(char[] s);
+
+  /***
+   * Write a line of text,
+   * appending the line with an operating-system-specific line ending.
+   *
+   * The format is implementation-specific.
+   * Throws WriteException on error.
+   */
+  void writeLineW(wchar[] s);
+
+  /***
+   * Write a string of text.
+   *
+   * Throws WriteException if it could not be fully written.
+   */
+  void writeString(char[] s);
+
+  /***
+   * Write a string of text.
+   *
+   * The format is implementation-specific.
+   * Throws WriteException if it could not be fully written.
+   */
+  void writeStringW(wchar[] s);
+
+  /***
+   * Print a formatted string into the stream using printf-style syntax,
+   * returning the number of bytes written.
+   */
+  size_t vprintf(char[] format, va_list args);
+  size_t printf(char[] format, ...);	/// ditto
+
+  /***
+   * Print a formatted string into the stream using writef-style syntax.
+   * References: <a href="std_format.html">std.format</a>.
+   * Returns: self to chain with other stream commands like flush.
+   */
+  OutputStream writef(...);
+  OutputStream writefln(...); /// ditto
+  OutputStream writefx(TypeInfo[] arguments, va_list argptr, int newline = false);  /// ditto
+
+  void flush();	/// Flush pending output if appropriate.
+  void close(); /// Close the stream, flushing output if appropriate.
+  bool isOpen(); /// Return true if the stream is currently open.
+}
+
+/***
+ * Stream is the base abstract class from which the other stream classes derive.
+ * 
+ * Stream's byte order is the format native to the computer.
+ *
+ * Reading:
+ * These methods require that the readable flag be set.
+ * Problems with reading result in a ReadException being thrown.
+ * Stream implements the InputStream interface in addition to the
+ * readBlock method.
+ *
+ * Writing:
+ * These methods require that the writeable flag be set. Problems with writing
+ * result in a WriteException being thrown. Stream implements the OutputStream
+ * interface in addition to the following methods:
+ * writeBlock
+ * copyFrom
+ * copyFrom
+ *
+ * Seeking:
+ * These methods require that the seekable flag be set.
+ * Problems with seeking result in a SeekException being thrown.
+ * seek, seekSet, seekCur, seekEnd, position, size, toString, toHash
+ */
+
+// not really abstract, but its instances will do nothing useful
+class Stream : InputStream, OutputStream {
+  private import std.string, crc32, std.c.stdlib, std.c.stdio, std.c.stdarg;
+
+  // stream abilities
+  bool readable = false;	/// Indicates whether this stream can be read from.
+  bool writeable = false;	/// Indicates whether this stream can be written to.
+  bool seekable = false;	/// Indicates whether this stream can be seeked within.
+  protected bool isopen = true;	/// Indicates whether this stream is open.
+
+  protected bool readEOF = false; /** Indicates whether this stream is at eof
+				   * after the last read attempt.
+				   */
+
+  protected bool prevCr = false; /** For a non-seekable stream indicates that
+				  * the last readLine or readLineW ended on a
+				  * '\r' character. 
+				  */
+
+  this() {}
+
+  /***
+   * Read up to size bytes into the buffer and return the number of bytes
+   * actually read. A return value of 0 indicates end-of-file.
+   */
+  abstract size_t readBlock(void* buffer, size_t size);
+
+  // reads block of data of specified size,
+  // throws ReadException on error
+  void readExact(void* buffer, size_t size) {
+    for(;;) {
+      if (!size) return;
+      size_t readsize = readBlock(buffer, size); // return 0 on eof
+      if (readsize == 0) break;
+      buffer += readsize;
+      size -= readsize;
+    }
+    if (size != 0)
+      throw new ReadException("not enough data in stream");
+  }
+
+  // reads block of data big enough to fill the given
+  // array, returns actual number of bytes read
+  size_t read(ubyte[] buffer) {
+    return readBlock(buffer.ptr, buffer.length);
+  }
+
+  // read a single value of desired type,
+  // throw ReadException on error
+  void read(out byte x) { readExact(&x, x.sizeof); }
+  void read(out ubyte x) { readExact(&x, x.sizeof); }
+  void read(out short x) { readExact(&x, x.sizeof); }
+  void read(out ushort x) { readExact(&x, x.sizeof); }
+  void read(out int x) { readExact(&x, x.sizeof); }
+  void read(out uint x) { readExact(&x, x.sizeof); }
+  void read(out long x) { readExact(&x, x.sizeof); }
+  void read(out ulong x) { readExact(&x, x.sizeof); }
+  void read(out float x) { readExact(&x, x.sizeof); }
+  void read(out double x) { readExact(&x, x.sizeof); }
+  void read(out real x) { readExact(&x, x.sizeof); }
+  void read(out ifloat x) { readExact(&x, x.sizeof); }
+  void read(out idouble x) { readExact(&x, x.sizeof); }
+  void read(out ireal x) { readExact(&x, x.sizeof); }
+  void read(out cfloat x) { readExact(&x, x.sizeof); }
+  void read(out cdouble x) { readExact(&x, x.sizeof); }
+  void read(out creal x) { readExact(&x, x.sizeof); }
+  void read(out char x) { readExact(&x, x.sizeof); }
+  void read(out wchar x) { readExact(&x, x.sizeof); }
+  void read(out dchar x) { readExact(&x, x.sizeof); }
+
+  // reads a string, written earlier by write()
+  void read(out char[] s) {
+    size_t len;
+    read(len);
+    s = readString(len);
+  }
+
+  // reads a Unicode string, written earlier by write()
+  void read(out wchar[] s) {
+    size_t len;
+    read(len);
+    s = readStringW(len);
+  }
+
+  // reads a line, terminated by either CR, LF, CR/LF, or EOF
+  char[] readLine() {
+    return readLine(null);
+  }
+
+  // reads a line, terminated by either CR, LF, CR/LF, or EOF
+  // reusing the memory in buffer if result will fit and otherwise
+  // allocates a new string
+  char[] readLine(char[] result) {
+    size_t strlen = 0;
+    char ch = getc();
+    while (readable) {
+      switch (ch) {
+      case '\r':
+	if (seekable) {
+	  ch = getc();
+	  if (ch != '\n')
+	    ungetc(ch);
+	} else {
+	  prevCr = true;
+	}
+      case '\n':
+      case char.init:
+	result.length = strlen;
+	return result;
+
+      default:
+	if (strlen < result.length) {
+	  result[strlen] = ch;
+	} else {
+	  result ~= ch;
+	}
+	strlen++;
+      }
+      ch = getc();
+    }
+    result.length = strlen;
+    return result;
+  }
+
+  // reads a Unicode line, terminated by either CR, LF, CR/LF,
+  // or EOF; pretty much the same as the above, working with
+  // wchars rather than chars
+  wchar[] readLineW() {
+    return readLineW(null);
+  }
+
+  // reads a Unicode line, terminated by either CR, LF, CR/LF,
+  // or EOF;
+  // fills supplied buffer if line fits and otherwise allocates a new string.
+  wchar[] readLineW(wchar[] result) {
+    size_t strlen = 0;
+    wchar c = getcw();
+    while (readable) {
+      switch (c) {
+      case '\r':
+	if (seekable) {
+	  c = getcw();
+	  if (c != '\n')
+	    ungetcw(c);
+	} else {
+	  prevCr = true;
+	}
+      case '\n':
+      case wchar.init:
+	result.length = strlen;
+	return result;
+
+      default:
+	if (strlen < result.length) {
+	  result[strlen] = c;
+	} else {
+	  result ~= c;
+	}
+	strlen++;
+      }
+      c = getcw();
+    }
+    result.length = strlen;
+    return result;
+  }
+
+  // iterate through the stream line-by-line - due to Regan Heath
+  int opApply(int delegate(inout char[] line) dg) {
+    int res = 0;
+    char[128] buf;
+    while (!eof()) {
+      char[] line = readLine(buf);
+      res = dg(line);
+      if (res) break;
+    }
+    return res;
+  }
+
+  // iterate through the stream line-by-line with line count and char[]
+  int opApply(int delegate(inout ulong n, inout char[] line) dg) {
+    int res = 0;
+    ulong n = 1;
+    char[128] buf;
+    while (!eof()) {
+      char[] line = readLine(buf);
+      res = dg(n,line);
+      if (res) break;
+      n++;
+    }
+    return res;
+  }
+
+  // iterate through the stream line-by-line with wchar[]
+  int opApply(int delegate(inout wchar[] line) dg) {
+    int res = 0;
+    wchar[128] buf;
+    while (!eof()) {
+      wchar[] line = readLineW(buf);
+      res = dg(line);
+      if (res) break;
+    }
+    return res;
+  }
+
+  // iterate through the stream line-by-line with line count and wchar[]
+  int opApply(int delegate(inout ulong n, inout wchar[] line) dg) {
+    int res = 0;
+    ulong n = 1;
+    wchar[128] buf;
+    while (!eof()) {
+      wchar[] line = readLineW(buf);
+      res = dg(n,line);
+      if (res) break;
+      n++;
+    }
+    return res;
+  }
+
+  // reads a string of given length, throws
+  // ReadException on error
+  char[] readString(size_t length) {
+    char[] result = new char[length];
+    readExact(result.ptr, length);
+    return result;
+  }
+
+  // reads a Unicode string of given length, throws
+  // ReadException on error
+  wchar[] readStringW(size_t length) {
+    wchar[] result = new wchar[length];
+    readExact(result.ptr, result.length * wchar.sizeof);
+    return result;
+  }
+
+  // unget buffer
+  private wchar[] unget;
+  final bool ungetAvailable() { return unget.length > 1; }
+
+  // reads and returns next character from the stream,
+  // handles characters pushed back by ungetc()
+  // returns char.init on eof.
+  char getc() {
+    char c;
+    if (prevCr) {
+      prevCr = false;
+      c = getc();
+      if (c != '\n') 
+	return c;
+    }
+    if (unget.length > 1) {
+      c = cast(char)unget[unget.length - 1];
+      unget.length = unget.length - 1;
+    } else {
+      readBlock(&c,1);
+    }
+    return c;
+  }
+
+  // reads and returns next Unicode character from the
+  // stream, handles characters pushed back by ungetc()
+  // returns wchar.init on eof.
+  wchar getcw() {
+    wchar c;
+    if (prevCr) {
+      prevCr = false;
+      c = getcw();
+      if (c != '\n') 
+	return c;
+    }
+    if (unget.length > 1) {
+      c = unget[unget.length - 1];
+      unget.length = unget.length - 1;
+    } else {
+      void* buf = &c;
+      size_t n = readBlock(buf,2);
+      if (n == 1 && readBlock(buf+1,1) == 0)
+          throw new ReadException("not enough data in stream");
+    }
+    return c;
+  }
+
+  // pushes back character c into the stream; only has
+  // effect on further calls to getc() and getcw()
+  char ungetc(char c) {
+    if (c == c.init) return c;
+    // first byte is a dummy so that we never set length to 0
+    if (unget.length == 0)
+      unget.length = 1;
+    unget ~= c;
+    return c;
+  }
+
+  // pushes back Unicode character c into the stream; only
+  // has effect on further calls to getc() and getcw()
+  wchar ungetcw(wchar c) {
+    if (c == c.init) return c;
+    // first byte is a dummy so that we never set length to 0
+    if (unget.length == 0)
+      unget.length = 1;
+    unget ~= c;
+    return c;
+  }
+
+  int vreadf(TypeInfo[] arguments, va_list args) {
+    char[] fmt;
+    int j = 0;
+    int count = 0, i = 0;
+    char c = getc();
+    while ((j < arguments.length || i < fmt.length) && !eof()) {
+      if (fmt.length == 0 || i == fmt.length) {
+	i = 0;
+	if (arguments[j] is typeid(char[])) {
+	  fmt = va_arg!(char[])(args);
+	  j++;
+	  continue;
+	} else if (arguments[j] is typeid(int*) ||
+		   arguments[j] is typeid(byte*) ||
+		   arguments[j] is typeid(short*) ||
+		   arguments[j] is typeid(long*)) {
+	  fmt = "%d";
+	} else if (arguments[j] is typeid(uint*) ||
+		   arguments[j] is typeid(ubyte*) ||
+		   arguments[j] is typeid(ushort*) ||
+		   arguments[j] is typeid(ulong*)) {
+	  fmt = "%d";
+	} else if (arguments[j] is typeid(float*) ||
+		   arguments[j] is typeid(double*) ||
+		   arguments[j] is typeid(real*)) {
+	  fmt = "%f";
+	} else if (arguments[j] is typeid(char[]*) ||
+		   arguments[j] is typeid(wchar[]*) ||
+		   arguments[j] is typeid(dchar[]*)) {
+	  fmt = "%s";
+	} else if (arguments[j] is typeid(char*)) {
+	  fmt = "%c";
+	}
+      }
+      if (fmt[i] == '%') {	// a field
+	i++;
+	bool suppress = false;
+	if (fmt[i] == '*') {	// suppress assignment
+	  suppress = true;
+	  i++;
+	}
+	// read field width
+	int width = 0;
+	while (isdigit(fmt[i])) {
+	  width = width * 10 + (fmt[i] - '0');
+	  i++;
+	}
+	if (width == 0)
+	  width = -1;
+	// skip any modifier if present
+	if (fmt[i] == 'h' || fmt[i] == 'l' || fmt[i] == 'L')
+	  i++;
+	// check the typechar and act accordingly
+	switch (fmt[i]) {
+	case 'd':	// decimal/hexadecimal/octal integer
+	case 'D':
+	case 'u':
+	case 'U':
+	case 'o':
+	case 'O':
+	case 'x':
+	case 'X':
+	case 'i':
+	case 'I':
+	  {
+	    while (iswhite(c)) {
+	      c = getc();
+	      count++;
+	    }
+	    bool neg = false;
+	    if (c == '-') {
+	      neg = true;
+	      c = getc();
+	      count++;
+	    } else if (c == '+') {
+	      c = getc();
+	      count++;
+	    }
+	    char ifmt = cast(char)(fmt[i] | 0x20);
+	    if (ifmt == 'i')	{ // undetermined base
+	      if (c == '0')	{ // octal or hex
+		c = getc();
+		count++;
+		if (c == 'x' || c == 'X')	{ // hex
+		  ifmt = 'x';
+		  c = getc();
+		  count++;
+		} else {	// octal
+		  ifmt = 'o';
+		}
+	      }
+	      else	// decimal
+		ifmt = 'd';
+	    }
+	    long n = 0;
+	    switch (ifmt)
+	    {
+		case 'd':	// decimal
+		case 'u': {
+		  while (isdigit(c) && width) {
+		    n = n * 10 + (c - '0');
+		    width--;
+		    c = getc();
+		    count++;
+		  }
+		} break;
+
+		case 'o': {	// octal
+		  while (isoctdigit(c) && width) {
+		    n = n * 010 + (c - '0');
+		    width--;
+		    c = getc();
+		    count++;
+		  }
+		} break;
+
+		case 'x': {	// hexadecimal
+		  while (ishexdigit(c) && width) {
+		    n *= 0x10;
+		    if (isdigit(c))
+		      n += c - '0';
+		    else
+		      n += 0xA + (c | 0x20) - 'a';
+		    width--;
+		    c = getc();
+		    count++;
+		  }
+		} break;
+
+		default:
+		    assert(0);
+	    }
+	    if (neg)
+	      n = -n;
+	    if (arguments[j] is typeid(int*)) {
+	      int* p = va_arg!(int*)(args);
+	      *p = cast(int)n;
+	    } else if (arguments[j] is typeid(short*)) {
+	      short* p = va_arg!(short*)(args);
+	      *p = cast(short)n;
+	    } else if (arguments[j] is typeid(byte*)) {
+	      byte* p = va_arg!(byte*)(args);
+	      *p = cast(byte)n;
+	    } else if (arguments[j] is typeid(long*)) {
+	      long* p = va_arg!(long*)(args);
+	      *p = n;
+	    } else if (arguments[j] is typeid(uint*)) {
+	      uint* p = va_arg!(uint*)(args);
+	      *p = cast(uint)n;
+	    } else if (arguments[j] is typeid(ushort*)) {
+	      ushort* p = va_arg!(ushort*)(args);
+	      *p = cast(ushort)n;
+	    } else if (arguments[j] is typeid(ubyte*)) {
+	      ubyte* p = va_arg!(ubyte*)(args);
+	      *p = cast(ubyte)n;
+	    } else if (arguments[j] is typeid(ulong*)) {
+	      ulong* p = va_arg!(ulong*)(args);
+	      *p = cast(ulong)n;
+	    }
+	    j++;
+	    i++;
+	  } break;
+
+	case 'f':	// float
+	case 'F':
+	case 'e':
+	case 'E':
+	case 'g':
+	case 'G':
+	  {
+	    while (iswhite(c)) {
+	      c = getc();
+	      count++;
+	    }
+	    bool neg = false;
+	    if (c == '-') {
+	      neg = true;
+	      c = getc();
+	      count++;
+	    } else if (c == '+') {
+	      c = getc();
+	      count++;
+	    }
+	    real n = 0;
+	    while (isdigit(c) && width) {
+	      n = n * 10 + (c - '0');
+	      width--;
+	      c = getc();
+	      count++;
+	    }
+	    if (width && c == '.') {
+	      width--;
+	      c = getc();
+	      count++;
+	      double frac = 1;
+	      while (isdigit(c) && width) {
+		n = n * 10 + (c - '0');
+		frac *= 10;
+		width--;
+		c = getc();
+		count++;
+	      }
+	      n /= frac;
+	    }
+	    if (width && (c == 'e' || c == 'E')) {
+	      width--;
+	      c = getc();
+	      count++;
+	      if (width) {
+		bool expneg = false;
+		if (c == '-') {
+		  expneg = true;
+		  width--;
+		  c = getc();
+		  count++;
+		} else if (c == '+') {
+		  width--;
+		  c = getc();
+		  count++;
+		}
+		real exp = 0;
+		while (isdigit(c) && width) {
+		  exp = exp * 10 + (c - '0');
+		  width--;
+		  c = getc();
+		  count++;
+		}
+		if (expneg) {
+		  while (exp--)
+		    n /= 10;
+		} else {
+		  while (exp--)
+		    n *= 10;
+		}
+	      }
+	    }
+	    if (neg)
+	      n = -n;
+	    if (arguments[j] is typeid(float*)) {
+	      float* p = va_arg!(float*)(args);
+	      *p = n;
+	    } else if (arguments[j] is typeid(double*)) {
+	      double* p = va_arg!(double*)(args);
+	      *p = n;
+	    } else if (arguments[j] is typeid(real*)) {
+	      real* p = va_arg!(real*)(args);
+	      *p = n;
+	    }
+	    j++;
+	    i++;
+	  } break;
+
+	case 's': {	// string
+	  while (iswhite(c)) {
+	    c = getc();
+	    count++;
+	  }
+	  char[] s;
+	  char[]* p;
+	  size_t strlen;
+	  if (arguments[j] is typeid(char[]*)) {
+	    p = va_arg!(char[]*)(args);
+	    s = *p;
+	  }
+	  while (!iswhite(c) && c != char.init) {
+	    if (strlen < s.length) {
+	      s[strlen] = c;
+	    } else {
+	      s ~= c;
+	    }
+	    strlen++;
+	    c = getc();
+	    count++;
+	  }
+	  s = s[0 .. strlen];
+	  if (arguments[j] is typeid(char[]*)) {
+	    *p = s;
+	  } else if (arguments[j] is typeid(char*)) {
+	    s ~= 0;
+	    char* q = va_arg!(char*)(args);
+	    q[0 .. s.length] = s[];
+	  } else if (arguments[j] is typeid(wchar[]*)) {
+	    wchar[]* q = va_arg!(wchar[]*)(args);
+	    *q = toUTF16(s);
+	  } else if (arguments[j] is typeid(dchar[]*)) {
+	    dchar[]* q = va_arg!(dchar[]*)(args);
+	    *q = toUTF32(s);
+	  }
+	  j++;
+	  i++;
+	} break;
+
+	case 'c': {	// character(s)
+	  char* s = va_arg!(char*)(args);
+	  if (width < 0)
+	    width = 1;
+	  else
+	    while (iswhite(c)) {
+	    c = getc();
+	    count++;
+	  }
+	  while (width-- && !eof()) {
+	    *(s++) = c;
+	    c = getc();
+	    count++;
+	  }
+	  j++;
+	  i++;
+	} break;
+
+	case 'n': {	// number of chars read so far
+	  int* p = va_arg!(int*)(args);
+	  *p = count;
+	  j++;
+	  i++;
+	} break;
+
+	default:	// read character as is
+	  goto nws;
+	}
+      } else if (iswhite(fmt[i])) {	// skip whitespace
+	while (iswhite(c))
+	  c = getc();
+	i++;
+      } else {	// read character as is
+      nws:
+	if (fmt[i] != c)
+	  break;
+	c = getc();
+	i++;
+      }
+    }
+    ungetc(c);
+    return count;
+  }
+
+  int readf(...) {
+    return vreadf(_arguments, _argptr);
+  }
+
+  // returns estimated number of bytes available for immediate reading
+  size_t available() { return 0; }
+
+  /***
+   * Write up to size bytes from buffer in the stream, returning the actual
+   * number of bytes that were written.
+   */
+  abstract size_t writeBlock(void* buffer, size_t size);
+
+  // writes block of data of specified size,
+  // throws WriteException on error
+  void writeExact(void* buffer, size_t size) {
+    for(;;) {
+      if (!size) return;
+      size_t writesize = writeBlock(buffer, size);
+      if (writesize == 0) break;
+      buffer += writesize;
+      size -= writesize;
+    }
+    if (size != 0)
+      throw new WriteException("unable to write to stream");
+  }
+
+  // writes the given array of bytes, returns
+  // actual number of bytes written
+  size_t write(ubyte[] buffer) {
+    return writeBlock(buffer.ptr, buffer.length);
+  }
+
+  // write a single value of desired type,
+  // throw WriteException on error
+  void write(byte x) { writeExact(&x, x.sizeof); }
+  void write(ubyte x) { writeExact(&x, x.sizeof); }
+  void write(short x) { writeExact(&x, x.sizeof); }
+  void write(ushort x) { writeExact(&x, x.sizeof); }
+  void write(int x) { writeExact(&x, x.sizeof); }
+  void write(uint x) { writeExact(&x, x.sizeof); }
+  void write(long x) { writeExact(&x, x.sizeof); }
+  void write(ulong x) { writeExact(&x, x.sizeof); }
+  void write(float x) { writeExact(&x, x.sizeof); }
+  void write(double x) { writeExact(&x, x.sizeof); }
+  void write(real x) { writeExact(&x, x.sizeof); }
+  void write(ifloat x) { writeExact(&x, x.sizeof); }
+  void write(idouble x) { writeExact(&x, x.sizeof); }
+  void write(ireal x) { writeExact(&x, x.sizeof); }
+  void write(cfloat x) { writeExact(&x, x.sizeof); }
+  void write(cdouble x) { writeExact(&x, x.sizeof); }
+  void write(creal x) { writeExact(&x, x.sizeof); }
+  void write(char x) { writeExact(&x, x.sizeof); }
+  void write(wchar x) { writeExact(&x, x.sizeof); }
+  void write(dchar x) { writeExact(&x, x.sizeof); }
+
+  // writes a string, together with its length
+  void write(char[] s) {
+    write(s.length);
+    writeString(s);
+  }
+
+  // writes a Unicode string, together with its length
+  void write(wchar[] s) {
+    write(s.length);
+    writeStringW(s);
+  }
+
+  // writes a line, throws WriteException on error
+  void writeLine(char[] s) {
+    writeString(s);
+    version (Win32)
+      writeString("\r\n");
+    else version (Mac)
+      writeString("\r");
+    else
+      writeString("\n");
+  }
+
+  // writes a Unicode line, throws WriteException on error
+  void writeLineW(wchar[] s) {
+    writeStringW(s);
+    version (Win32)
+      writeStringW("\r\n");
+    else version (Mac)
+      writeStringW("\r");
+    else
+      writeStringW("\n");
+  }
+
+  // writes a string, throws WriteException on error
+  void writeString(char[] s) {
+    writeExact(s.ptr, s.length);
+  }
+
+  // writes a Unicode string, throws WriteException on error
+  void writeStringW(wchar[] s) {
+    writeExact(s.ptr, s.length * wchar.sizeof);
+  }
+
+  // writes data to stream using vprintf() syntax,
+  // returns number of bytes written
+  size_t vprintf(char[] format, va_list args) {
+    // shamelessly stolen from OutBuffer,
+    // by Walter's permission
+    char[1024] buffer;
+    char* p = buffer.ptr;
+    char* f = toStringz(format);
+    size_t psize = buffer.length;
+    size_t count;
+    va_list args_copy;
+    while (true) {
+      va_copy(args_copy, args);
+      version (Win32) {
+	count = _vsnprintf(p, psize, f, args_copy);
+	if (count != -1)
+	  break;
+	psize *= 2;
+	p = cast(char*) alloca(psize);
+      } else version (Unix) {
+	count = vsnprintf(p, psize, f, args_copy);
+	if (count == -1)
+	  psize *= 2;
+	else if (count >= psize)
+	  psize = count + 1;
+	else
+	  break;
+	p = cast(char*) alloca(psize);
+      } else
+	  throw new Exception("unsupported platform");
+    }
+    writeString(p[0 .. count]);
+    return count;
+  }
+
+  // writes data to stream using printf() syntax,
+  // returns number of bytes written
+  size_t printf(char[] format, ...) {
+    version (GNU)
+	return vprintf(format, _argptr);
+    else {
+      va_list ap;
+      ap = cast(va_list) &format;
+      ap += format.sizeof;
+      return vprintf(format, ap);
+    }
+  }
+
+  private void doFormatCallback(dchar c) {
+    char[4] buf;
+    char[] b;
+    b = std.utf.toUTF8(buf, c);
+    writeString(b);
+  }
+
+  // writes data to stream using writef() syntax,
+  OutputStream writef(...) {
+    return writefx(_arguments,_argptr,0);
+  }
+
+  // writes data with trailing newline
+  OutputStream writefln(...) {
+    return writefx(_arguments,_argptr,1);
+  }
+
+  // writes data with optional trailing newline
+  OutputStream writefx(TypeInfo[] arguments, va_list argptr, int newline=false) {
+    doFormat(&doFormatCallback,arguments,argptr);
+    if (newline) 
+      writeLine("");
+    return this;
+  }
+
+  /***
+   * Copies all data from s into this stream.
+   * This may throw ReadException or WriteException on failure.
+   * This restores the file position of s so that it is unchanged.
+   */
+  void copyFrom(Stream s) {
+    if (seekable) {
+      ulong pos = s.position();
+      s.position(0);
+      copyFrom(s, s.size());
+      s.position(pos);
+    } else {
+      ubyte[128] buf;
+      while (!s.eof()) {
+	size_t m = s.readBlock(buf.ptr, buf.length);
+	writeExact(buf.ptr, m);
+      }
+    }
+  }
+
+  /***
+   * Copy a specified number of bytes from the given stream into this one.
+   * This may throw ReadException or WriteException on failure.
+   * Unlike the previous form, this doesn't restore the file position of s.
+   */
+  void copyFrom(Stream s, ulong count) {
+    ubyte[128] buf;
+    while (count > 0) {
+      size_t n = cast(size_t)(count<buf.length ? count : buf.length);
+      s.readExact(buf.ptr, n);
+      writeExact(buf.ptr, n);
+      count -= n;
+    }
+  }
+
+  /***
+   * Change the current position of the stream. whence is either SeekPos.Set, in
+   which case the offset is an absolute index from the beginning of the stream,
+   SeekPos.Current, in which case the offset is a delta from the current
+   position, or SeekPos.End, in which case the offset is a delta from the end of
+   the stream (negative or zero offsets only make sense in that case). This
+   returns the new file position.
+   */
+  abstract ulong seek(long offset, SeekPos whence);
+
+  /***
+   * Aliases for their normal seek counterparts.
+   */
+  ulong seekSet(long offset) { return seek (offset, SeekPos.Set); }
+  ulong seekCur(long offset) { return seek (offset, SeekPos.Current); }	/// ditto
+  ulong seekEnd(long offset) { return seek (offset, SeekPos.End); }	/// ditto
+
+  /***
+   * Sets file position. Equivalent to calling seek(pos, SeekPos.Set).
+   */
+  void position(ulong pos) { seek(cast(long)pos, SeekPos.Set); }
+
+  /***
+   * Returns current file position. Equivalent to seek(0, SeekPos.Current).
+   */
+  ulong position() { return seek(0, SeekPos.Current); }
+
+  /***
+   * Retrieve the size of the stream in bytes.
+   * The stream must be seekable or a SeekException is thrown.
+   */
+  ulong size() {
+    assertSeekable();
+    ulong pos = position(), result = seek(0, SeekPos.End);
+    position(pos);
+    return result;
+  }
+
+  // returns true if end of stream is reached, false otherwise
+  bool eof() { 
+    // for unseekable streams we only know the end when we read it
+    if (readEOF && !ungetAvailable())
+      return true;
+    else if (seekable)
+      return position() == size(); 
+    else
+      return false;
+  }
+
+  // returns true if the stream is open
+  bool isOpen() { return isopen; }
+
+  // flush the buffer if writeable
+  void flush() {
+    if (unget.length > 1)
+      unget.length = 1; // keep at least 1 so that data ptr stays
+  }
+
+  // close the stream somehow; the default just flushes the buffer
+  void close() {
+    if (isopen)
+      flush();
+    readEOF = prevCr = isopen = readable = writeable = seekable = false;
+  }
+
+  /***
+   * Read the entire stream and return it as a string.
+   * If the stream is not seekable the contents from the current position to eof
+   * is read and returned.
+   */
+  override char[] toString() {
+    if (!readable)
+      return super.toString();
+    size_t pos;
+    size_t rdlen;
+    size_t blockSize;
+    char[] result;
+    if (seekable) {
+      ulong orig_pos = position();
+      position(0);
+      blockSize = cast(size_t)size();
+      result = new char[blockSize];
+      while (blockSize > 0) {
+	rdlen = readBlock(&result[pos], blockSize);
+	pos += rdlen;
+	blockSize -= rdlen;
+      }
+      position(orig_pos);
+    } else {
+      blockSize = 4096;
+      result = new char[blockSize];
+      while ((rdlen = readBlock(&result[pos], blockSize)) > 0) {
+	pos += rdlen;
+	blockSize += rdlen;
+	result.length = result.length + blockSize;
+      }
+    }
+    return result[0 .. pos];
+  }
+
+  /***
+   * Get a hash of the stream by reading each byte and using it in a CRC-32
+   * checksum.
+   */
+  override size_t toHash() {
+    if (!readable || !seekable)
+      return super.toHash();
+    ulong pos = position();
+    uint crc = init_crc32 ();
+    position(0);
+    ulong len = size();
+    for (ulong i = 0; i < len; i++) {
+      ubyte c;
+      read(c);
+      crc = update_crc32(c, crc);
+    }
+    position(pos);
+    return crc;
+  }
+
+  // helper for checking that the stream is readable
+  final protected void assertReadable() {
+    if (!readable)
+      throw new ReadException("Stream is not readable");
+  }
+  // helper for checking that the stream is writeable
+  final protected void assertWriteable() {
+    if (!writeable)
+      throw new WriteException("Stream is not writeable");
+  }
+  // helper for checking that the stream is seekable
+  final protected void assertSeekable() {
+    if (!seekable)
+      throw new SeekException("Stream is not seekable");
+  }
+}
+
+/***
+ * A base class for streams that wrap a source stream with additional
+ * functionality.
+ *
+ * The method implementations forward read/write/seek calls to the
+ * source stream. A FilterStream can change the position of the source stream
+ * arbitrarily and may not keep the source stream state in sync with the
+ * FilterStream, even upon flushing and closing the FilterStream. It is
+ * recommended to not make any assumptions about the state of the source position
+ * and read/write state after a FilterStream has acted upon it. Specifc subclasses
+ * of FilterStream should document how they modify the source stream and if any
+ * invariants hold true between the source and filter.
+ */
+class FilterStream : Stream {
+  private Stream s;              // source stream
+
+  /// Property indicating when this stream closes to close the source stream as
+  /// well.
+  /// Defaults to true.
+  bool nestClose = true;
+
+  /// Construct a FilterStream for the given source.
+  this(Stream source) {
+    s = source;
+    resetSource();
+  }
+
+  // source getter/setter
+
+  /***
+   * Get the current source stream.
+   */
+  final Stream source(){return s;}
+
+  /***
+   * Set the current source stream.
+   *
+   * Setting the source stream closes this stream before attaching the new
+   * source. Attaching an open stream reopens this stream and resets the stream
+   * state. 
+   */
+  void source(Stream s) {
+    close();
+    this.s = s;
+    resetSource();
+  }
+
+  /***
+   * Indicates the source stream changed state and that this stream should reset
+   * any readable, writeable, seekable, isopen and buffering flags.
+   */
+  void resetSource() {
+    if (s !is null) {
+      readable = s.readable;
+      writeable = s.writeable;
+      seekable = s.seekable;
+      isopen = s.isOpen();
+    } else {
+      readable = writeable = seekable = false;
+      isopen = false;
+    }
+    readEOF = prevCr = false;
+  }
+
+  // read from source
+  size_t readBlock(void* buffer, size_t size) {
+    size_t res = s.readBlock(buffer,size);
+    readEOF = res == 0;
+    return res;
+  }
+
+  // write to source
+  size_t writeBlock(void* buffer, size_t size) {
+    return s.writeBlock(buffer,size);
+  }
+
+  // close stream
+  override void close() { 
+    if (isopen) {
+      super.close();
+      if (nestClose)
+	s.close();
+    }
+  }
+
+  // seek on source
+  override ulong seek(long offset, SeekPos whence) {
+    readEOF = false;
+    return s.seek(offset,whence);
+  }
+
+  override size_t available () { return s.available(); }
+  override void flush() { super.flush(); s.flush(); }
+}
+
+/***
+ * This subclass is for buffering a source stream.
+ *
+ * A buffered stream must be
+ * closed explicitly to ensure the final buffer content is written to the source
+ * stream. The source stream position is changed according to the block size so
+ * reading or writing to the BufferedStream may not change the source stream
+ * position by the same amount.
+ */
+class BufferedStream : FilterStream {
+  ubyte[] buffer;       // buffer, if any
+  uint bufferCurPos;    // current position in buffer
+  uint bufferLen;       // amount of data in buffer
+  bool bufferDirty = false;
+  uint bufferSourcePos; // position in buffer of source stream position
+  ulong streamPos;      // absolute position in source stream
+
+  /* Example of relationship between fields:
+   *
+   *  s             ...01234567890123456789012EOF
+   *  buffer                |--                     --|
+   *  bufferCurPos                       |
+   *  bufferLen             |--            --|
+   *  bufferSourcePos                        |
+   *
+   */
+
+  invariant {
+    assert(bufferSourcePos <= bufferLen);
+    assert(bufferCurPos <= bufferLen);
+    assert(bufferLen <= buffer.length);
+  }
+
+  const uint DefaultBufferSize = 8192;
+
+  /***
+   * Create a buffered stream for the stream source with the buffer size
+   * bufferSize.
+   */
+  this(Stream source, uint bufferSize = DefaultBufferSize) {
+    super(source);
+    if (bufferSize)
+      buffer = new ubyte[bufferSize];
+  }
+
+  protected void resetSource() {
+    super.resetSource();
+    streamPos = 0;
+    bufferLen = bufferSourcePos = bufferCurPos = 0;
+    bufferDirty = false;
+  }
+
+  // reads block of data of specified size using any buffered data
+  // returns actual number of bytes read
+  override size_t readBlock(void* result, size_t len) {
+    if (len == 0) return 0;
+
+    assertReadable();
+
+    ubyte* outbuf = cast(ubyte*)result;
+    size_t readsize = 0;
+
+    if (bufferCurPos + len < bufferLen) {
+      // buffer has all the data so copy it
+      outbuf[0 .. len] = buffer[bufferCurPos .. bufferCurPos+len];
+      bufferCurPos += len;
+      readsize = len;
+      goto ExitRead;
+    }
+
+    readsize = bufferLen - bufferCurPos;
+    if (readsize > 0) {
+      // buffer has some data so copy what is left
+      outbuf[0 .. readsize] = buffer[bufferCurPos .. bufferLen];
+      outbuf += readsize;
+      bufferCurPos += readsize;
+      len -= readsize;
+    }
+
+    flush();
+
+    if (len >= buffer.length) {
+      // buffer can't hold the data so fill output buffer directly
+      size_t siz = super.readBlock(outbuf, len);
+      readsize += siz;
+      streamPos += siz;
+    } else {
+      // read a new block into buffer
+      bufferLen = super.readBlock(buffer.ptr, buffer.length);
+      if (bufferLen < len) len = bufferLen;
+      outbuf[0 .. len] = buffer[0 .. len];
+      bufferSourcePos = bufferLen;
+      streamPos += bufferLen;
+      bufferCurPos = len;
+      readsize += len;
+    }
+
+  ExitRead:
+    return readsize;
+  }
+
+  // write block of data of specified size
+  // returns actual number of bytes written
+  override size_t writeBlock(void* result, size_t len) {
+    assertWriteable();
+
+    ubyte* buf = cast(ubyte*)result;
+    size_t writesize = 0;
+
+    if (bufferLen == 0) {
+      // buffer is empty so fill it if possible
+      if ((len < buffer.length) && (readable)) {
+	// read in data if the buffer is currently empty
+	bufferLen = s.readBlock(buffer.ptr, buffer.length);
+	bufferSourcePos = bufferLen;
+	streamPos += bufferLen;
+	  
+      } else if (len >= buffer.length) {
+	// buffer can't hold the data so write it directly and exit
+	writesize = s.writeBlock(buf,len);
+	streamPos += writesize;
+	goto ExitWrite;
+      }
+    }
+
+    if (bufferCurPos + len <= buffer.length) {
+      // buffer has space for all the data so copy it and exit
+      buffer[bufferCurPos .. bufferCurPos+len] = buf[0 .. len];
+      bufferCurPos += len;
+      bufferLen = bufferCurPos > bufferLen ? bufferCurPos : bufferLen;
+      writesize = len;
+      bufferDirty = true;
+      goto ExitWrite;
+    }
+
+    writesize = buffer.length - bufferCurPos;
+    if (writesize > 0) { 
+      // buffer can take some data
+      buffer[bufferCurPos .. buffer.length] = buf[0 .. writesize];
+      bufferCurPos = bufferLen = buffer.length;
+      buf += writesize;
+      len -= writesize;
+      bufferDirty = true;
+    }
+
+    assert(bufferCurPos == buffer.length);
+    assert(bufferLen == buffer.length);
+
+    flush();
+
+    writesize += writeBlock(buf,len);
+
+  ExitWrite:
+    return writesize;
+  }
+
+  override ulong seek(long offset, SeekPos whence) {
+    assertSeekable();
+
+    if ((whence != SeekPos.Current) ||
+	(offset + bufferCurPos < 0) ||
+	(offset + bufferCurPos >= bufferLen)) {
+      flush();
+      streamPos = s.seek(offset,whence);
+    } else {
+      bufferCurPos += offset;
+    }
+    readEOF = false;
+    return streamPos-bufferSourcePos+bufferCurPos;
+  }
+
+  // Buffered readLine - Dave Fladebo
+  // reads a line, terminated by either CR, LF, CR/LF, or EOF
+  // reusing the memory in buffer if result will fit, otherwise
+  // will reallocate (using concatenation)
+  template TreadLine(T) {
+    T[] readLine(T[] inBuffer)
+      {
+	size_t    lineSize = 0;
+	bool    haveCR = false;
+	T       c = '\0';
+	size_t    idx = 0;
+	ubyte*  pc = cast(ubyte*)&c;
+
+      L0:
+	for(;;) {
+	  uint start = bufferCurPos;
+	L1:
+	  foreach(ubyte b; buffer[start .. bufferLen]) {
+	    bufferCurPos++;
+	    pc[idx] = b;
+	    if(idx < T.sizeof - 1) {
+	      idx++;
+	      continue L1;
+	    } else {
+	      idx = 0;
+	    }
+	    if(c == '\n' || haveCR) {
+	      if(haveCR && c != '\n') bufferCurPos--;
+	      break L0;
+	    } else {
+	      if(c == '\r') {
+		haveCR = true;
+	      } else {
+		if(lineSize < inBuffer.length) {
+		  inBuffer[lineSize] = c;
+		} else {
+		  inBuffer ~= c;
+		}
+		lineSize++;
+	      }
+	    }
+	  }
+	  flush();
+	  size_t res = super.readBlock(buffer.ptr, buffer.length);
+	  if(!res) break L0; // EOF
+	  bufferSourcePos = bufferLen = res;
+	  streamPos += res;
+	}
+
+	return inBuffer[0 .. lineSize];
+      }
+  } // template TreadLine(T)
+
+  override char[] readLine(char[] inBuffer) {
+    if (ungetAvailable())
+      return super.readLine(inBuffer);
+    else
+      return TreadLine!(char).readLine(inBuffer);
+  }
+  alias Stream.readLine readLine;
+
+  override wchar[] readLineW(wchar[] inBuffer) {
+    if (ungetAvailable())
+      return super.readLineW(inBuffer);
+    else
+      return TreadLine!(wchar).readLine(inBuffer);
+  }
+  alias Stream.readLineW readLineW;
+
+  override void flush()
+  out {
+    assert(bufferCurPos == 0);
+    assert(bufferSourcePos == 0);
+    assert(bufferLen == 0);
+  }
+  body {
+    if (writeable && bufferDirty) {
+      if (bufferSourcePos != 0 && seekable) {
+	// move actual file pointer to front of buffer
+	streamPos = s.seek(-bufferSourcePos, SeekPos.Current);
+      }
+      // write buffer out
+      bufferSourcePos = s.writeBlock(buffer.ptr, bufferLen);
+      if (bufferSourcePos != bufferLen) {
+	throw new WriteException("Unable to write to stream");
+      }
+    }
+    super.flush();
+    long diff = cast(long)bufferCurPos-bufferSourcePos;
+    if (diff != 0 && seekable) {
+      // move actual file pointer to current position
+      streamPos = s.seek(diff, SeekPos.Current);
+    }
+    // reset buffer data to be empty
+    bufferSourcePos = bufferCurPos = bufferLen = 0;
+    bufferDirty = false;
+  }
+
+  // returns true if end of stream is reached, false otherwise
+  override bool eof() {
+    if ((buffer.length == 0) || !readable) {
+      return super.eof();
+    }
+    // some simple tests to avoid flushing
+    if (ungetAvailable() || bufferCurPos != bufferLen)
+      return false;
+    if (bufferLen == buffer.length)
+      flush();
+    size_t res = super.readBlock(&buffer[bufferLen],buffer.length-bufferLen);
+    bufferSourcePos +=  res;
+    bufferLen += res;
+    streamPos += res;
+    return readEOF;
+  }
+
+  // returns size of stream
+  ulong size() {
+    if (bufferDirty) flush();
+    return s.size();
+  }
+
+  // returns estimated number of bytes available for immediate reading
+  size_t available() {
+    return bufferLen - bufferCurPos;
+  }
+}
+
+/// An exception for File errors.
+class StreamFileException: StreamException {
+  /// Construct a StreamFileException with given error message.
+  this(char[] msg) { super(msg); }
+}
+
+/// An exception for errors during File.open.
+class OpenException: StreamFileException {
+  /// Construct an OpenFileException with given error message.
+  this(char[] msg) { super(msg); }
+}
+
+// access modes; may be or'ed
+enum FileMode {
+  In = 1,
+  Out = 2,
+  OutNew = 6, // includes FileMode.Out
+  Append = 10 // includes FileMode.Out
+}
+
+version (Win32) {
+  private import std.c.windows.windows;
+  extern (Windows) {
+    void FlushFileBuffers(HANDLE hFile);
+    DWORD  GetFileType(HANDLE hFile);
+  }
+}
+version (Unix) {
+  version(linux) {
+    private import std.c.linux.linux;
+    alias std.c.linux.linux sys;
+  } else {
+    private import std.c.unix.unix;
+    alias std.c.unix.unix sys;
+  }
+  alias int HANDLE;
+}
+version (NoSystem)
+  alias int HANDLE;
+
+/// This subclass is for unbuffered file system streams.
+class File: Stream {
+
+  version (Win32) {
+    private HANDLE hFile;
+  }
+  else version (Unix) {
+    private HANDLE hFile = -1;
+  }
+  else version (NoSystem)
+    private HANDLE hFile;
+
+  this() {
+    super();
+    version (Win32) {
+      hFile = null;
+    }
+    version (Unix) {
+      hFile = -1;
+    }
+    isopen = false;
+  }
+
+  // opens existing handle; use with care!
+  this(HANDLE hFile, FileMode mode) {
+    super();
+    this.hFile = hFile;
+    readable = cast(bool)(mode & FileMode.In);
+    writeable = cast(bool)(mode & FileMode.Out);
+    version(Windows) {
+      seekable = GetFileType(hFile) == 1; // FILE_TYPE_DISK
+    } else version (Unix) {
+      ulong result = lseek(hFile, 0, 0);
+      seekable = (result != ~0);
+    }
+  }
+
+  /***
+   * Create the stream with no open file, an open file in read mode, or an open
+   * file with explicit file mode.
+   * mode, if given, is a combination of FileMode.In
+   * (indicating a file that can be read) and FileMode.Out (indicating a file
+   * that can be written).
+   * Opening a file for reading that doesn't exist will error.
+   * Opening a file for writing that doesn't exist will create the file.
+   * The FileMode.OutNew mode will open the file for writing and reset the
+   * length to zero.
+   * The FileMode.Append mode will open the file for writing and move the
+   * file position to the end of the file.
+   */
+  this(char[] filename, FileMode mode = FileMode.In) { this(); open(filename, mode); }
+
+
+  /***
+   * Open a file for the stream, in an identical manner to the constructors.
+   * If an error occurs an OpenException is thrown.
+   */
+  void open(char[] filename, FileMode mode = FileMode.In) {
+    close();
+    int access, share, createMode;
+    parseMode(mode, access, share, createMode);
+    seekable = true;
+    readable = cast(bool)(mode & FileMode.In);
+    writeable = cast(bool)(mode & FileMode.Out);
+    version (Win32) {
+      if (std.file.useWfuncs) {
+	hFile = CreateFileW(std.utf.toUTF16z(filename), access, share,
+			    null, createMode, 0, null);
+      } else {
+	hFile = CreateFileA(std.file.toMBSz(filename), access, share,
+			    null, createMode, 0, null);
+      }
+      isopen = hFile != INVALID_HANDLE_VALUE;
+    }
+    version (Unix) {
+      hFile = sys.open(toStringz(filename), access | createMode, share);
+      isopen = hFile != -1;
+    }
+    version (NoSystem)
+      throw new OpenException("Files not supported on this target");
+    if (!isopen)
+      throw new OpenException("Cannot open or create file '" ~ filename ~ "'");
+    else if ((mode & FileMode.Append) == FileMode.Append)
+      seekEnd(0);
+  }
+
+  private void parseMode(int mode,
+			 out int access,
+			 out int share,
+			 out int createMode) {
+    version (Win32) {
+      if (mode & FileMode.In) {
+	access |= GENERIC_READ;
+	share |= FILE_SHARE_READ;
+	createMode = OPEN_EXISTING;
+      }
+      if (mode & FileMode.Out) {
+	access |= GENERIC_WRITE;
+	createMode = OPEN_ALWAYS; // will create if not present
+      }
+      if ((mode & FileMode.OutNew) == FileMode.OutNew) {
+	createMode = CREATE_ALWAYS; // resets file
+      }
+    }
+    version (Unix) {
+      if (mode & FileMode.In) {
+	access = O_RDONLY;
+	share = 0660;
+      }
+      if (mode & FileMode.Out) {
+	createMode = O_CREAT; // will create if not present
+	access = O_WRONLY;
+	share = 0660;
+      }
+      if (access == (O_WRONLY | O_RDONLY)) {
+	access = O_RDWR;
+      }
+      if ((mode & FileMode.OutNew) == FileMode.OutNew) {
+	access |= O_TRUNC; // resets file
+      }
+    }
+  }
+
+  /// Create a file for writing.
+  void create(char[] filename) {
+    create(filename, FileMode.OutNew);
+  }
+
+  /// ditto
+  void create(char[] filename, FileMode mode) {
+    close();
+    open(filename, mode | FileMode.OutNew);
+  }
+
+  /// Close the current file if it is open; otherwise it does nothing.
+  override void close() {
+    if (isopen) { 
+      super.close();
+      if (hFile) {
+	version (Win32) {
+	  CloseHandle(hFile);
+	  hFile = null;
+	} else version (Unix) {
+	  sys.close(hFile);
+	  hFile = -1;
+	}
+      }
+    }
+  }
+
+  // destructor, closes file if still opened
+  ~this() { close(); }
+
+  version (Win32) {
+    // returns size of stream
+    ulong size() {
+      assertSeekable();
+      uint sizehi;
+      uint sizelow = GetFileSize(hFile,&sizehi);
+      return (cast(ulong)sizehi << 32) + sizelow;
+    }
+  }
+
+  override size_t readBlock(void* buffer, size_t size) {
+    assertReadable();
+    version (Win32) {
+      ReadFile(hFile, buffer, size, &size, null);
+    } else version (Unix) {
+      size = sys.read(hFile, buffer, size);
+      if (size == -1)
+	size = 0;
+    }
+    readEOF = (size == 0);
+    return size;
+  }
+
+  override size_t writeBlock(void* buffer, size_t size) {
+    assertWriteable();
+    version (Win32) {
+      WriteFile(hFile, buffer, size, &size, null);
+    } else version (Unix) {
+      size = sys.write(hFile, buffer, size);
+      if (size == -1)
+	size = 0;
+    }
+    return size;
+  }
+
+  override ulong seek(long offset, SeekPos rel) {
+    assertSeekable();
+    version (Win32) {
+      int hi = cast(int)(offset>>32);
+      uint low = SetFilePointer(hFile, cast(int)offset, &hi, rel);
+      if ((low == INVALID_SET_FILE_POINTER) && (GetLastError() != 0))
+	throw new SeekException("unable to move file pointer");
+      ulong result = (cast(ulong)hi << 32) + low;
+    } else version (Unix) {
+       ulong result = lseek(hFile, cast(off_t)offset, rel);
+      if (result == 0xFFFFFFFF)
+	throw new SeekException("unable to move file pointer");
+    } else version (NoSystem) {
+	int result;
+	throw new SeekException("unable to move file pointer");
+    }
+    readEOF = false;
+    return result;
+  }
+
+  /***
+   * For a seekable file returns the difference of the size and position and
+   * otherwise returns 0.
+   */
+
+  override size_t available() {
+    if (seekable) {
+      ulong lavail = size - position;
+      if (lavail > size_t.max) lavail = size_t.max;
+      return cast(size_t)lavail;
+    }
+    return 0;
+  }
+
+  // OS-specific property, just in case somebody wants
+  // to mess with underlying API
+  HANDLE handle() { return hFile; }
+
+  // run a few tests
+  unittest {
+    File file = new File;
+    int i = 666;
+    file.create("stream.$$$");
+    // should be ok to write
+    assert(file.writeable);
+    file.writeLine("Testing stream.d:");
+    file.writeString("Hello, world!");
+    file.write(i);
+    // string#1 + string#2 + int should give exacly that
+    version (Win32)
+      assert(file.position() == 19 + 13 + 4);
+    version (Unix)
+      assert(file.position() == 18 + 13 + 4);
+    // we must be at the end of file
+    assert(file.eof());
+    file.close();
+    // no operations are allowed when file is closed
+    assert(!file.readable && !file.writeable && !file.seekable);
+    file.open("stream.$$$");
+    // should be ok to read
+    assert(file.readable);
+    assert(file.available == file.size);
+    char[] line = file.readLine();
+    char[] exp = "Testing stream.d:";
+    assert(line[0] == 'T');
+    assert(line.length == exp.length);
+    assert(!std.string.cmp(line, "Testing stream.d:"));
+    // jump over "Hello, "
+    file.seek(7, SeekPos.Current);
+    version (Win32)
+      assert(file.position() == 19 + 7);
+    version (Unix)
+      assert(file.position() == 18 + 7);
+    assert(!std.string.cmp(file.readString(6), "world!"));
+    i = 0; file.read(i);
+    assert(i == 666);
+    // string#1 + string#2 + int should give exacly that
+    version (Win32)
+      assert(file.position() == 19 + 13 + 4);
+    version (Unix)
+      assert(file.position() == 18 + 13 + 4);
+    // we must be at the end of file
+    assert(file.eof());
+    file.close();
+    file.open("stream.$$$",FileMode.OutNew | FileMode.In);
+    file.writeLine("Testing stream.d:");
+    file.writeLine("Another line");
+    file.writeLine("");
+    file.writeLine("That was blank");
+    file.position = 0;
+    char[][] lines;
+    foreach(char[] line; file) {
+      lines ~= line.dup;
+    }
+    assert( lines.length == 4 );
+    assert( lines[0] == "Testing stream.d:");
+    assert( lines[1] == "Another line");
+    assert( lines[2] == "");
+    assert( lines[3] == "That was blank");
+    file.position = 0;
+    lines = new char[][4];
+    foreach(ulong n, char[] line; file) {
+      lines[cast(size_t)(n-1)] = line.dup;
+    }
+    assert( lines[0] == "Testing stream.d:");
+    assert( lines[1] == "Another line");
+    assert( lines[2] == "");
+    assert( lines[3] == "That was blank");
+    file.close();
+    remove("stream.$$$");
+  }
+}
+
+/***
+ * This subclass is for buffered file system streams.
+ *
+ * It is a convenience class for wrapping a File in a BufferedStream.
+ * A buffered stream must be closed explicitly to ensure the final buffer
+ * content is written to the file.
+ */
+class BufferedFile: BufferedStream {
+
+  /// opens file for reading
+  this() { super(new File()); }
+
+  /// opens file in requested mode and buffer size
+  this(char[] filename, FileMode mode = FileMode.In,
+       uint bufferSize = DefaultBufferSize) {
+    super(new File(filename,mode),bufferSize);
+  }
+
+  /// opens file for reading with requested buffer size
+  this(File file, uint bufferSize = DefaultBufferSize) {
+    super(file,bufferSize);
+  }
+
+  /// opens existing handle; use with care!
+  this(HANDLE hFile, FileMode mode, uint buffersize) {
+    super(new File(hFile,mode),buffersize);
+  }
+
+  /// opens file in requested mode
+  void open(char[] filename, FileMode mode = FileMode.In) {
+    File sf = cast(File)s;
+    sf.open(filename,mode);
+    resetSource();
+  }
+
+  /// creates file in requested mode
+  void create(char[] filename, FileMode mode = FileMode.OutNew) {
+    File sf = cast(File)s;
+    sf.create(filename,mode);
+    resetSource();
+  }
+
+  // run a few tests same as File
+  unittest {
+    BufferedFile file = new BufferedFile;
+    int i = 666;
+    file.create("stream.$$$");
+    // should be ok to write
+    assert(file.writeable);
+    file.writeLine("Testing stream.d:");
+    file.writeString("Hello, world!");
+    file.write(i);
+    // string#1 + string#2 + int should give exacly that
+    version (Win32)
+      assert(file.position() == 19 + 13 + 4);
+    version (Unix)
+      assert(file.position() == 18 + 13 + 4);
+    // we must be at the end of file
+    assert(file.eof());
+    long oldsize = cast(long)file.size();
+    file.close();
+    // no operations are allowed when file is closed
+    assert(!file.readable && !file.writeable && !file.seekable);
+    file.open("stream.$$$");
+    // should be ok to read
+    assert(file.readable);
+    // test getc/ungetc and size()
+    char c1 = file.getc();
+    file.ungetc(c1);
+    assert( file.size() == oldsize );
+    assert(!std.string.cmp(file.readLine(), "Testing stream.d:"));
+    // jump over "Hello, "
+    file.seek(7, SeekPos.Current);
+    version (Win32)
+      assert(file.position() == 19 + 7);
+    version (Unix)
+      assert(file.position() == 18 + 7);
+    assert(!std.string.cmp(file.readString(6), "world!"));
+    i = 0; file.read(i);
+    assert(i == 666);
+    // string#1 + string#2 + int should give exacly that
+    version (Win32)
+      assert(file.position() == 19 + 13 + 4);
+    version (Unix)
+      assert(file.position() == 18 + 13 + 4);
+    // we must be at the end of file
+    assert(file.eof());
+    file.close();
+    remove("stream.$$$");
+  }
+
+}
+
+/// UTF byte-order-mark signatures 
+enum BOM {
+	UTF8,		/// UTF-8
+	UTF16LE,	/// UTF-16 Little Endian
+	UTF16BE,	/// UTF-16 Big Endian
+	UTF32LE,	/// UTF-32 Little Endian
+	UTF32BE,	/// UTF-32 Big Endian
+}
+
+private const int NBOMS = 5;
+Endian[NBOMS] BOMEndian = 
+[ std.system.endian, 
+  Endian.LittleEndian, Endian.BigEndian,
+  Endian.LittleEndian, Endian.BigEndian
+  ];
+
+ubyte[][NBOMS] ByteOrderMarks = 
+[ [0xEF, 0xBB, 0xBF],
+  [0xFF, 0xFE],
+  [0xFE, 0xFF],
+  [0xFF, 0xFE, 0x00, 0x00],
+  [0x00, 0x00, 0xFE, 0xFF]
+  ];
+
+
+/***
+ * This subclass wraps a stream with big-endian or little-endian byte order
+ * swapping.
+ *
+ * UTF Byte-Order-Mark (BOM) signatures can be read and deduced or
+ * written.
+ * Note that an EndianStream should not be used as the source of another
+ * FilterStream since a FilterStream call the source with byte-oriented
+ * read/write requests and the EndianStream will not perform any byte swapping.
+ * The EndianStream reads and writes binary data (non-getc functions) in a
+ * one-to-one
+ * manner with the source stream so the source stream's position and state will be
+ * kept in sync with the EndianStream if only non-getc functions are called.
+ */
+class EndianStream : FilterStream {
+
+  Endian endian;        /// Endianness property of the source stream.
+
+  /***
+   * Create the endian stream for the source stream source with endianness end.
+   * The default endianness is the native byte order.
+   * The Endian type is defined
+   * in the std.system module.
+   */
+  this(Stream source, Endian end = std.system.endian) {
+    super(source);
+    endian = end;
+  }
+
+  /***
+   * Return -1 if no BOM and otherwise read the BOM and return it.
+   *
+   * If there is no BOM or if bytes beyond the BOM are read then the bytes read
+   * are pushed back onto the ungetc buffer or ungetcw buffer.
+   * Pass ungetCharSize == 2 to use
+   * ungetcw instead of ungetc when no BOM is present.
+   */
+  int readBOM(int ungetCharSize = 1) {
+    ubyte[4] BOM_buffer;
+    int n = 0;       // the number of read bytes
+    int result = -1; // the last match or -1
+    for (int i=0; i < NBOMS; ++i) {
+      int j;
+      ubyte[] bom = ByteOrderMarks[i];
+      for (j=0; j < bom.length; ++j) {
+	if (n <= j) { // have to read more
+	  if (eof())
+	    break;
+	  readExact(&BOM_buffer[n++],1);
+	}
+	if (BOM_buffer[j] != bom[j])
+	  break;
+      }
+      if (j == bom.length) // found a match
+	result = i;
+    }
+    int m = 0;
+    if (result != -1) {
+      endian = BOMEndian[result]; // set stream endianness
+      m = ByteOrderMarks[result].length;
+    }
+    if ((ungetCharSize == 1 && result == -1) || (result == BOM.UTF8)) {
+      while (n-- > m)
+	ungetc(BOM_buffer[n]);
+    } else { // should eventually support unget for dchar as well
+      if (n & 1) // make sure we have an even number of bytes
+	readExact(&BOM_buffer[n++],1);
+      while (n > m) {
+	n -= 2;
+	wchar cw = *(cast(wchar*)&BOM_buffer[n]);
+	fixBO(&cw,2);
+	ungetcw(cw);
+      }
+    }
+    return result;
+  }
+
+  /***
+   * Correct the byte order of buffer to match native endianness.
+   * size must be even.
+   */
+  final void fixBO(void* buffer, uint size) {
+    if (endian != std.system.endian) {
+      ubyte* startb = cast(ubyte*)buffer;
+      uint* start = cast(uint*)buffer;
+      switch (size) {
+      case 0: break;
+      case 2: {
+	ubyte x = *startb;
+	*startb = *(startb+1);
+	*(startb+1) = x;
+	break;
+      }
+      case 4: {
+	*start = bswap(*start);
+	break;
+      }
+      default: {
+	uint* end = cast(uint*)(buffer + size - uint.sizeof);
+	while (start < end) {
+	  uint x = bswap(*start);
+	  *start = bswap(*end);
+	  *end = x;
+	  ++start;
+	  --end;
+	}
+	startb = cast(ubyte*)start;
+	ubyte* endb = cast(ubyte*)end;
+	int len = uint.sizeof - (startb - endb);
+	if (len > 0)
+	  fixBO(startb,len);
+      }
+      }
+    }
+  }
+
+  /***
+   * Correct the byte order of the given buffer in blocks of the given size and
+   * repeated the given number of times.
+   * size must be even.
+   */
+  final void fixBlockBO(void* buffer, uint size, size_t repeat) {
+    while (repeat--) {
+      fixBO(buffer,size);
+      buffer += size;
+    }
+  }
+
+  void read(out short x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); }
+  void read(out ushort x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); }
+  void read(out int x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); }
+  void read(out uint x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); }
+  void read(out long x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); }
+  void read(out ulong x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); }
+  void read(out float x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); }
+  void read(out double x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); }
+  void read(out real x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); }
+  void read(out ifloat x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); }
+  void read(out idouble x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); }
+  void read(out ireal x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); }
+  void read(out cfloat x) { readExact(&x, x.sizeof); fixBlockBO(&x,float.sizeof,2); }
+  void read(out cdouble x) { readExact(&x, x.sizeof); fixBlockBO(&x,double.sizeof,2); }
+  void read(out creal x) { readExact(&x, x.sizeof); fixBlockBO(&x,real.sizeof,2); }
+  void read(out wchar x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); }
+  void read(out dchar x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); }
+
+  wchar getcw() {
+    wchar c;
+    if (prevCr) {
+      prevCr = false;
+      c = getcw();
+      if (c != '\n') 
+	return c;
+    }
+    if (unget.length > 1) {
+      c = unget[unget.length - 1];
+      unget.length = unget.length - 1;
+    } else {
+      void* buf = &c;
+      size_t n = readBlock(buf,2);
+      if (n == 1 && readBlock(buf+1,1) == 0)
+          throw new ReadException("not enough data in stream");
+      fixBO(&c,c.sizeof);
+    }
+    return c;
+  }
+
+  wchar[] readStringW(size_t length) {
+    wchar[] result = new wchar[length];
+    readExact(result.ptr, result.length * wchar.sizeof);
+    fixBlockBO(&result,2,length);
+    return result;
+  }
+
+  /// Write the specified BOM b to the source stream.
+  void writeBOM(BOM b) {
+    ubyte[] bom = ByteOrderMarks[b];
+    writeBlock(bom.ptr, bom.length);
+  }
+
+  void write(short x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); }
+  void write(ushort x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); }
+  void write(int x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); }
+  void write(uint x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); }
+  void write(long x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); }
+  void write(ulong x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); }
+  void write(float x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); }
+  void write(double x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); }
+  void write(real x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); }
+  void write(ifloat x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); }
+  void write(idouble x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); }
+  void write(ireal x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); }
+  void write(cfloat x) { fixBlockBO(&x,float.sizeof,2); writeExact(&x, x.sizeof); }
+  void write(cdouble x) { fixBlockBO(&x,double.sizeof,2); writeExact(&x, x.sizeof); }
+  void write(creal x) { fixBlockBO(&x,real.sizeof,2); writeExact(&x, x.sizeof);  }
+  void write(wchar x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); }
+  void write(dchar x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); }
+
+  void writeStringW(wchar[] str) {
+    foreach(wchar cw;str) {
+      fixBO(&cw,2);
+      s.writeExact(&cw, 2);
+    }
+  }
+
+  override bool eof() { return s.eof() && !ungetAvailable();  }
+  override ulong size() { return s.size();  }
+
+  unittest {
+    MemoryStream m;
+    m = new MemoryStream ();
+    EndianStream em = new EndianStream(m,Endian.BigEndian);
+    uint x = 0x11223344;
+    em.write(x);
+    assert( m.data[0] == 0x11 );
+    assert( m.data[1] == 0x22 );
+    assert( m.data[2] == 0x33 );
+    assert( m.data[3] == 0x44 );
+    em.position(0);
+    ushort x2 = 0x5566;
+    em.write(x2);
+    assert( m.data[0] == 0x55 );
+    assert( m.data[1] == 0x66 );
+    em.position(0);
+    static ubyte[12] x3 = [1,2,3,4,5,6,7,8,9,10,11,12];
+    em.fixBO(x3,12);
+    if (std.system.endian == Endian.LittleEndian) {
+      assert( x3[0] == 12 );
+      assert( x3[1] == 11 );
+      assert( x3[2] == 10 );
+      assert( x3[4] == 8 );
+      assert( x3[5] == 7 );
+      assert( x3[6] == 6 );
+      assert( x3[8] == 4 );
+      assert( x3[9] == 3 );
+      assert( x3[10] == 2 );
+      assert( x3[11] == 1 );
+    }
+    em.endian = Endian.LittleEndian;
+    em.write(x);
+    assert( m.data[0] == 0x44 );
+    assert( m.data[1] == 0x33 );
+    assert( m.data[2] == 0x22 );
+    assert( m.data[3] == 0x11 );
+    em.position(0);
+    em.write(x2);
+    assert( m.data[0] == 0x66 );
+    assert( m.data[1] == 0x55 );
+    em.position(0);
+    em.fixBO(x3,12);
+    if (std.system.endian == Endian.BigEndian) {
+      assert( x3[0] == 12 );
+      assert( x3[1] == 11 );
+      assert( x3[2] == 10 );
+      assert( x3[4] == 8 );
+      assert( x3[5] == 7 );
+      assert( x3[6] == 6 );
+      assert( x3[8] == 4 );
+      assert( x3[9] == 3 );
+      assert( x3[10] == 2 );
+      assert( x3[11] == 1 );
+    }
+    em.writeBOM(BOM.UTF8);
+    assert( m.position() == 3 );
+    assert( m.data[0] == 0xEF );
+    assert( m.data[1] == 0xBB );
+    assert( m.data[2] == 0xBF );
+    em.writeString ("Hello, world");
+    em.position(0);
+    assert( m.position() == 0 );
+    assert( em.readBOM == BOM.UTF8 );
+    assert( m.position() == 3 );
+    assert( em.getc() == 'H' );
+    em.position(0);
+    em.writeBOM(BOM.UTF16BE);
+    assert( m.data[0] == 0xFE );
+    assert( m.data[1] == 0xFF );
+    em.position(0);
+    em.writeBOM(BOM.UTF16LE);
+    assert( m.data[0] == 0xFF );
+    assert( m.data[1] == 0xFE );
+    em.position(0);
+    em.writeString ("Hello, world");
+    em.position(0);
+    assert( em.readBOM == -1 );
+    assert( em.getc() == 'H' );
+    assert( em.getc() == 'e' );
+    assert( em.getc() == 'l' );
+    assert( em.getc() == 'l' );
+    em.position(0);
+  }
+}
+
+/***
+ * Parameterized subclass that wraps an array-like buffer with a stream
+ * interface.
+ *
+ * The type Buffer must support the length property, opIndex and opSlice.
+ * Compile in release mode when directly instantiating a TArrayStream to avoid
+ * link errors.
+ */
+class TArrayStream(Buffer): Stream {
+  Buffer buf; // current data
+  ulong len;  // current data length
+  ulong cur;  // current file position
+
+  /// Create the stream for the the buffer buf. Non-copying.
+  this(Buffer buf) {
+    super ();
+    this.buf = buf;
+    this.len = buf.length;
+    readable = writeable = seekable = true;
+  }
+
+  // ensure subclasses don't violate this
+  invariant {
+    assert(len <= buf.length);
+    assert(cur <= len);
+  }
+
+  override size_t readBlock(void* buffer, size_t size) {
+    assertReadable();
+    ubyte* cbuf = cast(ubyte*) buffer;
+    if (len - cur < size)
+      size = cast(size_t)(len - cur);
+    ubyte[] ubuf = cast(ubyte[])buf[cast(size_t)cur .. cast(size_t)(cur + size)];
+    cbuf[0 .. size] = ubuf[];
+    cur += size;
+    return size;
+  }
+
+  override size_t writeBlock(void* buffer, size_t size) {
+    assertWriteable();
+    ubyte* cbuf = cast(ubyte*) buffer;
+    ulong blen = buf.length;
+    if (cur + size > blen)
+      size = cast(size_t)(blen - cur);
+    ubyte[] ubuf = cast(ubyte[])buf[cast(size_t)cur .. cast(size_t)(cur + size)];
+    ubuf[] = cbuf[0 .. size];
+    cur += size;
+    if (cur > len)
+      len = cur;
+    return size;
+  }
+
+  override ulong seek(long offset, SeekPos rel) {
+    assertSeekable();
+    long scur; // signed to saturate to 0 properly
+
+    switch (rel) {
+    case SeekPos.Set: scur = offset; break;
+    case SeekPos.Current: scur = cast(long)(cur + offset); break;
+    case SeekPos.End: scur = cast(long)(len + offset); break;
+    default:
+	assert(0);
+    }
+
+    if (scur < 0)
+      cur = 0;
+    else if (scur > len)
+      cur = len;
+    else
+      cur = cast(ulong)scur;
+
+    return cur;
+  }
+
+  override size_t available () { return cast(size_t)(len - cur); }
+
+  /// Get the current memory data in total.
+  ubyte[] data() { 
+    if (len > size_t.max)
+      throw new StreamException("Stream too big");
+    void[] res = buf[0 .. cast(size_t)len];
+    return cast(ubyte[])res;
+  }
+
+  override char[] toString() {
+    return cast(char[]) data ();
+  }
+}
+
+/* Test the TArrayStream */
+unittest {
+  char[100] buf;
+  TArrayStream!(char[]) m;
+
+  m = new TArrayStream!(char[]) (buf);
+  assert (m.isOpen);
+  m.writeString ("Hello, world");
+  assert (m.position () == 12);
+  assert (m.available == 88);
+  assert (m.seekSet (0) == 0);
+  assert (m.available == 100);
+  assert (m.seekCur (4) == 4);
+  assert (m.available == 96);
+  assert (m.seekEnd (-8) == 92);
+  assert (m.available == 8);
+  assert (m.size () == 100);
+  assert (m.seekSet (4) == 4);
+  assert (m.readString (4) == "o, w");
+  m.writeString ("ie");
+  assert (buf[0..12] == "Hello, wield");
+  assert (m.position == 10);
+  assert (m.available == 90);
+  assert (m.size () == 100);
+}
+
+/// This subclass reads and constructs an array of bytes in memory.
+class MemoryStream: TArrayStream!(ubyte[]) {
+
+  /// Create the output buffer and setup for reading, writing, and seeking.
+  // clear to an empty buffer.
+  this() { this(cast(ubyte[]) null); }
+
+  /***
+   * Create the output buffer and setup for reading, writing, and seeking.
+   * Load it with specific input data.
+   */
+  this(ubyte[] buf) { super (buf); }
+  this(byte[] buf) { this(cast(ubyte[]) buf); }	/// ditto
+  this(char[] buf) { this(cast(ubyte[]) buf); } /// ditto
+
+  /// Ensure the stream can hold count bytes.
+  void reserve(size_t count) {
+    if (cur + count > buf.length)
+      buf.length = cast(size_t)((cur + count) * 2);
+  }
+
+  override size_t writeBlock(void* buffer, size_t size) {
+    reserve(size);
+    return super.writeBlock(buffer,size);
+  }
+
+  unittest {
+    MemoryStream m;
+
+    m = new MemoryStream ();
+    assert (m.isOpen);
+    m.writeString ("Hello, world");
+    assert (m.position () == 12);
+    assert (m.seekSet (0) == 0);
+    assert (m.available == 12);
+    assert (m.seekCur (4) == 4);
+    assert (m.available == 8);
+    assert (m.seekEnd (-8) == 4);
+    assert (m.available == 8);
+    assert (m.size () == 12);
+    assert (m.readString (4) == "o, w");
+    m.writeString ("ie");
+    assert (cast(char[]) m.data () == "Hello, wield");
+    m.seekEnd (0);
+    m.writeString ("Foo");
+    assert (m.position () == 15);
+    assert (m.available == 0);
+    m.writeString ("Foo foo foo foo foo foo foo");
+    assert (m.position () == 42);
+    m.position = 0;
+    assert (m.available == 42);
+    m.writef("%d %d %s",100,345,"hello");
+    char[] str = m.toString;
+    assert (str[0..13] == "100 345 hello");
+    assert (m.available == 29);
+    assert (m.position == 13);
+    
+    MemoryStream m2;
+    m.position = 3;
+    m2 = new MemoryStream ();
+    m2.writeString("before");
+    m2.copyFrom(m,10);
+    str = m2.toString;
+    assert (str[0..16] == "before 345 hello");
+    m2.position = 3;
+    m2.copyFrom(m);
+    char[] str2 = m.toString;
+    str = m2.toString;
+    assert (str == ("bef" ~ str2));
+  }
+}
+
+import std.mmfile;
+
+/***
+ * This subclass wraps a memory-mapped file with the stream API.
+ * See std.mmfile module.
+ */
+class MmFileStream : TArrayStream!(MmFile) {
+
+  /// Create stream wrapper for file.
+  this(MmFile file) {
+    super (file);
+    MmFile.Mode mode = file.mode;
+    writeable = mode > MmFile.Mode.Read;
+  }
+
+  override void flush() {
+    if (isopen) {
+      super.flush();
+      buf.flush();
+    }
+  }
+
+  override void close() {
+    if (isopen) {
+      super.close();
+      delete buf;
+      buf = null;
+    }
+  }
+}
+
+unittest {
+  MmFile mf = new MmFile("testing.txt",MmFile.Mode.ReadWriteNew,100,null);
+  MmFileStream m;
+  m = new MmFileStream (mf);
+  m.writeString ("Hello, world");
+  assert (m.position () == 12);
+  assert (m.seekSet (0) == 0);
+  assert (m.seekCur (4) == 4);
+  assert (m.seekEnd (-8) == 92);
+  assert (m.size () == 100);
+  assert (m.seekSet (4));
+  assert (m.readString (4) == "o, w");
+  m.writeString ("ie");
+  ubyte[] dd = m.data();
+  assert ((cast(char[]) dd)[0 .. 12] == "Hello, wield");
+  m.position = 12;
+  m.writeString ("Foo");
+  assert (m.position () == 15);
+  m.writeString ("Foo foo foo foo foo foo foo");
+  assert (m.position () == 42);
+  m.close();
+  mf = new MmFile("testing.txt");
+  m = new MmFileStream (mf);
+  assert (!m.writeable);
+  char[] str = m.readString(12);
+  assert (str == "Hello, wield");
+  m.close();
+  std.file.remove("testing.txt");
+}
+
+
+/***
+ * This subclass slices off a portion of another stream, making seeking relative
+ * to the boundaries of the slice.
+ *
+ * It could be used to section a large file into a
+ * set of smaller files, such as with tar archives. Reading and writing a
+ * SliceStream does not modify the position of the source stream if it is
+ * seekable.
+ */
+class SliceStream : FilterStream {
+  private {
+    ulong pos;  // our position relative to low
+    ulong low; // low stream offset.
+    ulong high; // high stream offset.
+    bool bounded; // upper-bounded by high.
+  }
+
+  /***
+   * Indicate both the source stream to use for reading from and the low part of
+   * the slice.
+   *
+   * The high part of the slice is dependent upon the end of the source
+   * stream, so that if you write beyond the end it resizes the stream normally.
+   */
+  this (Stream s, ulong low)
+  in {
+    assert (low <= s.size ());
+  }
+  body {
+    super(s);
+    this.low = low;
+    this.high = 0;
+    this.bounded = false;
+  }
+
+  /***
+   * Indicate the high index as well.
+   *
+   * Attempting to read or write past the high
+   * index results in the end being clipped off.
+   */
+  this (Stream s, ulong low, ulong high)
+  in {
+    assert (low <= high);
+    assert (high <= s.size ());
+  }
+  body {
+    super(s);
+    this.low = low;
+    this.high = high;
+    this.bounded = true;
+  }
+
+  invariant {
+    if (bounded)
+      assert (pos <= high - low);
+    else
+      assert (pos <= s.size - low);
+  }
+
+  override size_t readBlock (void *buffer, size_t size) {
+    assertReadable();
+    if (bounded && size > high - low - pos)
+	size = cast(size_t)(high - low - pos);
+    ulong bp = s.position;
+    if (seekable)
+      s.position = low + pos;
+    size_t ret = super.readBlock(buffer, size);
+    if (seekable) {
+      pos = s.position - low;
+      s.position = bp;
+    }
+    return ret;
+  }
+
+  override size_t writeBlock (void *buffer, size_t size) {
+    assertWriteable();
+    if (bounded && size > high - low - pos)
+	size = cast(size_t)(high - low - pos);
+    ulong bp = s.position;
+    if (seekable)
+      s.position = low + pos;
+    size_t ret = s.writeBlock(buffer, size);
+    if (seekable) {
+      pos = s.position - low;
+      s.position = bp;
+    }
+    return ret;
+  }
+
+  override ulong seek(long offset, SeekPos rel) {
+    assertSeekable();
+    long spos;
+
+    switch (rel) {
+      case SeekPos.Set:
+	spos = offset;
+	break;
+      case SeekPos.Current:
+	spos = cast(long)(pos + offset);
+	break;
+      case SeekPos.End:
+	if (bounded)
+	  spos = cast(long)(high - low + offset);
+	else
+	  spos = cast(long)(s.size - low + offset);
+	break;
+      default:
+	assert(0);
+    }
+
+    if (spos < 0)
+      pos = 0;
+    else if (bounded && spos > high - low)
+      pos = high - low;
+    else if (!bounded && spos > s.size - low)
+      pos = s.size - low;
+    else
+      pos = cast(ulong)spos;
+
+    readEOF = false;
+    return pos;
+  }
+
+  override size_t available () {
+    size_t res = s.available;
+    ulong bp = s.position;
+    if (bp <= pos+low && pos+low <= bp+res) {
+      if (!bounded || bp+res <= high)
+	return cast(size_t)(bp + res - pos - low);
+      else if (high <= bp+res)
+	return cast(size_t)(high - pos - low);
+    }
+    return 0;
+  }
+
+  unittest {
+    MemoryStream m;
+    SliceStream s;
+
+    m = new MemoryStream ((cast(char[])"Hello, world").dup);
+    s = new SliceStream (m, 4, 8);
+    assert (s.size () == 4);
+    assert (m.position () == 0);
+    assert (s.position () == 0);
+    assert (m.available == 12);
+    assert (s.available == 4);
+
+    assert (s.writeBlock (cast(char *) "Vroom", 5) == 4);
+    assert (m.position () == 0);
+    assert (s.position () == 4);
+    assert (m.available == 12);
+    assert (s.available == 0);
+    assert (s.seekEnd (-2) == 2);
+    assert (s.available == 2);
+    assert (s.seekEnd (2) == 4);
+    assert (s.available == 0);
+    assert (m.position () == 0);
+    assert (m.available == 12);
+
+    m.seekEnd(0);
+    m.writeString("\nBlaho");
+    assert (m.position == 18);
+    assert (m.available == 0);
+    assert (s.position == 4);
+    assert (s.available == 0);
+
+    s = new SliceStream (m, 4);
+    assert (s.size () == 14);
+    assert (s.toString () == "Vrooorld\nBlaho");
+    s.seekEnd (0);
+    assert (s.available == 0);
+
+    s.writeString (", etcetera.");
+    assert (s.position () == 25);
+    assert (s.seekSet (0) == 0);
+    assert (s.size () == 25);
+    assert (m.position () == 18);
+    assert (m.size () == 29);
+    assert (m.toString() == "HellVrooorld\nBlaho, etcetera.");
+  }
+}
+
+// helper functions
+private bool iswhite(char c) {
+  return c == ' ' || c == '\t' || c == '\r' || c == '\n';
+}
+
+private bool isdigit(char c) {
+  return c >= '0' && c <= '9';
+}
+
+private bool isoctdigit(char c) {
+  return c >= '0' && c <= '7';
+}
+
+private bool ishexdigit(char c) {
+  return isdigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
+}
--- a/lphobos/std/string.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/std/string.d	Mon Aug 04 19:28:49 2008 +0200
@@ -3443,85 +3443,85 @@
 }
 
 /// Check only the first parameter, all others will be ignored. 
-bool isNumeric(TypeInfo[] _arguments, va_list _argptr)
+bool isNumeric(TypeInfo[] _args, va_list _ptr)
 {
     char[]  s  = "";
     wchar[] ws = "";
     dchar[] ds = "";
 
     //writefln("isNumeric(...) called!");
-    if (_arguments.length == 0)
+    if (_args.length == 0)
         return false;
 
-    if (_arguments[0] == typeid(char[]))
-        return isNumeric(va_arg!(char[])(_argptr));
-    else if (_arguments[0] == typeid(wchar[]))
-        return isNumeric(std.utf.toUTF8(va_arg!(wchar[])(_argptr)));
-    else if (_arguments[0] == typeid(dchar[]))
-        return isNumeric(std.utf.toUTF8(va_arg!(dchar[])(_argptr)));
-    else if (_arguments[0] == typeid(real))
+    if (_args[0] == typeid(char[]))
+        return isNumeric(va_arg!(char[])(_ptr));
+    else if (_args[0] == typeid(wchar[]))
+        return isNumeric(std.utf.toUTF8(va_arg!(wchar[])(_ptr)));
+    else if (_args[0] == typeid(dchar[]))
+        return isNumeric(std.utf.toUTF8(va_arg!(dchar[])(_ptr)));
+    else if (_args[0] == typeid(real))
         return true;
-    else if (_arguments[0] == typeid(double)) 
+    else if (_args[0] == typeid(double)) 
         return true;   
-    else if (_arguments[0] == typeid(float)) 
+    else if (_args[0] == typeid(float)) 
         return true;  
-    else if (_arguments[0] == typeid(ulong)) 
+    else if (_args[0] == typeid(ulong)) 
         return true; 
-    else if (_arguments[0] == typeid(long)) 
+    else if (_args[0] == typeid(long)) 
         return true;   
-    else if (_arguments[0] == typeid(uint)) 
+    else if (_args[0] == typeid(uint)) 
         return true;  
-    else if (_arguments[0] == typeid(int)) 
+    else if (_args[0] == typeid(int)) 
         return true;   
-    else if (_arguments[0] == typeid(ushort)) 
+    else if (_args[0] == typeid(ushort)) 
         return true;   
-    else if (_arguments[0] == typeid(short)) 
+    else if (_args[0] == typeid(short)) 
         return true;   
-    else if (_arguments[0] == typeid(ubyte)) 
+    else if (_args[0] == typeid(ubyte)) 
     {
        s.length = 1;
-       s[0]= va_arg!(ubyte)(_argptr);
+       s[0]= va_arg!(ubyte)(_ptr);
        return isNumeric(cast(char[])s);
     }
-    else if (_arguments[0] == typeid(byte)) 
+    else if (_args[0] == typeid(byte)) 
     {
        s.length = 1;
-       s[0] = va_arg!(byte)(_argptr);
+       s[0] = va_arg!(byte)(_ptr);
        return isNumeric(cast(char[])s);
     }
-    else if (_arguments[0] == typeid(ireal))
+    else if (_args[0] == typeid(ireal))
         return true;
-    else if (_arguments[0] == typeid(idouble)) 
+    else if (_args[0] == typeid(idouble)) 
         return true;   
-    else if (_arguments[0] == typeid(ifloat)) 
+    else if (_args[0] == typeid(ifloat)) 
         return true;  
-    else if (_arguments[0] == typeid(creal))
+    else if (_args[0] == typeid(creal))
         return true;
-    else if (_arguments[0] == typeid(cdouble)) 
+    else if (_args[0] == typeid(cdouble)) 
         return true;   
-    else if (_arguments[0] == typeid(cfloat)) 
+    else if (_args[0] == typeid(cfloat)) 
         return true;  
-    else if (_arguments[0] == typeid(char))
+    else if (_args[0] == typeid(char))
     {
         s.length = 1;
-        s[0] = va_arg!(char)(_argptr);
+        s[0] = va_arg!(char)(_ptr);
         return isNumeric(s);
     }
-    else if (_arguments[0] == typeid(wchar))
+    else if (_args[0] == typeid(wchar))
     {
         ws.length = 1;
-        ws[0] = va_arg!(wchar)(_argptr);
+        ws[0] = va_arg!(wchar)(_ptr);
         return isNumeric(std.utf.toUTF8(ws));
     }
-    else if (_arguments[0] == typeid(dchar))
+    else if (_args[0] == typeid(dchar))
     { 
         ds.length =  1;
-        ds[0] = va_arg!(dchar)(_argptr);
+        ds[0] = va_arg!(dchar)(_ptr);
         return isNumeric(std.utf.toUTF8(ds));
     }
-    //else if (_arguments[0] == typeid(cent)) 
+    //else if (_args[0] == typeid(cent)) 
     //    return true;   
-    //else if (_arguments[0] == typeid(ucent)) 
+    //else if (_args[0] == typeid(ucent)) 
     //    return true;  
     else       
        return false; 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/system.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,95 @@
+// Written in the D programming language
+
+/**
+ * Information about the target operating system, environment, and CPU
+ * Authors: Walter Bright, www.digitalmars.com
+ * License: Public Domain
+ * Macros:
+ *	WIKI = Phobos/StdSystem
+ */
+
+/* NOTE: This file has been patched from the original DMD distribution to
+   work with the GDC compiler.
+
+   Modified by David Friedman, September 2007
+*/
+
+// Information about the target operating system, environment, and CPU
+
+module std.system;
+
+const
+{
+
+    // Operating system family
+    enum Family
+    {
+	Win32 = 1,		// Microsoft 32 bit Windows systems
+	linux,			// all linux systems
+	Unix,                  // Unix-like
+	NoSystem               // No operating system
+    }
+
+    version (Win32)
+    {
+	Family family = Family.Win32;
+    }
+    else version (linux)
+    {
+	Family family = Family.linux;
+    }
+    else version (Unix)
+    {
+	Family family = Family.Unix;
+    }	     
+    else version (NoSystem)
+    {
+	Family family = Family.NoSystem;
+    }
+    else
+    {
+	static assert(0);
+    }
+
+    // More specific operating system name
+    enum OS
+    {
+	Windows95 = 1,
+	Windows98,
+	WindowsME,
+	WindowsNT,
+	Windows2000,
+	WindowsXP,
+
+	RedHatLinux,
+    }
+
+    /// Byte order endianness
+
+    enum Endian
+    {
+	BigEndian,	/// big endian byte order
+	LittleEndian	/// little endian byte order
+    }
+
+    version(LittleEndian)
+    {
+	/// Native system endianness
+        Endian endian = Endian.LittleEndian;
+    }
+    else
+    {
+        Endian endian = Endian.BigEndian;
+    }
+}
+
+// The rest should get filled in dynamically at runtime
+
+OS os = OS.WindowsXP;
+
+// Operating system version as in
+// os_major.os_minor
+uint os_major = 4;
+uint os_minor = 0;
+
+
--- a/lphobos/std/thread.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/std/thread.d	Mon Aug 04 19:28:49 2008 +0200
@@ -658,7 +658,7 @@
 	}
 
 	state = TS.RUNNING;
-	//printf("creating thread x%x\n", this);
+	printf("creating thread x%x\n", this);
 	//result = pthread_create(&id, null, &threadstart, this);
 	// Create with thread attributes to allow non-default stack size - Dave Fladebo
 	int result = pthread_create(&id, &threadAttrs, &threadstart, cast(void*)this);
@@ -668,7 +668,7 @@
 	    idx = -1;
 	    error("failed to start");	// BUG: should report errno
 	}
-	//printf("t = x%x, id = %d\n", this, id);
+	printf("t = x%x, id = %d\n", this, id);
     }
 
     int run()
--- a/lphobos/std/traits.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/std/traits.d	Mon Aug 04 19:28:49 2008 +0200
@@ -127,37 +127,14 @@
     assert(is (TL[1] == I));
 }
 
-/* *******************************************
- */
-template isStaticArray_impl(T)
-{
-    const T inst = void;
-    
-    static if (is(typeof(T.length)))
-    {
-    static if (!is(typeof(T) == typeof(T.init)))
-    {           // abuses the fact that int[5].init == int
-        static if (is(T == typeof(T[0])[inst.length]))
-        {   // sanity check. this check alone isn't enough because dmd complains about dynamic arrays
-        const bool res = true;
-        }
-        else
-        const bool res = false;
-    }
-    else
-        const bool res = false;
-    }
-    else
-    {
-        const bool res = false;
-    }
-}
 /**
  * Detect whether type T is a static array.
  */
 template isStaticArray(T)
 {
-    const bool isStaticArray = isStaticArray_impl!(T).res;
+    static if (isArray!(T))
+        const bool isStaticArray = !is(T == typeof(T[0])[]);
+    else const bool isStaticArray = false;
 }
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/zip.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,520 @@
+
+/**
+ * Read/write data in the $(LINK2 http://www.info-_zip.org, zip archive) format.
+ * Makes use of the etc.c.zlib compression library.
+ *
+ * Bugs: 
+ *	$(UL
+ *	$(LI Multi-disk zips not supported.)
+ *	$(LI Only Zip version 20 formats are supported.)
+ *	$(LI Only supports compression modes 0 (no compression) and 8 (deflate).)
+ *	$(LI Does not support encryption.)
+ *	)
+ *
+ * Macros:
+ *	WIKI = Phobos/StdZip
+ */
+
+module std.zip;
+
+private import std.zlib;
+private import std.date;
+private import std.intrinsic;
+
+//debug=print;
+
+/** Thrown on error.
+ */
+class ZipException : Exception
+{
+    this(char[] msg)
+    {
+	super("ZipException: " ~ msg);
+    }
+}
+
+/**
+ * A member of the ZipArchive.
+ */
+class ArchiveMember
+{
+    ushort madeVersion = 20;	/// Read Only
+    ushort extractVersion = 20;	/// Read Only
+    ushort flags;		/// Read/Write: normally set to 0
+    ushort compressionMethod;	/// Read/Write: 0 for compression, 8 for deflate
+    std.date.DosFileTime time;	/// Read/Write: Last modified time of the member. It's in the DOS date/time format.
+    uint crc32;			/// Read Only: cyclic redundancy check (CRC) value
+    uint compressedSize;	/// Read Only: size of data of member in compressed form.
+    uint expandedSize;		/// Read Only: size of data of member in expanded form.
+    ushort diskNumber;		/// Read Only: should be 0.
+    ushort internalAttributes;	/// Read/Write
+    uint externalAttributes;	/// Read/Write
+
+    private uint offset;
+
+    /**
+     * Read/Write: Usually the file name of the archive member; it is used to
+     * index the archive directory for the member. Each member must have a unique
+     * name[]. Do not change without removing member from the directory first.
+     */
+    char[] name;
+
+    ubyte[] extra;		/// Read/Write: extra data for this member.
+    char[] comment;		/// Read/Write: comment associated with this member.
+    ubyte[] compressedData;	/// Read Only: data of member in compressed form.
+    ubyte[] expandedData;	/// Read/Write: data of member in uncompressed form.
+
+    debug(print)
+    {
+    void print()
+    {
+	printf("name = '%.*s'\n", cast(int) name.length, name.ptr);
+	printf("\tcomment = '%.*s'\n", cast(int) comment.length, comment.ptr);
+	printf("\tmadeVersion = x%04x\n", madeVersion);
+	printf("\textractVersion = x%04x\n", extractVersion);
+	printf("\tflags = x%04x\n", flags);
+	printf("\tcompressionMethod = %d\n", compressionMethod);
+	printf("\ttime = %d\n", time);
+	printf("\tcrc32 = x%08x\n", crc32);
+	printf("\texpandedSize = %d\n", expandedSize);
+	printf("\tcompressedSize = %d\n", compressedSize);
+	printf("\tinternalAttributes = x%04x\n", internalAttributes);
+	printf("\texternalAttributes = x%08x\n", externalAttributes);
+    }
+    }
+}
+
+/**
+ * Object representing the entire archive.
+ * ZipArchives are collections of ArchiveMembers.
+ */
+class ZipArchive
+{
+    ubyte[] data;	/// Read Only: array representing the entire contents of the archive.
+    uint endrecOffset;
+
+    uint diskNumber;	/// Read Only: 0 since multi-disk zip archives are not supported.
+    uint diskStartDir;	/// Read Only: 0 since multi-disk zip archives are not supported.
+    uint numEntries;	/// Read Only: number of ArchiveMembers in the directory.
+    uint totalEntries;	/// Read Only: same as totalEntries.
+    char[] comment;	/// Read/Write: the archive comment. Must be less than 65536 bytes in length.
+
+    /**
+     * Read Only: array indexed by the name of each member of the archive.
+     * Example:
+     *  All the members of the archive can be accessed with a foreach loop:
+     * --------------------
+     * ZipArchive archive = new ZipArchive(data);
+     * foreach (ArchiveMember am; archive.directory)
+     * {
+     *     writefln("member name is '%s'", am.name);
+     * }
+     * --------------------
+     */
+    ArchiveMember[char[]] directory;
+
+    debug (print)
+    {
+    void print()
+    {
+	printf("\tdiskNumber = %u\n", diskNumber);
+	printf("\tdiskStartDir = %u\n", diskStartDir);
+	printf("\tnumEntries = %u\n", numEntries);
+	printf("\ttotalEntries = %u\n", totalEntries);
+	printf("\tcomment = '%.*s'\n", cast(int) comment.length, comment.ptr);
+    }
+    }
+
+    /* ============ Creating a new archive =================== */
+
+    /** Constructor to use when creating a new archive.
+     */
+    this()
+    {
+    }
+
+    /** Add de to the archive.
+     */
+    void addMember(ArchiveMember de)
+    {
+	directory[de.name] = de;
+    }
+
+    /** Delete de from the archive.
+     */
+    void deleteMember(ArchiveMember de)
+    {
+	directory.remove(de.name);
+    }
+
+    /**
+     * Construct an archive out of the current members of the archive.
+     *
+     * Fills in the properties data[], diskNumber, diskStartDir, numEntries,
+     * totalEntries, and directory[].
+     * For each ArchiveMember, fills in properties crc32, compressedSize,
+     * compressedData[].
+     *
+     * Returns: array representing the entire archive.
+     */
+    void[] build()
+    {	uint i;
+	uint directoryOffset;
+
+	if (comment.length > 0xFFFF)
+	    throw new ZipException("archive comment longer than 65535");
+
+	// Compress each member; compute size
+	uint archiveSize = 0;
+	uint directorySize = 0;
+	foreach (ArchiveMember de; directory)
+	{
+	    de.expandedSize = de.expandedData.length;
+	    switch (de.compressionMethod)
+	    {
+		case 0:
+		    de.compressedData = de.expandedData;
+		    break;
+
+		case 8:
+		    de.compressedData = cast(ubyte[])std.zlib.compress(cast(void[])de.expandedData);
+		    de.compressedData = de.compressedData[2 .. de.compressedData.length - 4];
+		    break;
+
+		default:
+		    throw new ZipException("unsupported compression method");
+	    }
+	    de.compressedSize = de.compressedData.length;
+	    de.crc32 = std.zlib.crc32(0, cast(void[])de.expandedData);
+
+	    archiveSize += 30 + de.name.length +
+				de.extra.length +
+				de.compressedSize;
+	    directorySize += 46 + de.name.length +
+				de.extra.length +
+				de.comment.length;
+	}
+
+	data = new ubyte[archiveSize + directorySize + 22 + comment.length];
+
+	// Populate the data[]
+
+	// Store each archive member
+	i = 0;
+	foreach (ArchiveMember de; directory)
+	{
+	    de.offset = i;
+	    data[i .. i + 4] = cast(ubyte[])"PK\x03\x04";
+	    putUshort(i + 4,  de.extractVersion);
+	    putUshort(i + 6,  de.flags);
+	    putUshort(i + 8,  de.compressionMethod);
+	    putUint  (i + 10, cast(uint)de.time);
+	    putUint  (i + 14, de.crc32);
+	    putUint  (i + 18, de.compressedSize);
+	    putUint  (i + 22, de.expandedData.length);
+	    putUshort(i + 26, cast(ushort)de.name.length);
+	    putUshort(i + 28, cast(ushort)de.extra.length);
+	    i += 30;
+
+	    data[i .. i + de.name.length] = cast(ubyte[])de.name[];
+	    i += de.name.length;
+	    data[i .. i + de.extra.length] = cast(ubyte[])de.extra[];
+	    i += de.extra.length;
+	    data[i .. i + de.compressedSize] = de.compressedData[];
+	    i += de.compressedSize;
+	}
+
+	// Write directory
+	directoryOffset = i;
+	numEntries = 0;
+	foreach (ArchiveMember de; directory)
+	{
+	    data[i .. i + 4] = cast(ubyte[])"PK\x01\x02";
+	    putUshort(i + 4,  de.madeVersion);
+	    putUshort(i + 6,  de.extractVersion);
+	    putUshort(i + 8,  de.flags);
+	    putUshort(i + 10, de.compressionMethod);
+	    putUint  (i + 12, cast(uint)de.time);
+	    putUint  (i + 16, de.crc32);
+	    putUint  (i + 20, de.compressedSize);
+	    putUint  (i + 24, de.expandedSize);
+	    putUshort(i + 28, cast(ushort)de.name.length);
+	    putUshort(i + 30, cast(ushort)de.extra.length);
+	    putUshort(i + 32, cast(ushort)de.comment.length);
+	    putUshort(i + 34, de.diskNumber);
+	    putUshort(i + 36, de.internalAttributes);
+	    putUint  (i + 38, de.externalAttributes);
+	    putUint  (i + 42, de.offset);
+	    i += 46;
+
+	    data[i .. i + de.name.length] = cast(ubyte[])de.name[];
+	    i += de.name.length;
+	    data[i .. i + de.extra.length] = cast(ubyte[])de.extra[];
+	    i += de.extra.length;
+	    data[i .. i + de.comment.length] = cast(ubyte[])de.comment[];
+	    i += de.comment.length;
+	    numEntries++;
+	}
+	totalEntries = numEntries;
+
+	// Write end record
+	endrecOffset = i;
+	data[i .. i + 4] = cast(ubyte[])"PK\x05\x06";
+	putUshort(i + 4,  cast(ushort)diskNumber);
+	putUshort(i + 6,  cast(ushort)diskStartDir);
+	putUshort(i + 8,  cast(ushort)numEntries);
+	putUshort(i + 10, cast(ushort)totalEntries);
+	putUint  (i + 12, directorySize);
+	putUint  (i + 16, directoryOffset);
+	putUshort(i + 20, cast(ushort)comment.length);
+	i += 22;
+
+	// Write archive comment
+	assert(i + comment.length == data.length);
+	data[i .. data.length] = cast(ubyte[])comment[];
+
+	return cast(void[])data;
+    }
+
+    /* ============ Reading an existing archive =================== */
+
+    /**
+     * Constructor to use when reading an existing archive.
+     *
+     * Fills in the properties data[], diskNumber, diskStartDir, numEntries,
+     * totalEntries, comment[], and directory[].
+     * For each ArchiveMember, fills in
+     * properties madeVersion, extractVersion, flags, compressionMethod, time,
+     * crc32, compressedSize, expandedSize, compressedData[], diskNumber,
+     * internalAttributes, externalAttributes, name[], extra[], comment[].
+     * Use expand() to get the expanded data for each ArchiveMember.
+     *
+     * Params:
+     *	buffer = the entire contents of the archive.
+     */
+
+    this(void[] buffer)
+    {	int iend;
+	int i;
+	int endcommentlength;
+	uint directorySize;
+	uint directoryOffset;
+
+	this.data = cast(ubyte[]) buffer;
+
+	// Find 'end record index' by searching backwards for signature
+	iend = data.length - 66000;
+	if (iend < 0)
+	    iend = 0;
+	for (i = data.length - 22; 1; i--)
+	{
+	    if (i < iend)
+		throw new ZipException("no end record");
+
+	    if (data[i .. i + 4] == cast(ubyte[])"PK\x05\x06")
+	    {
+		endcommentlength = getUshort(i + 20);
+		if (i + 22 + endcommentlength > data.length)
+		    continue;
+		comment = cast(char[])data[i + 22 .. i + 22 + endcommentlength];
+		endrecOffset = i;
+		break;
+	    }
+	}
+
+	// Read end record data
+	diskNumber = getUshort(i + 4);
+	diskStartDir = getUshort(i + 6);
+
+	numEntries = getUshort(i + 8);
+	totalEntries = getUshort(i + 10);
+
+	if (numEntries != totalEntries)
+	    throw new ZipException("multiple disk zips not supported");
+
+	directorySize = getUint(i + 12);
+	directoryOffset = getUint(i + 16);
+
+	if (directoryOffset + directorySize > i)
+	    throw new ZipException("corrupted directory");
+
+	i = directoryOffset;
+	for (int n = 0; n < numEntries; n++)
+	{
+	    /* The format of an entry is:
+	     *	'PK' 1, 2
+	     *	directory info
+	     *	path
+	     *	extra data
+	     *	comment
+	     */
+
+	    uint offset;
+	    uint namelen;
+	    uint extralen;
+	    uint commentlen;
+
+	    if (data[i .. i + 4] != cast(ubyte[])"PK\x01\x02")
+		throw new ZipException("invalid directory entry 1");
+	    ArchiveMember de = new ArchiveMember();
+	    de.madeVersion = getUshort(i + 4);
+	    de.extractVersion = getUshort(i + 6);
+	    de.flags = getUshort(i + 8);
+	    de.compressionMethod = getUshort(i + 10);
+	    de.time = cast(DosFileTime)getUint(i + 12);
+	    de.crc32 = getUint(i + 16);
+	    de.compressedSize = getUint(i + 20);
+	    de.expandedSize = getUint(i + 24);
+	    namelen = getUshort(i + 28);
+	    extralen = getUshort(i + 30);
+	    commentlen = getUshort(i + 32);
+	    de.diskNumber = getUshort(i + 34);
+	    de.internalAttributes = getUshort(i + 36);
+	    de.externalAttributes = getUint(i + 38);
+	    de.offset = getUint(i + 42);
+	    i += 46;
+
+	    if (i + namelen + extralen + commentlen > directoryOffset + directorySize)
+		throw new ZipException("invalid directory entry 2");
+
+	    de.name = cast(char[])data[i .. i + namelen];
+	    i += namelen;
+	    de.extra = data[i .. i + extralen];
+	    i += extralen;
+	    de.comment = cast(char[])data[i .. i + commentlen];
+	    i += commentlen;
+
+	    directory[de.name] = de;
+	}
+	if (i != directoryOffset + directorySize)
+	    throw new ZipException("invalid directory entry 3");
+    }
+
+    /*****
+     * Decompress the contents of archive member de and return the expanded
+     * data.
+     *
+     * Fills in properties extractVersion, flags, compressionMethod, time,
+     * crc32, compressedSize, expandedSize, expandedData[], name[], extra[].
+     */
+    ubyte[] expand(ArchiveMember de)
+    {	uint namelen;
+	uint extralen;
+
+	if (data[de.offset .. de.offset + 4] != cast(ubyte[])"PK\x03\x04")
+	    throw new ZipException("invalid directory entry 4");
+
+	// These values should match what is in the main zip archive directory
+	de.extractVersion = getUshort(de.offset + 4);
+	de.flags = getUshort(de.offset + 6);
+	de.compressionMethod = getUshort(de.offset + 8);
+	de.time = cast(DosFileTime)getUint(de.offset + 10);
+	de.crc32 = getUint(de.offset + 14);
+	de.compressedSize = getUint(de.offset + 18);
+	de.expandedSize = getUint(de.offset + 22);
+	namelen = getUshort(de.offset + 26);
+	extralen = getUshort(de.offset + 28);
+
+	debug(print)
+	{
+	    printf("\t\texpandedSize = %d\n", de.expandedSize);
+	    printf("\t\tcompressedSize = %d\n", de.compressedSize);
+	    printf("\t\tnamelen = %d\n", namelen);
+	    printf("\t\textralen = %d\n", extralen);
+	}
+
+	if (de.flags & 1)
+	    throw new ZipException("encryption not supported");
+
+	int i;
+	i = de.offset + 30 + namelen + extralen;
+	if (i + de.compressedSize > endrecOffset)
+	    throw new ZipException("invalid directory entry 5");
+
+	de.compressedData = data[i .. i + de.compressedSize];
+	debug(print) arrayPrint(de.compressedData);
+
+	switch (de.compressionMethod)
+	{
+	    case 0:
+		de.expandedData = de.compressedData;
+		return de.expandedData;
+
+	    case 8:
+		// -15 is a magic value used to decompress zip files.
+		// It has the effect of not requiring the 2 byte header
+		// and 4 byte trailer.
+		de.expandedData = cast(ubyte[])std.zlib.uncompress(cast(void[])de.compressedData, de.expandedSize, -15);
+		return de.expandedData;
+
+	    default:
+		throw new ZipException("unsupported compression method");
+	}
+	assert(0);
+    }
+
+    /* ============ Utility =================== */
+
+    ushort getUshort(int i)
+    {
+	version (LittleEndian)
+	{
+	    return *cast(ushort *)&data[i];
+	}
+	else
+	{
+	    ubyte b0 = data[i];
+	    ubyte b1 = data[i + 1];
+	    return (b1 << 8) | b0;
+	}
+    }
+
+    uint getUint(int i)
+    {
+	version (LittleEndian)
+	{
+	    return *cast(uint *)&data[i];
+	}
+	else
+	{
+	    return bswap(*cast(uint *)&data[i]);
+	}
+    }
+
+    void putUshort(int i, ushort us)
+    {
+	version (LittleEndian)
+	{
+	    *cast(ushort *)&data[i] = us;
+	}
+	else
+	{
+	    data[i] = cast(ubyte)us;
+	    data[i + 1] = cast(ubyte)(us >> 8);
+	}
+    }
+
+    void putUint(int i, uint ui)
+    {
+	version (BigEndian)
+	{
+	    ui = bswap(ui);
+	}
+	*cast(uint *)&data[i] = ui;
+    }
+}
+
+debug(print)
+{
+    void arrayPrint(ubyte[] array)
+    {
+	printf("array %p,%d\n", cast(void*)array, array.length);
+	for (int i = 0; i < array.length; i++)
+	{
+	    printf("%02x ", array[i]);
+	    if (((i + 1) & 15) == 0)
+		printf("\n");
+	}
+	printf("\n");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/zlib.d	Mon Aug 04 19:28:49 2008 +0200
@@ -0,0 +1,618 @@
+/**
+ * Compress/decompress data using the $(LINK2 http://www._zlib.net, zlib library).
+ *
+ * References:
+ *	$(LINK2 http://en.wikipedia.org/wiki/Zlib, Wikipedia)
+ * License:
+ *	Public Domain
+ *
+ * Macros:
+ *	WIKI = Phobos/StdZlib
+ */
+
+/* NOTE: This file has been patched from the original DMD distribution to
+   work with the GDC compiler.
+
+   Modified by David Friedman, February 2007
+*/
+
+module std.zlib;
+
+ //debug=zlib;		// uncomment to turn on debugging printf's
+
+private import etc.c.zlib, std.stdint;
+
+// Values for 'mode'
+
+enum
+{
+	Z_NO_FLUSH      = 0,
+	Z_SYNC_FLUSH    = 2,
+	Z_FULL_FLUSH    = 3,
+	Z_FINISH        = 4,
+}
+
+/*************************************
+ * Errors throw a ZlibException.
+ */
+
+class ZlibException : Exception
+{
+    this(int errnum)
+    {	char[] msg;
+
+	switch (errnum)
+	{
+	    case Z_STREAM_END:		msg = "stream end"; break;
+	    case Z_NEED_DICT:		msg = "need dict"; break;
+	    case Z_ERRNO:		msg = "errno"; break;
+	    case Z_STREAM_ERROR:	msg = "stream error"; break;
+	    case Z_DATA_ERROR:		msg = "data error"; break;
+	    case Z_MEM_ERROR:		msg = "mem error"; break;
+	    case Z_BUF_ERROR:		msg = "buf error"; break;
+	    case Z_VERSION_ERROR:	msg = "version error"; break;
+	    default:			msg = "unknown error";	break;
+	}
+	super(msg);
+    }
+}
+
+/**************************************************
+ * Compute the Adler32 checksum of the data in buf[]. adler is the starting
+ * value when computing a cumulative checksum.
+ */
+
+uint adler32(uint adler, void[] buf)
+{
+    return etc.c.zlib.adler32(adler, cast(ubyte *)buf, buf.length);
+}
+
+unittest
+{
+    static ubyte[] data = [1,2,3,4,5,6,7,8,9,10];
+
+    uint adler;
+
+    debug(zlib) printf("D.zlib.adler32.unittest\n");
+    adler = adler32(0u, cast(void[])data);
+    debug(zlib) printf("adler = %x\n", adler);
+    assert(adler == 0xdc0037);
+}
+
+/*********************************
+ * Compute the CRC32 checksum of the data in buf[]. crc is the starting value
+ * when computing a cumulative checksum.
+ */
+
+uint crc32(uint crc, void[] buf)
+{
+    return etc.c.zlib.crc32(crc, cast(ubyte *)buf, buf.length);
+}
+
+unittest
+{
+    static ubyte[] data = [1,2,3,4,5,6,7,8,9,10];
+
+    uint crc;
+
+    debug(zlib) printf("D.zlib.crc32.unittest\n");
+    crc = crc32(0u, cast(void[])data);
+    debug(zlib) printf("crc = %x\n", crc);
+    assert(crc == 0x2520577b);
+}
+
+/*********************************************
+ * Compresses the data in srcbuf[] using compression _level level.
+ * The default value
+ * for level is 6, legal values are 1..9, with 1 being the least compression
+ * and 9 being the most.
+ * Returns the compressed data.
+ */
+
+void[] compress(void[] srcbuf, int level)
+in
+{
+    assert(-1 <= level && level <= 9);
+}
+body
+{
+    int err;
+    ubyte[] destbuf;
+    Culong_t destlen;
+
+    destlen = srcbuf.length + ((srcbuf.length + 1023) / 1024) + 12;
+    destbuf = new ubyte[destlen];
+    err = etc.c.zlib.compress2(destbuf.ptr, &destlen, cast(ubyte *)srcbuf, srcbuf.length, level);
+    if (err)
+    {	delete destbuf;
+	throw new ZlibException(err);
+    }
+
+    destbuf.length = destlen;
+    return destbuf;
+}
+
+/*********************************************
+ * ditto
+ */
+
+void[] compress(void[] buf)
+{
+    return compress(buf, Z_DEFAULT_COMPRESSION);
+}
+
+/*********************************************
+ * Decompresses the data in srcbuf[].
+ * Params: destlen = size of the uncompressed data.
+ * It need not be accurate, but the decompression will be faster if the exact
+ * size is supplied.
+ * Returns: the decompressed data.
+ */
+
+void[] uncompress(void[] srcbuf, size_t destlen = 0u, int winbits = 15)
+{
+    int err;
+    ubyte[] destbuf;
+
+    if (!destlen)
+	destlen = srcbuf.length * 2 + 1;
+
+    while (1)
+    {
+	etc.c.zlib.z_stream zs;
+
+	destbuf = new ubyte[destlen];
+	
+	zs.next_in = cast(ubyte*) srcbuf;
+	zs.avail_in = srcbuf.length;
+
+	zs.next_out = destbuf.ptr;
+	zs.avail_out = destlen;
+
+	err = etc.c.zlib.inflateInit2(&zs, winbits);
+	if (err)
+	{   delete destbuf;
+	    throw new ZlibException(err);
+	}
+	err = etc.c.zlib.inflate(&zs, Z_NO_FLUSH);
+	switch (err)
+	{
+	    case Z_OK:
+		etc.c.zlib.inflateEnd(&zs);
+		destlen = destbuf.length * 2;
+		continue;
+
+	    case Z_STREAM_END:
+		destbuf.length = zs.total_out;
+		err = etc.c.zlib.inflateEnd(&zs);
+		if (err != Z_OK)
+		    goto Lerr;
+		return destbuf;
+
+	    default:
+		etc.c.zlib.inflateEnd(&zs);
+	    Lerr:
+		delete destbuf;
+		throw new ZlibException(err);
+	}
+    }
+    assert(0);
+}
+
+unittest
+{
+    ubyte[] src = cast(ubyte[])
+"the quick brown fox jumps over the lazy dog\r
+the quick brown fox jumps over the lazy dog\r
+";
+    ubyte[] dst;
+    ubyte[] result;
+
+    //arrayPrint(src);
+    dst = cast(ubyte[])compress(cast(void[])src);
+    //arrayPrint(dst);
+    result = cast(ubyte[])uncompress(cast(void[])dst);
+    //arrayPrint(result);
+    assert(result == src);
+}
+
+/+
+void arrayPrint(ubyte[] array)
+{
+    //printf("array %p,%d\n", (void*)array, array.length);
+    for (int i = 0; i < array.length; i++)
+    {
+	printf("%02x ", array[i]);
+	if (((i + 1) & 15) == 0)
+	    printf("\n");
+    }
+    printf("\n\n");
+}
++/
+
+/*********************************************
+ * Used when the data to be compressed is not all in one buffer.
+ */
+
+class Compress
+{
+  private:
+    z_stream zs;
+    int level = Z_DEFAULT_COMPRESSION;
+    int inited;
+
+    void error(int err)
+    {
+	if (inited)
+	{   deflateEnd(&zs);
+	    inited = 0;
+	}
+	throw new ZlibException(err);
+    }
+
+  public:
+
+    /**
+     * Construct. level is the same as for D.zlib.compress().
+     */
+    this(int level)
+    in
+    {
+	assert(1 <= level && level <= 9);
+    }
+    body
+    {
+	this.level = level;
+    }
+
+    /// ditto
+    this()
+    {
+    }
+
+    ~this()
+    {	int err;
+
+	if (inited)
+	{
+	    inited = 0;
+	    err = deflateEnd(&zs);
+	    if (err)
+		error(err);
+	}
+    }
+
+    /**
+     * Compress the data in buf and return the compressed data.
+     * The buffers
+     * returned from successive calls to this should be concatenated together.
+     */
+    void[] compress(void[] buf)
+    {	int err;
+	ubyte[] destbuf;
+
+	if (buf.length == 0)
+	    return null;
+
+	if (!inited)
+	{
+	    err = deflateInit(&zs, level);
+	    if (err)
+		error(err);
+	    inited = 1;
+	}
+
+	destbuf = new ubyte[zs.avail_in + buf.length];
+	zs.next_out = destbuf.ptr;
+	zs.avail_out = destbuf.length;
+
+	if (zs.avail_in)
+	    buf = cast(void[])zs.next_in[0 .. zs.avail_in] ~ buf;
+
+	zs.next_in = cast(ubyte*) buf.ptr;
+	zs.avail_in = buf.length;
+
+	err = deflate(&zs, Z_NO_FLUSH);
+	if (err != Z_STREAM_END && err != Z_OK)
+	{   delete destbuf;
+	    error(err);
+	}
+	destbuf.length = destbuf.length - zs.avail_out;
+	return destbuf;
+    }
+
+    /***
+     * Compress and return any remaining data.
+     * The returned data should be appended to that returned by compress().
+     * Params:
+     *	mode = one of the following: 
+     *		$(DL
+		    $(DT Z_SYNC_FLUSH )
+		    $(DD Syncs up flushing to the next byte boundary.
+			Used when more data is to be compressed later on.)
+		    $(DT Z_FULL_FLUSH )
+		    $(DD Syncs up flushing to the next byte boundary.
+			Used when more data is to be compressed later on,
+			and the decompressor needs to be restartable at this
+			point.)
+		    $(DT Z_FINISH)
+		    $(DD (default) Used when finished compressing the data. )
+		)
+     */
+    void[] flush(int mode = Z_FINISH)
+    in
+    {
+	assert(mode == Z_FINISH || mode == Z_SYNC_FLUSH || mode == Z_FULL_FLUSH);
+    }
+    body
+    {
+	void[] destbuf;
+	ubyte[512] tmpbuf = void;
+	int err;
+
+	if (!inited)
+	    return null;
+
+	/* may be  zs.avail_out+<some constant>
+	 * zs.avail_out is set nonzero by deflate in previous compress()
+	 */
+	//tmpbuf = new void[zs.avail_out];
+	zs.next_out = tmpbuf.ptr;
+	zs.avail_out = tmpbuf.length;
+
+	while( (err = deflate(&zs, mode)) != Z_STREAM_END)
+	{
+	    if (err == Z_OK)
+	    {
+		if (zs.avail_out != 0 && mode != Z_FINISH)
+		    break;
+		else if(zs.avail_out == 0)
+		{
+		    destbuf ~= tmpbuf;
+		    zs.next_out = tmpbuf.ptr;
+		    zs.avail_out = tmpbuf.length;
+		    continue;
+		}
+		err = Z_BUF_ERROR;
+	    }
+	    delete destbuf;
+	    error(err);
+	}
+	destbuf ~= tmpbuf[0 .. (tmpbuf.length - zs.avail_out)];
+
+	if (mode == Z_FINISH)
+	{
+	    err = deflateEnd(&zs);
+	    inited = 0;
+	    if (err)
+		error(err);
+	}
+	return destbuf;
+    }
+}
+
+/******
+ * Used when the data to be decompressed is not all in one buffer.
+ */
+
+class UnCompress
+{
+  private:
+    z_stream zs;
+    int inited;
+    int done;
+    uint destbufsize;
+
+    void error(int err)
+    {
+	if (inited)
+	{   inflateEnd(&zs);
+	    inited = 0;
+	}
+	throw new ZlibException(err);
+    }
+
+  public:
+
+    /**
+     * Construct. destbufsize is the same as for D.zlib.uncompress().
+     */
+    this(uint destbufsize)
+    {
+	this.destbufsize = destbufsize;
+    }
+
+    /** ditto */
+    this()
+    {
+    }
+
+    ~this()
+    {	int err;
+
+	if (inited)
+	{
+	    inited = 0;
+	    err = inflateEnd(&zs);
+	    if (err)
+		error(err);
+	}
+	done = 1;
+    }
+
+    /**
+     * Decompress the data in buf and return the decompressed data.
+     * The buffers returned from successive calls to this should be concatenated
+     * together.
+     */
+    void[] uncompress(void[] buf)
+    in
+    {
+	assert(!done);
+    }
+    body
+    {	int err;
+	ubyte[] destbuf;
+
+	if (buf.length == 0)
+	    return null;
+
+	if (!inited)
+	{
+	    err = inflateInit(&zs);
+	    if (err)
+		error(err);
+	    inited = 1;
+	}
+
+	if (!destbufsize)
+	    destbufsize = buf.length * 2;
+	destbuf = new ubyte[zs.avail_in * 2 + destbufsize];
+	zs.next_out = destbuf.ptr;
+	zs.avail_out = destbuf.length;
+
+	if (zs.avail_in)
+	    buf = cast(void[])zs.next_in[0 .. zs.avail_in] ~ buf;
+
+	zs.next_in = cast(ubyte*) buf;
+	zs.avail_in = buf.length;
+
+	err = inflate(&zs, Z_NO_FLUSH);
+	if (err != Z_STREAM_END && err != Z_OK)
+	{   delete destbuf;
+	    error(err);
+	}
+	destbuf.length = destbuf.length - zs.avail_out;
+	return destbuf;
+    }
+
+    /**
+     * Decompress and return any remaining data.
+     * The returned data should be appended to that returned by uncompress().
+     * The UnCompress object cannot be used further.
+     */
+    void[] flush()
+    in
+    {
+	assert(!done);
+    }
+    out
+    {
+	assert(done);
+    }
+    body
+    {
+	ubyte[] extra;
+	ubyte[] destbuf;
+	int err;
+
+	done = 1;
+	if (!inited)
+	    return null;
+
+      L1:
+	destbuf = new ubyte[zs.avail_in * 2 + 100];
+	zs.next_out = destbuf.ptr;
+	zs.avail_out = destbuf.length;
+
+	err = etc.c.zlib.inflate(&zs, Z_NO_FLUSH);
+	if (err == Z_OK && zs.avail_out == 0)
+	{
+	    extra ~= destbuf;
+	    goto L1;
+	}
+	if (err != Z_STREAM_END)
+	{
+	    delete destbuf;
+	    if (err == Z_OK)
+		err = Z_BUF_ERROR;
+	    error(err);
+	}
+	destbuf = destbuf.ptr[0 .. zs.next_out - destbuf.ptr];
+	err = etc.c.zlib.inflateEnd(&zs);
+	inited = 0;
+	if (err)
+	    error(err);
+	if (extra.length)
+	    destbuf = extra ~ destbuf;
+	return destbuf;
+    }
+}
+
+/* ========================== unittest ========================= */
+
+private import std.stdio;
+private import std.random;
+
+unittest // by Dave
+{
+    debug(zlib) printf("std.zlib.unittest\n");
+
+    bool CompressThenUncompress (ubyte[] src)
+    {
+      try {
+	ubyte[] dst = cast(ubyte[])std.zlib.compress(cast(void[])src);
+	double ratio = (dst.length / cast(double)src.length);
+	debug(zlib) writef("src.length:  ", src.length, ", dst: ", dst.length, ", Ratio = ", ratio);
+	ubyte[] uncompressedBuf;
+	uncompressedBuf = cast(ubyte[])std.zlib.uncompress(cast(void[])dst);
+	assert(src.length == uncompressedBuf.length);
+	assert(src == uncompressedBuf);
+      }
+      catch {
+	debug(zlib) writefln(" ... Exception thrown when src.length = ", src.length, ".");
+	return false;
+      }
+      return true;
+    }
+
+
+    // smallish buffers
+    for(int idx = 0; idx < 25; idx++) {
+        char[] buf = new char[rand() % 100];
+
+        // Alternate between more & less compressible
+        foreach(inout char c; buf) c = ' ' + (rand() % (idx % 2 ? 91 : 2));
+
+        if(CompressThenUncompress(cast(ubyte[])buf)) {
+            debug(zlib) printf("; Success.\n");
+        } else {
+            return;
+        }
+    }
+
+    // larger buffers
+    for(int idx = 0; idx < 25; idx++) {
+        char[] buf = new char[rand() % 1000/*0000*/];
+
+        // Alternate between more & less compressible
+        foreach(inout char c; buf) c = ' ' + (rand() % (idx % 2 ? 91 : 10));
+
+        if(CompressThenUncompress(cast(ubyte[])buf)) {
+            debug(zlib) printf("; Success.\n");
+        } else {
+            return;
+        }
+    }
+
+    debug(zlib) printf("PASSED std.zlib.unittest\n");
+}
+
+
+unittest // by Artem Rebrov
+{
+    Compress cmp = new Compress;
+    UnCompress decmp = new UnCompress;
+
+    void[] input;
+    input = "tesatdffadf";
+
+    void[] buf = cmp.compress(input);
+    buf ~= cmp.flush();
+    void[] output = decmp.uncompress(buf);
+
+    //writefln("input = '%s'", cast(char[])input);
+    //writefln("output = '%s'", cast(char[])output);
+    assert( output[] == input[] );
+}
+
--- a/lphobos/typeinfo1/ti_float.d	Mon Aug 04 19:08:39 2008 +0200
+++ b/lphobos/typeinfo1/ti_float.d	Mon Aug 04 19:28:49 2008 +0200
@@ -3,6 +3,7 @@
 
 module typeinfo1.ti_float;
 
+import std.gc: malloc;
 class TypeInfo_f : TypeInfo
 {
     char[] toString() { return "float"; }
@@ -62,9 +63,8 @@
     }
 
     void[] init()
-    {	static float r;
-
-	return (&r)[0 .. 1];
+    {
+	return (cast(float*)malloc(float.sizeof))[0..1];
     }
 }