changeset 662:88e23f8c2354

Applied downs' latest Phobos patch
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Mon, 06 Oct 2008 21:40:33 +0200
parents 99f32e967746
children 6aaa3d3c1183
files lphobos/build.sh lphobos/gc/gc.d lphobos/internal/adi.d lphobos/internal/eh.d lphobos/llvmdc.conf lphobos/object.d lphobos/std/dateparse.d lphobos/std/file.d lphobos/std/format.d lphobos/std/mmfile.d lphobos/std/outbuffer.d lphobos/std/outofmemory.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
diffstat 18 files changed, 2478 insertions(+), 2444 deletions(-) [+]
line wrap: on
line diff
--- a/lphobos/build.sh	Mon Oct 06 21:27:29 2008 +0200
+++ b/lphobos/build.sh	Mon Oct 06 21:40:33 2008 +0200
@@ -5,8 +5,8 @@
 rm -f obj/*.bc
 rm -f ../lib/*.bc
 
-LLVMDCFLAGS="-c -odobj -oq -gc -noasm"
-LLVMDCFLAGS_ASM="-c -odobj -oq -gc"
+LLVMDCFLAGS_ASM="-c -oq -release"
+LLVMDCFLAGS="$LLVMDCFLAGS_ASM -noasm"
 
 echo "compiling contract runtime"
 llvmdc internal/contract.d -c -of../lib/llvmdcore.bc || exit 1 #-noruntime || exit 1
@@ -16,8 +16,10 @@
         internal/mem.d \
         internal/critical.d \
         internal/dmain2.d \
+        internal/inv.d \
         $LLVMDCFLAGS_ASM || exit 1
 mv *.bc obj
+llvm-link -f -o=../lib/llvmdcore.bc obj/internal.*.bc ../lib/llvmdcore.bc
 
 echo "compiling typeinfo 1"
 ./llvmdc-build typeinfos1.d $LLVMDCFLAGS || exit 1
@@ -47,24 +49,26 @@
 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
+llvmdc internal/qsort2.d internal/adi.d internal/aaA.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
+llvm-link -f -o=../lib/llvmdcore.bc obj/qsort2.bc obj/adi.bc obj/aaA.bc ../lib/llvmdcore.bc || exit 1
 
 echo "compiling object implementation"
-llvmdc internal/objectimpl.d -c -odobj -g || exit 1
+llvmdc internal/objectimpl.d $LLVMDCFLAGS || exit 1
+mv object.bc objectimpl.bc
+mv *.bc obj
 llvm-link -f -o=../lib/llvmdcore.bc obj/objectimpl.bc ../lib/llvmdcore.bc || exit 1
 
+echo "compiling crc32"
+llvmdc crc32.d $LLVMDCFLAGS || exit 1
+mv *.bc obj
+llvm-link -f -o=../lib/llvmdcore.bc ../lib/llvmdcore.bc obj/crc32.bc || exit 1
+
 echo "compiling llvm runtime support"
-./llvmdc-build llvmsupport.d $LLVMDCFLAGS || exit 1
+# ./llvmdc-build llvmsupport.d $LLVMDCFLAGS || exit 1
+llvmdc llvmsupport.d -oq -c || exit 1
 mv *.bc obj
-llvm-link -f -o=../lib/llvmdcore.bc `ls obj/llvm.*.bc` ../lib/llvmdcore.bc || exit 1
+llvm-link -f -o=../lib/llvmdcore.bc `ls obj/llvm*.bc` ../lib/llvmdcore.bc || exit 1
 
 echo "compiling garbage collector"
 cd gc
@@ -72,17 +76,22 @@
 # 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
+# llvmdc gc.d -oq -c -I.. || exit 1
+mv std.gc.bc std_gc.bc
 mv *.bc ../obj
+# mv -v obj/*.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
+llvm-link -f -o=../lib/llvmdcore.bc obj/gclinux.bc obj/gcx.bc obj/gcbits.bc obj/std_gc.bc ../lib/llvmdcore.bc || exit 1
 
 echo "compiling phobos"
 ./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
+# llvm-link -f -o=../lib/llvmdcore.bc `ls obj/std.*.bc` ../lib/llvmdcore.bc || exit 1
+for i in $(ls obj/std.*.bc); do
+	echo $i
+	llvm-link -f -o=../lib/llvmdcore.bc ../lib/llvmdcore.bc $i || exit 1
+done
 
 echo "Compiling auxiliary"
 ./llvmdc-build etc/c/zlib.d $LLVMDCFLAGS || exit 1
@@ -90,7 +99,6 @@
 llvm-link -f -o=../lib/llvmdcore.bc `ls obj/etc.*.bc` ../lib/llvmdcore.bc || exit 1
 
 echo "optimizing"
-opt -stats -p -f -std-compile-opts -disable-inlining -o=../lib/llvmdcore.bc ../lib/llvmdcore.bc || exit 1
-
+opt -stats -p -f -std-compile-opts -o=../lib/llvmdcore.bc ../lib/llvmdcore.bc || exit 1
 
 echo "SUCCESS"
--- a/lphobos/gc/gc.d	Mon Oct 06 21:27:29 2008 +0200
+++ b/lphobos/gc/gc.d	Mon Oct 06 21:40:33 2008 +0200
@@ -276,6 +276,10 @@
     _d_OutOfMemory();
 }
 
+void* _d_newarrayvT(TypeInfo ti, size_t length) {
+  return _d_newarrayT(ti, length);
+}
+
 /* For when the array has a non-zero initializer.
  */
 void* _d_newarrayiT(TypeInfo ti, size_t length)
@@ -1025,4 +1029,6 @@
     void* ptr;
 }*/
 
-extern(C) void* _d_allocmemoryT(size_t foo) { return malloc(foo).ptr; }
+extern(C) void* _d_allocmemoryT(TypeInfo ti) {
+  return malloc(ti.tsize).ptr; // Tit size :)
+}
--- a/lphobos/internal/adi.d	Mon Oct 06 21:27:29 2008 +0200
+++ b/lphobos/internal/adi.d	Mon Oct 06 21:40:33 2008 +0200
@@ -1,838 +1,838 @@
-//_ adi.d
-
-/**
- * Part of the D programming language runtime library.
- * Dynamic array property support routines
- */
-
-/*
- *  Copyright (C) 2000-2006 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, 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
- *     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.
- */
-
-//debug=adi;        // uncomment to turn on debugging printf's
-
-//import std.stdio;
-import std.c.stdio;
-import std.c.stdlib;
-import std.c.string;
-//import std.string;
-import std.outofmemory;
-import std.utf;
-
-pragma(no_typeinfo)
-struct Array
-{
-    size_t length;
-    void* ptr;
-}
-
-/**********************************************
- * Reverse array of chars.
- * Handled separately because embedded multibyte encodings should not be
- * reversed.
- */
-
-extern (C) char[] _adReverseChar(char[] a)
-{
-    if (a.length > 1)
-    {
-    char[6] tmp;
-    char[6] tmplo;
-    char* lo = a.ptr;
-    char* hi = &a[length - 1];
-
-    while (lo < hi)
-    {   auto clo = *lo;
-        auto chi = *hi;
-
-        //printf("lo = %d, hi = %d\n", lo, hi);
-        if (clo <= 0x7F && chi <= 0x7F)
-        {
-        //printf("\tascii\n");
-        *lo = chi;
-        *hi = clo;
-        lo++;
-        hi--;
-        continue;
-        }
-
-        uint stridelo = std.utf.UTF8stride[clo];
-
-        uint stridehi = 1;
-        while ((chi & 0xC0) == 0x80)
-        {
-        chi = *--hi;
-        stridehi++;
-        assert(hi >= lo);
-        }
-        if (lo == hi)
-        break;
-
-        //printf("\tstridelo = %d, stridehi = %d\n", stridelo, stridehi);
-        if (stridelo == stridehi)
-        {
-
-        memcpy(tmp.ptr, lo, stridelo);
-        memcpy(lo, hi, stridelo);
-        memcpy(hi, tmp.ptr, stridelo);
-        lo += stridelo;
-        hi--;
-        continue;
-        }
-
-        /* Shift the whole array. This is woefully inefficient
-         */
-        memcpy(tmp.ptr, hi, stridehi);
-        memcpy(tmplo.ptr, lo, stridelo);
-        memmove(lo + stridehi, lo + stridelo , (hi - lo) - stridelo);
-        memcpy(lo, tmp.ptr, stridehi);
-        memcpy(hi + stridehi - stridelo, tmplo.ptr, stridelo);
-
-        lo += stridehi;
-        hi = hi - 1 + (stridehi - stridelo);
-    }
-    }
-    return a;
-}
-
-unittest
-{
-    string a = "abcd";
-    string r;
-
-    r = a.dup.reverse;
-    //writefln(r);
-    assert(r == "dcba");
-
-    a = "a\u1235\u1234c";
-    //writefln(a);
-    r = a.dup.reverse;
-    //writefln(r);
-    assert(r == "c\u1234\u1235a");
-
-    a = "ab\u1234c";
-    //writefln(a);
-    r = a.dup.reverse;
-    //writefln(r);
-    assert(r == "c\u1234ba");
-
-    a = "\u3026\u2021\u3061\n";
-    r = a.dup.reverse;
-    assert(r == "\n\u3061\u2021\u3026");
-}
-
-
-/**********************************************
- * Reverse array of wchars.
- * Handled separately because embedded multiword encodings should not be
- * reversed.
- */
-
-extern (C) wchar[] _adReverseWchar(wchar[] a)
-{
-    if (a.length > 1)
-    {
-    wchar[2] tmp;
-    wchar* lo = a.ptr;
-    wchar* hi = &a[length - 1];
-
-    while (lo < hi)
-    {   auto clo = *lo;
-        auto chi = *hi;
-
-        if ((clo < 0xD800 || clo > 0xDFFF) &&
-        (chi < 0xD800 || chi > 0xDFFF))
-        {
-        *lo = chi;
-        *hi = clo;
-        lo++;
-        hi--;
-        continue;
-        }
-
-        int stridelo = 1 + (clo >= 0xD800 && clo <= 0xDBFF);
-
-        int stridehi = 1;
-        if (chi >= 0xDC00 && chi <= 0xDFFF)
-        {
-        chi = *--hi;
-        stridehi++;
-        assert(hi >= lo);
-        }
-        if (lo == hi)
-        break;
-
-        if (stridelo == stridehi)
-        {   int stmp;
-
-        assert(stridelo == 2);
-        assert(stmp.sizeof == 2 * (*lo).sizeof);
-        stmp = *cast(int*)lo;
-        *cast(int*)lo = *cast(int*)hi;
-        *cast(int*)hi = stmp;
-        lo += stridelo;
-        hi--;
-        continue;
-        }
-
-        /* Shift the whole array. This is woefully inefficient
-         */
-        memcpy(tmp.ptr, hi, stridehi * wchar.sizeof);
-        memcpy(hi + stridehi - stridelo, lo, stridelo * wchar.sizeof);
-        memmove(lo + stridehi, lo + stridelo , (hi - (lo + stridelo)) * wchar.sizeof);
-        memcpy(lo, tmp.ptr, stridehi * wchar.sizeof);
-
-        lo += stridehi;
-        hi = hi - 1 + (stridehi - stridelo);
-    }
-    }
-    return a;
-}
-
-unittest
-{
-    wstring a = "abcd";
-    wstring r;
-
-    r = a.dup.reverse;
-    assert(r == "dcba");
-
-    a = "a\U00012356\U00012346c";
-    r = a.dup.reverse;
-    assert(r == "c\U00012346\U00012356a");
-
-    a = "ab\U00012345c";
-    r = a.dup.reverse;
-    assert(r == "c\U00012345ba");
-}
-
-
-/**********************************************
- * Support for array.reverse property.
- */
-
-extern (C) Array _adReverse(Array a, size_t szelem)
-{
-    if (a.length >= 2)
-    {
-        byte* tmp;
-        byte[16] buffer;
-
-        void* lo = a.ptr;
-        void* hi = a.ptr + (a.length - 1) * szelem;
-
-        tmp = buffer.ptr;
-        if (szelem > 16)
-        {
-        //version (Win32)
-            tmp = cast(byte*) alloca(szelem);
-        //else
-            //tmp = new byte[szelem];
-        }
-
-        for (; lo < hi; lo += szelem, hi -= szelem)
-        {
-        memcpy(tmp, lo,  szelem);
-        memcpy(lo,  hi,  szelem);
-        memcpy(hi,  tmp, szelem);
-        }
-
-        version (Win32)
-        {
-        }
-        else
-        {
-        //if (szelem > 16)
-            // BUG: bad code is generate for delete pointer, tries
-            // to call delclass.
-            //delete tmp;
-        }
-    }
-    return a;
-}
-
-unittest
-{
-    debug(adi) printf("array.reverse.unittest\n");
-
-    int[] a = new int[5];
-    int[] b;
-    size_t i;
-
-    for (i = 0; i < 5; i++)
-    a[i] = i;
-    b = a.reverse;
-    assert(b is a);
-    for (i = 0; i < 5; i++)
-    assert(a[i] == 4 - i);
-
-    struct X20
-    {   // More than 16 bytes in size
-    int a;
-    int b, c, d, e;
-    }
-
-    X20[] c = new X20[5];
-    X20[] d;
-
-    for (i = 0; i < 5; i++)
-    {   c[i].a = i;
-    c[i].e = 10;
-    }
-    d = c.reverse;
-    assert(d is c);
-    for (i = 0; i < 5; i++)
-    {
-    assert(c[i].a == 4 - i);
-    assert(c[i].e == 10);
-    }
-}
-
-/**********************************************
- * Support for array.reverse property for bit[].
- */
-
-version (none)
-{
-extern (C) bit[] _adReverseBit(bit[] a)
-    out (result)
-    {
-    assert(result is a);
-    }
-    body
-    {
-    if (a.length >= 2)
-    {
-        bit t;
-        int lo, hi;
-
-        lo = 0;
-        hi = a.length - 1;
-        for (; lo < hi; lo++, hi--)
-        {
-        t = a[lo];
-        a[lo] = a[hi];
-        a[hi] = t;
-        }
-    }
-    return a;
-    }
-
-unittest
-{
-    debug(adi) printf("array.reverse_Bit[].unittest\n");
-
-    bit[] b;
-    b = new bit[5];
-    static bit[5] data = [1,0,1,1,0];
-    int i;
-
-    b[] = data[];
-    b.reverse;
-    for (i = 0; i < 5; i++)
-    {
-    assert(b[i] == data[4 - i]);
-    }
-}
-}
-
-/**********************************************
- * Sort array of chars.
- */
-
-extern (C) char[] _adSortChar(char[] a)
-{
-    if (a.length > 1)
-    {
-    dstring da = toUTF32(a);
-    da.sort;
-    size_t i = 0;
-    foreach (dchar d; da)
-    {   char[4] buf;
-        string t = toUTF8(buf, d);
-        a[i .. i + t.length] = t[];
-        i += t.length;
-    }
-    delete da;
-    }
-    return a;
-}
-
-/**********************************************
- * Sort array of wchars.
- */
-
-extern (C) wchar[] _adSortWchar(wchar[] a)
-{
-    if (a.length > 1)
-    {
-    dstring da = toUTF32(a);
-    da.sort;
-    size_t i = 0;
-    foreach (dchar d; da)
-    {   wchar[2] buf;
-        wstring t = toUTF16(buf, d);
-        a[i .. i + t.length] = t[];
-        i += t.length;
-    }
-    delete da;
-    }
-    return a;
-}
-
-/**********************************************
- * Support for array.sort property for bit[].
- */
-
-version (none)
-{
-extern (C) bit[] _adSortBit(bit[] a)
-    out (result)
-    {
-    assert(result is a);
-    }
-    body
-    {
-    if (a.length >= 2)
-    {
-        size_t lo, hi;
-
-        lo = 0;
-        hi = a.length - 1;
-        while (1)
-        {
-        while (1)
-        {
-            if (lo >= hi)
-            goto Ldone;
-            if (a[lo] == true)
-            break;
-            lo++;
-        }
-
-        while (1)
-        {
-            if (lo >= hi)
-            goto Ldone;
-            if (a[hi] == false)
-            break;
-            hi--;
-        }
-
-        a[lo] = false;
-        a[hi] = true;
-
-        lo++;
-        hi--;
-        }
-    Ldone:
-        ;
-    }
-    return a;
-    }
-
-unittest
-{
-    debug(adi) printf("array.sort_Bit[].unittest\n");
-}
-}
-
-/***************************************
- * Support for array equality test.
- */
-
-extern (C) int _adEq(Array a1, Array a2, TypeInfo ti)
-{
-    // 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.next.tsize();
-    auto p1 = a1.ptr;
-    auto p2 = a2.ptr;
-    
-/+
-    for (int i = 0; i < a1.length; i++)
-    {
-    printf("%4x %4x\n", (cast(short*)p1)[i], (cast(short*)p2)[i]);
-    }
-    printf("sz = %u\n", sz);
-+/
-
-    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.next.equals(p1 + i * sz, p2 + i * sz))
-        return 0;       // not equal
-    }
-    return 1;           // equal
-}
-
-unittest
-{
-    debug(adi) printf("array.Eq unittest\n");
-
-    string a = "hello";
-
-    assert(a != "hel");
-    assert(a != "helloo");
-    assert(a != "betty");
-    assert(a == "hello");
-    assert(a != "hxxxx");
-}
-
-/***************************************
- * Support for bit array equality test for bit arrays.
- */
-
-version (none)
-{
-extern (C) int _adEqBit(Array a1, Array a2)
-{   size_t i;
-
-    if (a1.length != a2.length)
-    return 0;       // not equal
-    auto p1 = cast(byte*)a1.ptr;
-    auto p2 = cast(byte*)a2.ptr;
-    auto n = a1.length / 8;
-    for (i = 0; i < n; i++)
-    {
-    if (p1[i] != p2[i])
-        return 0;       // not equal
-    }
-
-    ubyte mask;
-
-    n = a1.length & 7;
-    mask = cast(ubyte)((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(adi) printf("array.EqBit unittest\n");
-
-    static bit[] a = [1,0,1,0,1];
-    static bit[] b = [1,0,1];
-    static bit[] c = [1,0,1,0,1,0,1];
-    static bit[] d = [1,0,1,1,1];
-    static bit[] e = [1,0,1,0,1];
-
-    assert(a != b);
-    assert(a != c);
-    assert(a != d);
-    assert(a == e);
-}
-}
-
-/***************************************
- * Support for array compare test.
- */
-
-extern (C) int _adCmp(Array a1, Array a2, TypeInfo ti)
-{
-    //printf("adCmp()\n");
-    auto len = a1.length;
-    if (a2.length < len)
-    len = a2.length;
-    auto sz = ti.tsize();
-    void *p1 = a1.ptr;
-    void *p2 = a2.ptr;
-
-    if (sz == 1)
-    {   // We should really have a ti.isPOD() check for this
-    auto c = memcmp(p1, p2, len);
-    if (c)
-        return c;
-    }
-    else
-    {
-    for (size_t i = 0; i < len; i++)
-    {
-        auto c = ti.compare(p1 + i * sz, p2 + i * sz);
-        if (c)
-        return c;
-    }
-    }
-    if (a1.length == a2.length)
-    return 0;
-    return (a1.length > a2.length) ? 1 : -1;
-}
-
-unittest
-{
-    debug(adi) printf("array.Cmp unittest\n");
-
-    string a = "hello";
-
-    assert(a >  "hel");
-    assert(a >= "hel");
-    assert(a <  "helloo");
-    assert(a <= "helloo");
-    assert(a >  "betty");
-    assert(a >= "betty");
-    assert(a == "hello");
-    assert(a <= "hello");
-    assert(a >= "hello");
-}
-
-/***************************************
- * Support for char array compare test.
- */
-
-extern (C) int _adCmpChar(Array a1, Array a2)
-{
-version (D_InlineAsm_X86)
-{
-    asm
-    {   naked           ;
-
-        push    EDI     ;
-        push    ESI     ;
-
-        mov    ESI,a1+4[4+ESP]  ;
-        mov    EDI,a2+4[4+ESP]  ;
-
-        mov    ECX,a1[4+ESP]    ;
-        mov    EDX,a2[4+ESP]    ;
-
-    cmp ECX,EDX     ;
-    jb  GotLength   ;
-
-    mov ECX,EDX     ;
-
-GotLength:
-        cmp    ECX,4        ;
-        jb    DoBytes       ;
-
-        // Do alignment if neither is dword aligned
-        test    ESI,3       ;
-        jz    Aligned       ;
-
-        test    EDI,3       ;
-        jz    Aligned       ;
-DoAlign:
-        mov    AL,[ESI]     ; //align ESI to dword bounds
-        mov    DL,[EDI]     ;
-
-        cmp    AL,DL        ;
-        jnz    Unequal      ;
-
-        inc    ESI      ;
-        inc    EDI      ;
-
-        test    ESI,3       ;
-
-        lea    ECX,[ECX-1]  ;
-        jnz    DoAlign      ;
-Aligned:
-        mov    EAX,ECX      ;
-
-    // do multiple of 4 bytes at a time
-
-        shr    ECX,2        ;
-        jz    TryOdd        ;
-
-        repe            ;
-    cmpsd           ;
-
-        jnz    UnequalQuad  ;
-
-TryOdd:
-        mov    ECX,EAX      ;
-DoBytes:
-    // if still equal and not end of string, do up to 3 bytes slightly
-    // slower.
-
-        and    ECX,3        ;
-        jz    Equal     ;
-
-        repe            ;
-    cmpsb           ;
-
-        jnz    Unequal      ;
-Equal:
-        mov    EAX,a1[4+ESP]    ;
-        mov    EDX,a2[4+ESP]    ;
-
-        sub    EAX,EDX      ;
-        pop    ESI      ;
-
-        pop    EDI      ;
-        ret         ;
-
-UnequalQuad:
-        mov    EDX,[EDI-4]  ;
-        mov    EAX,[ESI-4]  ;
-
-        cmp    AL,DL        ;
-        jnz    Unequal      ;
-
-        cmp    AH,DH        ;
-        jnz    Unequal      ;
-
-        shr    EAX,16       ;
-
-        shr    EDX,16       ;
-
-        cmp    AL,DL        ;
-        jnz    Unequal      ;
-
-        cmp    AH,DH        ;
-Unequal:
-        sbb    EAX,EAX      ;
-        pop    ESI      ;
-
-        or     EAX,1        ;
-        pop    EDI      ;
-
-        ret         ;
-    }
-}
-else
-{
-    int len;
-    int c;
-
-    //printf("adCmpChar()\n");
-    len = a1.length;
-    if (a2.length < len)
-    len = a2.length;
-    c = memcmp(cast(char *)a1.ptr, cast(char *)a2.ptr, len);
-    if (!c)
-    c = cast(int)a1.length - cast(int)a2.length;
-    return c;
-}
-}
-
-unittest
-{
-    debug(adi) printf("array.CmpChar unittest\n");
-
-    string a = "hello";
-
-    assert(a >  "hel");
-    assert(a >= "hel");
-    assert(a <  "helloo");
-    assert(a <= "helloo");
-    assert(a >  "betty");
-    assert(a >= "betty");
-    assert(a == "hello");
-    assert(a <= "hello");
-    assert(a >= "hello");
-}
-
-/***************************************
- * Support for bit array compare test.
- */
-
-version (none)
-{
-extern (C) int _adCmpBit(Array a1, Array a2)
-{
-    int len;
-    uint i;
-
-    len = a1.length;
-    if (a2.length < len)
-    len = a2.length;
-    ubyte *p1 = cast(ubyte*)a1.ptr;
-    ubyte *p2 = cast(ubyte*)a2.ptr;
-    uint n = len / 8;
-    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;
-    }
-    return cast(int)a1.length - cast(int)a2.length;
-}
-
-unittest
-{
-    debug(adi) printf("array.CmpBit unittest\n");
-
-    static bit[] a = [1,0,1,0,1];
-    static bit[] b = [1,0,1];
-    static bit[] c = [1,0,1,0,1,0,1];
-    static bit[] d = [1,0,1,1,1];
-    static bit[] e = [1,0,1,0,1];
-
-    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);
-}
-}
-
-/**********************************
- * Support for array.dup property.
- */
-
-extern(C)
-void* _d_realloc(void*, size_t);
-
-extern(C)
-Array _adDupT(TypeInfo ti, Array a)
-{
-    Array r;
-    if (a.length)
-    {
-        auto sizeelem = ti.next.tsize();        // array element size
-        auto size = a.length * sizeelem;
-        r.ptr = _d_realloc(null,size);
-        r.length = a.length;
-        memcpy(r.ptr, a.ptr, size);
-    }
-    return r;
-}
-
-unittest
-{
-    int[] a;
-    int[] b;
-    int i;
-
-    debug(adi) printf("array.dup.unittest\n");
-
-    a = new int[3];
-    a[0] = 1; a[1] = 2; a[2] = 3;
-    b = a.dup;
-    assert(b.length == 3);
-    for (i = 0; i < 3; i++)
-    assert(b[i] == i + 1);
-}
+//_ adi.d
+
+/**
+ * Part of the D programming language runtime library.
+ * Dynamic array property support routines
+ */
+
+/*
+ *  Copyright (C) 2000-2006 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, 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
+ *     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.
+ */
+
+//debug=adi;        // uncomment to turn on debugging printf's
+
+//import std.stdio;
+import std.c.stdio;
+import std.c.stdlib;
+import std.c.string;
+//import std.string;
+import std.outofmemory;
+import std.utf;
+
+pragma(no_typeinfo)
+struct Array
+{
+    size_t length;
+    void* ptr;
+}
+
+/**********************************************
+ * Reverse array of chars.
+ * Handled separately because embedded multibyte encodings should not be
+ * reversed.
+ */
+
+extern (C) char[] _adReverseChar(char[] a)
+{
+    if (a.length > 1)
+    {
+    char[6] tmp;
+    char[6] tmplo;
+    char* lo = a.ptr;
+    char* hi = &a[length - 1];
+
+    while (lo < hi)
+    {   auto clo = *lo;
+        auto chi = *hi;
+
+        //printf("lo = %d, hi = %d\n", lo, hi);
+        if (clo <= 0x7F && chi <= 0x7F)
+        {
+        //printf("\tascii\n");
+        *lo = chi;
+        *hi = clo;
+        lo++;
+        hi--;
+        continue;
+        }
+
+        uint stridelo = std.utf.UTF8stride[clo];
+
+        uint stridehi = 1;
+        while ((chi & 0xC0) == 0x80)
+        {
+        chi = *--hi;
+        stridehi++;
+        assert(hi >= lo);
+        }
+        if (lo == hi)
+        break;
+
+        //printf("\tstridelo = %d, stridehi = %d\n", stridelo, stridehi);
+        if (stridelo == stridehi)
+        {
+
+        memcpy(tmp.ptr, lo, stridelo);
+        memcpy(lo, hi, stridelo);
+        memcpy(hi, tmp.ptr, stridelo);
+        lo += stridelo;
+        hi--;
+        continue;
+        }
+
+        /* Shift the whole array. This is woefully inefficient
+         */
+        memcpy(tmp.ptr, hi, stridehi);
+        memcpy(tmplo.ptr, lo, stridelo);
+        memmove(lo + stridehi, lo + stridelo , (hi - lo) - stridelo);
+        memcpy(lo, tmp.ptr, stridehi);
+        memcpy(hi + stridehi - stridelo, tmplo.ptr, stridelo);
+
+        lo += stridehi;
+        hi = hi - 1 + (stridehi - stridelo);
+    }
+    }
+    return a;
+}
+
+unittest
+{
+    string a = "abcd";
+    string r;
+
+    r = a.dup.reverse;
+    //writefln(r);
+    assert(r == "dcba");
+
+    a = "a\u1235\u1234c";
+    //writefln(a);
+    r = a.dup.reverse;
+    //writefln(r);
+    assert(r == "c\u1234\u1235a");
+
+    a = "ab\u1234c";
+    //writefln(a);
+    r = a.dup.reverse;
+    //writefln(r);
+    assert(r == "c\u1234ba");
+
+    a = "\u3026\u2021\u3061\n";
+    r = a.dup.reverse;
+    assert(r == "\n\u3061\u2021\u3026");
+}
+
+
+/**********************************************
+ * Reverse array of wchars.
+ * Handled separately because embedded multiword encodings should not be
+ * reversed.
+ */
+
+extern (C) wchar[] _adReverseWchar(wchar[] a)
+{
+    if (a.length > 1)
+    {
+    wchar[2] tmp;
+    wchar* lo = a.ptr;
+    wchar* hi = &a[length - 1];
+
+    while (lo < hi)
+    {   auto clo = *lo;
+        auto chi = *hi;
+
+        if ((clo < 0xD800 || clo > 0xDFFF) &&
+        (chi < 0xD800 || chi > 0xDFFF))
+        {
+        *lo = chi;
+        *hi = clo;
+        lo++;
+        hi--;
+        continue;
+        }
+
+        int stridelo = 1 + (clo >= 0xD800 && clo <= 0xDBFF);
+
+        int stridehi = 1;
+        if (chi >= 0xDC00 && chi <= 0xDFFF)
+        {
+        chi = *--hi;
+        stridehi++;
+        assert(hi >= lo);
+        }
+        if (lo == hi)
+        break;
+
+        if (stridelo == stridehi)
+        {   int stmp;
+
+        assert(stridelo == 2);
+        assert(stmp.sizeof == 2 * (*lo).sizeof);
+        stmp = *cast(int*)lo;
+        *cast(int*)lo = *cast(int*)hi;
+        *cast(int*)hi = stmp;
+        lo += stridelo;
+        hi--;
+        continue;
+        }
+
+        /* Shift the whole array. This is woefully inefficient
+         */
+        memcpy(tmp.ptr, hi, stridehi * wchar.sizeof);
+        memcpy(hi + stridehi - stridelo, lo, stridelo * wchar.sizeof);
+        memmove(lo + stridehi, lo + stridelo , (hi - (lo + stridelo)) * wchar.sizeof);
+        memcpy(lo, tmp.ptr, stridehi * wchar.sizeof);
+
+        lo += stridehi;
+        hi = hi - 1 + (stridehi - stridelo);
+    }
+    }
+    return a;
+}
+
+unittest
+{
+    wstring a = "abcd";
+    wstring r;
+
+    r = a.dup.reverse;
+    assert(r == "dcba");
+
+    a = "a\U00012356\U00012346c";
+    r = a.dup.reverse;
+    assert(r == "c\U00012346\U00012356a");
+
+    a = "ab\U00012345c";
+    r = a.dup.reverse;
+    assert(r == "c\U00012345ba");
+}
+
+
+/**********************************************
+ * Support for array.reverse property.
+ */
+
+extern (C) Array _adReverse(Array a, size_t szelem)
+{
+    if (a.length >= 2)
+    {
+        byte* tmp;
+        byte[16] buffer;
+
+        void* lo = a.ptr;
+        void* hi = a.ptr + (a.length - 1) * szelem;
+
+        tmp = buffer.ptr;
+        if (szelem > 16)
+        {
+        //version (Win32)
+            //tmp = cast(byte*) alloca(szelem);
+        //else
+            tmp = (new byte[szelem]).ptr;
+        }
+
+        for (; lo < hi; lo += szelem, hi -= szelem)
+        {
+        memcpy(tmp, lo,  szelem);
+        memcpy(lo,  hi,  szelem);
+        memcpy(hi,  tmp, szelem);
+        }
+
+        version (Win32)
+        {
+        }
+        else
+        {
+        //if (szelem > 16)
+            // BUG: bad code is generate for delete pointer, tries
+            // to call delclass.
+            //delete tmp;
+        }
+    }
+    return a;
+}
+
+unittest
+{
+    debug(adi) printf("array.reverse.unittest\n");
+
+    int[] a = new int[5];
+    int[] b;
+    size_t i;
+
+    for (i = 0; i < 5; i++)
+    a[i] = i;
+    b = a.reverse;
+    assert(b is a);
+    for (i = 0; i < 5; i++)
+    assert(a[i] == 4 - i);
+
+    struct X20
+    {   // More than 16 bytes in size
+    int a;
+    int b, c, d, e;
+    }
+
+    X20[] c = new X20[5];
+    X20[] d;
+
+    for (i = 0; i < 5; i++)
+    {   c[i].a = i;
+    c[i].e = 10;
+    }
+    d = c.reverse;
+    assert(d is c);
+    for (i = 0; i < 5; i++)
+    {
+    assert(c[i].a == 4 - i);
+    assert(c[i].e == 10);
+    }
+}
+
+/**********************************************
+ * Support for array.reverse property for bit[].
+ */
+
+version (none)
+{
+extern (C) bit[] _adReverseBit(bit[] a)
+    out (result)
+    {
+    assert(result is a);
+    }
+    body
+    {
+    if (a.length >= 2)
+    {
+        bit t;
+        int lo, hi;
+
+        lo = 0;
+        hi = a.length - 1;
+        for (; lo < hi; lo++, hi--)
+        {
+        t = a[lo];
+        a[lo] = a[hi];
+        a[hi] = t;
+        }
+    }
+    return a;
+    }
+
+unittest
+{
+    debug(adi) printf("array.reverse_Bit[].unittest\n");
+
+    bit[] b;
+    b = new bit[5];
+    static bit[5] data = [1,0,1,1,0];
+    int i;
+
+    b[] = data[];
+    b.reverse;
+    for (i = 0; i < 5; i++)
+    {
+    assert(b[i] == data[4 - i]);
+    }
+}
+}
+
+/**********************************************
+ * Sort array of chars.
+ */
+
+extern (C) char[] _adSortChar(char[] a)
+{
+    if (a.length > 1)
+    {
+    dstring da = toUTF32(a);
+    da.sort;
+    size_t i = 0;
+    foreach (dchar d; da)
+    {   char[4] buf;
+        string t = toUTF8(buf, d);
+        a[i .. i + t.length] = t[];
+        i += t.length;
+    }
+    delete da;
+    }
+    return a;
+}
+
+/**********************************************
+ * Sort array of wchars.
+ */
+
+extern (C) wchar[] _adSortWchar(wchar[] a)
+{
+    if (a.length > 1)
+    {
+    dstring da = toUTF32(a);
+    da.sort;
+    size_t i = 0;
+    foreach (dchar d; da)
+    {   wchar[2] buf;
+        wstring t = toUTF16(buf, d);
+        a[i .. i + t.length] = t[];
+        i += t.length;
+    }
+    delete da;
+    }
+    return a;
+}
+
+/**********************************************
+ * Support for array.sort property for bit[].
+ */
+
+version (none)
+{
+extern (C) bit[] _adSortBit(bit[] a)
+    out (result)
+    {
+    assert(result is a);
+    }
+    body
+    {
+    if (a.length >= 2)
+    {
+        size_t lo, hi;
+
+        lo = 0;
+        hi = a.length - 1;
+        while (1)
+        {
+        while (1)
+        {
+            if (lo >= hi)
+            goto Ldone;
+            if (a[lo] == true)
+            break;
+            lo++;
+        }
+
+        while (1)
+        {
+            if (lo >= hi)
+            goto Ldone;
+            if (a[hi] == false)
+            break;
+            hi--;
+        }
+
+        a[lo] = false;
+        a[hi] = true;
+
+        lo++;
+        hi--;
+        }
+    Ldone:
+        ;
+    }
+    return a;
+    }
+
+unittest
+{
+    debug(adi) printf("array.sort_Bit[].unittest\n");
+}
+}
+
+/***************************************
+ * Support for array equality test.
+ */
+
+extern (C) int _adEq(Array a1, Array a2, TypeInfo ti)
+{
+    // 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.next.tsize();
+    auto p1 = a1.ptr;
+    auto p2 = a2.ptr;
+    
+/+
+    for (int i = 0; i < a1.length; i++)
+    {
+    printf("%4x %4x\n", (cast(short*)p1)[i], (cast(short*)p2)[i]);
+    }
+    printf("sz = %u\n", sz);
++/
+
+    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.next.equals(p1 + i * sz, p2 + i * sz))
+        return 0;       // not equal
+    }
+    return 1;           // equal
+}
+
+unittest
+{
+    debug(adi) printf("array.Eq unittest\n");
+
+    string a = "hello";
+
+    assert(a != "hel");
+    assert(a != "helloo");
+    assert(a != "betty");
+    assert(a == "hello");
+    assert(a != "hxxxx");
+}
+
+/***************************************
+ * Support for bit array equality test for bit arrays.
+ */
+
+version (none)
+{
+extern (C) int _adEqBit(Array a1, Array a2)
+{   size_t i;
+
+    if (a1.length != a2.length)
+    return 0;       // not equal
+    auto p1 = cast(byte*)a1.ptr;
+    auto p2 = cast(byte*)a2.ptr;
+    auto n = a1.length / 8;
+    for (i = 0; i < n; i++)
+    {
+    if (p1[i] != p2[i])
+        return 0;       // not equal
+    }
+
+    ubyte mask;
+
+    n = a1.length & 7;
+    mask = cast(ubyte)((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(adi) printf("array.EqBit unittest\n");
+
+    static bit[] a = [1,0,1,0,1];
+    static bit[] b = [1,0,1];
+    static bit[] c = [1,0,1,0,1,0,1];
+    static bit[] d = [1,0,1,1,1];
+    static bit[] e = [1,0,1,0,1];
+
+    assert(a != b);
+    assert(a != c);
+    assert(a != d);
+    assert(a == e);
+}
+}
+
+/***************************************
+ * Support for array compare test.
+ */
+
+extern (C) int _adCmp(Array a1, Array a2, TypeInfo ti)
+{
+    //printf("adCmp()\n");
+    auto len = a1.length;
+    if (a2.length < len)
+    len = a2.length;
+    auto sz = ti.tsize();
+    void *p1 = a1.ptr;
+    void *p2 = a2.ptr;
+
+    if (sz == 1)
+    {   // We should really have a ti.isPOD() check for this
+    auto c = memcmp(p1, p2, len);
+    if (c)
+        return c;
+    }
+    else
+    {
+    for (size_t i = 0; i < len; i++)
+    {
+        auto c = ti.compare(p1 + i * sz, p2 + i * sz);
+        if (c)
+        return c;
+    }
+    }
+    if (a1.length == a2.length)
+    return 0;
+    return (a1.length > a2.length) ? 1 : -1;
+}
+
+unittest
+{
+    debug(adi) printf("array.Cmp unittest\n");
+
+    string a = "hello";
+
+    assert(a >  "hel");
+    assert(a >= "hel");
+    assert(a <  "helloo");
+    assert(a <= "helloo");
+    assert(a >  "betty");
+    assert(a >= "betty");
+    assert(a == "hello");
+    assert(a <= "hello");
+    assert(a >= "hello");
+}
+
+/***************************************
+ * Support for char array compare test.
+ */
+
+extern (C) int _adCmpChar(Array a1, Array a2)
+{
+version (D_InlineAsm_X86)
+{
+    asm
+    {   naked           ;
+
+        push    EDI     ;
+        push    ESI     ;
+
+        mov    ESI,a1+4[4+ESP]  ;
+        mov    EDI,a2+4[4+ESP]  ;
+
+        mov    ECX,a1[4+ESP]    ;
+        mov    EDX,a2[4+ESP]    ;
+
+    cmp ECX,EDX     ;
+    jb  GotLength   ;
+
+    mov ECX,EDX     ;
+
+GotLength:
+        cmp    ECX,4        ;
+        jb    DoBytes       ;
+
+        // Do alignment if neither is dword aligned
+        test    ESI,3       ;
+        jz    Aligned       ;
+
+        test    EDI,3       ;
+        jz    Aligned       ;
+DoAlign:
+        mov    AL,[ESI]     ; //align ESI to dword bounds
+        mov    DL,[EDI]     ;
+
+        cmp    AL,DL        ;
+        jnz    Unequal      ;
+
+        inc    ESI      ;
+        inc    EDI      ;
+
+        test    ESI,3       ;
+
+        lea    ECX,[ECX-1]  ;
+        jnz    DoAlign      ;
+Aligned:
+        mov    EAX,ECX      ;
+
+    // do multiple of 4 bytes at a time
+
+        shr    ECX,2        ;
+        jz    TryOdd        ;
+
+        repe            ;
+    cmpsd           ;
+
+        jnz    UnequalQuad  ;
+
+TryOdd:
+        mov    ECX,EAX      ;
+DoBytes:
+    // if still equal and not end of string, do up to 3 bytes slightly
+    // slower.
+
+        and    ECX,3        ;
+        jz    Equal     ;
+
+        repe            ;
+    cmpsb           ;
+
+        jnz    Unequal      ;
+Equal:
+        mov    EAX,a1[4+ESP]    ;
+        mov    EDX,a2[4+ESP]    ;
+
+        sub    EAX,EDX      ;
+        pop    ESI      ;
+
+        pop    EDI      ;
+        ret         ;
+
+UnequalQuad:
+        mov    EDX,[EDI-4]  ;
+        mov    EAX,[ESI-4]  ;
+
+        cmp    AL,DL        ;
+        jnz    Unequal      ;
+
+        cmp    AH,DH        ;
+        jnz    Unequal      ;
+
+        shr    EAX,16       ;
+
+        shr    EDX,16       ;
+
+        cmp    AL,DL        ;
+        jnz    Unequal      ;
+
+        cmp    AH,DH        ;
+Unequal:
+        sbb    EAX,EAX      ;
+        pop    ESI      ;
+
+        or     EAX,1        ;
+        pop    EDI      ;
+
+        ret         ;
+    }
+}
+else
+{
+    int len;
+    int c;
+
+    //printf("adCmpChar()\n");
+    len = a1.length;
+    if (a2.length < len)
+    len = a2.length;
+    c = memcmp(cast(char *)a1.ptr, cast(char *)a2.ptr, len);
+    if (!c)
+    c = cast(int)a1.length - cast(int)a2.length;
+    return c;
+}
+}
+
+unittest
+{
+    debug(adi) printf("array.CmpChar unittest\n");
+
+    string a = "hello";
+
+    assert(a >  "hel");
+    assert(a >= "hel");
+    assert(a <  "helloo");
+    assert(a <= "helloo");
+    assert(a >  "betty");
+    assert(a >= "betty");
+    assert(a == "hello");
+    assert(a <= "hello");
+    assert(a >= "hello");
+}
+
+/***************************************
+ * Support for bit array compare test.
+ */
+
+version (none)
+{
+extern (C) int _adCmpBit(Array a1, Array a2)
+{
+    int len;
+    uint i;
+
+    len = a1.length;
+    if (a2.length < len)
+    len = a2.length;
+    ubyte *p1 = cast(ubyte*)a1.ptr;
+    ubyte *p2 = cast(ubyte*)a2.ptr;
+    uint n = len / 8;
+    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;
+    }
+    return cast(int)a1.length - cast(int)a2.length;
+}
+
+unittest
+{
+    debug(adi) printf("array.CmpBit unittest\n");
+
+    static bit[] a = [1,0,1,0,1];
+    static bit[] b = [1,0,1];
+    static bit[] c = [1,0,1,0,1,0,1];
+    static bit[] d = [1,0,1,1,1];
+    static bit[] e = [1,0,1,0,1];
+
+    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);
+}
+}
+
+/**********************************
+ * Support for array.dup property.
+ */
+
+extern(C)
+void* _d_realloc(void*, size_t);
+
+extern(C)
+Array _adDupT(TypeInfo ti, Array a)
+{
+    Array r;
+    if (a.length)
+    {
+        auto sizeelem = ti.next.tsize();        // array element size
+        auto size = a.length * sizeelem;
+        r.ptr = _d_realloc(null,size);
+        r.length = a.length;
+        memcpy(r.ptr, a.ptr, size);
+    }
+    return r;
+}
+
+unittest
+{
+    int[] a;
+    int[] b;
+    int i;
+
+    debug(adi) printf("array.dup.unittest\n");
+
+    a = new int[3];
+    a[0] = 1; a[1] = 2; a[2] = 3;
+    b = a.dup;
+    assert(b.length == 3);
+    for (i = 0; i < 3; i++)
+    assert(b[i] == i + 1);
+}
--- a/lphobos/internal/eh.d	Mon Oct 06 21:27:29 2008 +0200
+++ b/lphobos/internal/eh.d	Mon Oct 06 21:40:33 2008 +0200
@@ -287,8 +287,8 @@
       action_walker += next_action_offset;
   }
   
-  printf("Assertion failure ;_;\n");
-  assert(false);
+  /*printf("Assertion failure ;_;\n");
+  assert(false);*/
 }
 
 // These are the register numbers for SetGR that
@@ -353,12 +353,14 @@
 
 } // end of x86 Linux specific implementation
 
+extern(C) void* malloc(size_t size);
 
 extern(C) void _d_throw_exception(Object e)
 {
     if (e !is null)
     {
-        _d_exception* exc_struct = new _d_exception;
+        // _d_exception* exc_struct = new _d_exception;
+        auto exc_struct = cast(_d_exception*)malloc(_d_exception.sizeof);
         exc_struct.unwind_info.exception_class[] = _d_exception_class;
         exc_struct.exception_object = e;
         printf("Raising exception\n");
--- a/lphobos/llvmdc.conf	Mon Oct 06 21:27:29 2008 +0200
+++ b/lphobos/llvmdc.conf	Mon Oct 06 21:40:33 2008 +0200
@@ -1,4 +1,5 @@
 
 [Environment]
 
-DFLAGS=-I%@P%/../lphobos -I%@P%/../import -L-L%@P%/../lib -R%@P%/../lib
+DFLAGS=-I%@P%/../lphobos -I%@P%/../import -L-L%@P%/../lib
+# -R%@P%/../lib
--- a/lphobos/object.d	Mon Oct 06 21:27:29 2008 +0200
+++ b/lphobos/object.d	Mon Oct 06 21:40:33 2008 +0200
@@ -81,6 +81,7 @@
     OffsetTypeInfo[] offTi();
 }
 
+pragma(no_typeinfo)
 class TypeInfo_Typedef : TypeInfo
 {
     TypeInfo base;
@@ -205,3 +206,4 @@
     this(string msg);
     this(string msg, Error next);
 }
+
--- a/lphobos/std/dateparse.d	Mon Oct 06 21:27:29 2008 +0200
+++ b/lphobos/std/dateparse.d	Mon Oct 06 21:40:33 2008 +0200
@@ -48,7 +48,7 @@
 	*this = DateParse.init;
 
 	//version (Win32)
-	    buffer = (cast(char *)alloca(s.length))[0 .. s.length];
+	    buffer = (cast(char *)/*alloca*/malloc(s.length))[0 .. s.length];
 	//else
 	    //buffer = new char[s.length];
 
--- a/lphobos/std/file.d	Mon Oct 06 21:27:29 2008 +0200
+++ b/lphobos/std/file.d	Mon Oct 06 21:40:33 2008 +0200
@@ -43,6 +43,8 @@
 private import std.regexp;
 private import std.gc;
 
+version(linux) version = Unix;
+
 /* =========================== Win32 ======================= */
 
 version (Win32)
--- a/lphobos/std/format.d	Mon Oct 06 21:27:29 2008 +0200
+++ b/lphobos/std/format.d	Mon Oct 06 21:40:33 2008 +0200
@@ -1,1570 +1,1570 @@
-
-// Written in the D programming language.
-
-/**
- * This module implements the workhorse functionality for string and I/O formatting.
- * It's comparable to C99's vsprintf().
- *
- * Macros:
- *	WIKI = Phobos/StdFormat
- */
-
-/*
- *  Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
- *  Written by Walter Bright
- *  Modified for LLVMDC by Tomas Lindquist Olsen
- *
- *  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.format;
-
-//debug=format;		// uncomment to turn on debugging printf's
-
-import std.stdarg;	// caller will need va_list
-
-private import std.utf;
-private import std.c.stdlib;
-private import std.c.string;
-private import std.string;
-
-version (Windows)
-{
-    version (DigitalMars)
-    {
-	version = DigitalMarsC;
-    }
-}
-
-version (DigitalMarsC)
-{
-    // This is DMC's internal floating point formatting function
-    extern (C)
-    {
-	extern char* function(int c, int flags, int precision, real* pdval,
-	    char* buf, int* psl, int width) __pfloatfmt;
-    }
-}
-else
-{
-    // Use C99 snprintf
-    extern (C) int snprintf(char* s, size_t n, char* format, ...);
-}
-
-/**********************************************************************
- * Signals a mismatch between a format and its corresponding argument.
- */
-class FormatError : Error
-{
-  private:
-
-    this()
-    {
-	super("std.format");
-    }
-
-    this(char[] msg)
-    {
-	super("std.format " ~ msg);
-    }
-}
-
-
-enum Mangle : char
-{
-    Tvoid     = 'v',
-    Tbool     = 'b',
-    Tbyte     = 'g',
-    Tubyte    = 'h',
-    Tshort    = 's',
-    Tushort   = 't',
-    Tint      = 'i',
-    Tuint     = 'k',
-    Tlong     = 'l',
-    Tulong    = 'm',
-    Tfloat    = 'f',
-    Tdouble   = 'd',
-    Treal     = 'e',
-
-    Tifloat   = 'o',
-    Tidouble  = 'p',
-    Tireal    = 'j',
-    Tcfloat   = 'q',
-    Tcdouble  = 'r',
-    Tcreal    = 'c',
-
-    Tchar     = 'a',
-    Twchar    = 'u',
-    Tdchar    = 'w',
-
-    Tarray    = 'A',
-    Tsarray   = 'G',
-    Taarray   = 'H',
-    Tpointer  = 'P',
-    Tfunction = 'F',
-    Tident    = 'I',
-    Tclass    = 'C',
-    Tstruct   = 'S',
-    Tenum     = 'E',
-    Ttypedef  = 'T',
-    Tdelegate = 'D',
-
-    Tconst    = 'x',
-    Tinvariant = 'y',
-}
-
-// return the TypeInfo for a primitive type and null otherwise.
-// This is required since for arrays of ints we only have the mangled
-// char to work from. If arrays always subclassed TypeInfo_Array this
-// routine could go away.
-private TypeInfo primitiveTypeInfo(Mangle m) 
-{
-  TypeInfo ti;
-
-  switch (m)
-    {
-    case Mangle.Tvoid:
-      ti = typeid(void);break;
-    case Mangle.Tbool:
-      ti = typeid(bool);break;
-    case Mangle.Tbyte:
-      ti = typeid(byte);break;
-    case Mangle.Tubyte:
-      ti = typeid(ubyte);break;
-    case Mangle.Tshort:
-      ti = typeid(short);break;
-    case Mangle.Tushort:
-      ti = typeid(ushort);break;
-    case Mangle.Tint:
-      ti = typeid(int);break;
-    case Mangle.Tuint:
-      ti = typeid(uint);break;
-    case Mangle.Tlong:
-      ti = typeid(long);break;
-    case Mangle.Tulong:
-      ti = typeid(ulong);break;
-    case Mangle.Tfloat:
-      ti = typeid(float);break;
-    case Mangle.Tdouble:
-      ti = typeid(double);break;
-    case Mangle.Treal:
-      ti = typeid(real);break;
-    case Mangle.Tifloat:
-      ti = typeid(ifloat);break;
-    case Mangle.Tidouble:
-      ti = typeid(idouble);break;
-    case Mangle.Tireal:
-      ti = typeid(ireal);break;
-    case Mangle.Tcfloat:
-      ti = typeid(cfloat);break;
-    case Mangle.Tcdouble:
-      ti = typeid(cdouble);break;
-    case Mangle.Tcreal:
-      ti = typeid(creal);break;
-    case Mangle.Tchar:
-      ti = typeid(char);break;
-    case Mangle.Twchar:
-      ti = typeid(wchar);break;
-    case Mangle.Tdchar:
-      ti = typeid(dchar);
-    default:
-      ti = null;
-    }
-  return ti;
-}
-
-/************************************
- * Interprets variadic argument list pointed to by argptr whose types are given
- * by arguments[], formats them according to embedded format strings in the
- * variadic argument list, and sends the resulting characters to putc.
- *
- * The variadic arguments are consumed in order.
- * Each is formatted into a sequence of chars, using the default format
- * specification for its type, and the
- * characters are sequentially passed to putc.
- * If a char[], wchar[], or dchar[]
- * argument is encountered, it is interpreted as a format string. As many
- * arguments as specified in the format string are consumed and formatted
- * according to the format specifications in that string and passed to putc. If
- * there are too few remaining arguments, a FormatError is thrown. If there are
- * more remaining arguments than needed by the format specification, the default
- * processing of arguments resumes until they are all consumed.
- *
- * Params:
- *	putc =	Output is sent do this delegate, character by character.
- *	arguments = Array of TypeInfo's, one for each argument to be formatted.
- *	argptr = Points to variadic argument list.
- *
- * Throws:
- *	Mismatched arguments and formats result in a FormatError being thrown.
- *
- * Format_String:
- *	<a name="format-string">$(I Format strings)</a>
- *	consist of characters interspersed with
- *	$(I format specifications). Characters are simply copied
- *	to the output (such as putc) after any necessary conversion
- *	to the corresponding UTF-8 sequence.
- *
- *	A $(I format specification) starts with a '%' character,
- *	and has the following grammar:
-
-<pre>
-$(I FormatSpecification):
-    $(B '%%')
-    $(B '%') $(I Flags) $(I Width) $(I Precision) $(I FormatChar)
-
-$(I Flags):
-    $(I empty)
-    $(B '-') $(I Flags)
-    $(B '+') $(I Flags)
-    $(B '#') $(I Flags)
-    $(B '0') $(I Flags)
-    $(B ' ') $(I Flags)
-
-$(I Width):
-    $(I empty)
-    $(I Integer)
-    $(B '*')
-
-$(I Precision):
-    $(I empty)
-    $(B '.')
-    $(B '.') $(I Integer)
-    $(B '.*')
-
-$(I Integer):
-    $(I Digit)
-    $(I Digit) $(I Integer)
-
-$(I Digit):
-    $(B '0')
-    $(B '1')
-    $(B '2')
-    $(B '3')
-    $(B '4')
-    $(B '5')
-    $(B '6')
-    $(B '7')
-    $(B '8')
-    $(B '9')
-
-$(I FormatChar):
-    $(B 's')
-    $(B 'b')
-    $(B 'd')
-    $(B 'o')
-    $(B 'x')
-    $(B 'X')
-    $(B 'e')
-    $(B 'E')
-    $(B 'f')
-    $(B 'F')
-    $(B 'g')
-    $(B 'G')
-    $(B 'a')
-    $(B 'A')
-</pre>
-    <dl>
-    <dt>$(I Flags)
-    <dl>
-	<dt>$(B '-')
-	<dd>
-	Left justify the result in the field.
-	It overrides any $(B 0) flag.
-
-	<dt>$(B '+')
-	<dd>Prefix positive numbers in a signed conversion with a $(B +).
-	It overrides any $(I space) flag.
-
-	<dt>$(B '#')
-	<dd>Use alternative formatting:
-	<dl>
-	    <dt>For $(B 'o'):
-	    <dd> Add to precision as necessary so that the first digit
-	    of the octal formatting is a '0', even if both the argument
-	    and the $(I Precision) are zero.
-	    <dt> For $(B 'x') ($(B 'X')):
-	    <dd> If non-zero, prefix result with $(B 0x) ($(B 0X)).
-	    <dt> For floating point formatting:
-	    <dd> Always insert the decimal point.
-	    <dt> For $(B 'g') ($(B 'G')):
-	    <dd> Do not elide trailing zeros.
-	</dl>
-
-	<dt>$(B '0')
-	<dd> For integer and floating point formatting when not nan or
-	infinity, use leading zeros
-	to pad rather than spaces.
-	Ignore if there's a $(I Precision).
-
-	<dt>$(B ' ')
-	<dd>Prefix positive numbers in a signed conversion with a space.
-    </dl>
-
-    <dt>$(I Width)
-    <dd>
-    Specifies the minimum field width.
-    If the width is a $(B *), the next argument, which must be
-    of type $(B int), is taken as the width.
-    If the width is negative, it is as if the $(B -) was given
-    as a $(I Flags) character.
-
-    <dt>$(I Precision)
-    <dd> Gives the precision for numeric conversions.
-    If the precision is a $(B *), the next argument, which must be
-    of type $(B int), is taken as the precision. If it is negative,
-    it is as if there was no $(I Precision).
-
-    <dt>$(I FormatChar)
-    <dd>
-    <dl>
-	<dt>$(B 's')
-	<dd>The corresponding argument is formatted in a manner consistent
-	with its type:
-	<dl>
-	    <dt>$(B bool)
-	    <dd>The result is <tt>'true'</tt> or <tt>'false'</tt>.
-	    <dt>integral types
-	    <dd>The $(B %d) format is used.
-	    <dt>floating point types
-	    <dd>The $(B %g) format is used.
-	    <dt>string types
-	    <dd>The result is the string converted to UTF-8.
-	    A $(I Precision) specifies the maximum number of characters
-	    to use in the result.
-	    <dt>classes derived from $(B Object)
-	    <dd>The result is the string returned from the class instance's
-	    $(B .toString()) method.
-	    A $(I Precision) specifies the maximum number of characters
-	    to use in the result.
-	    <dt>non-string static and dynamic arrays
-	    <dd>The result is [s<sub>0</sub>, s<sub>1</sub>, ...]
-	    where s<sub>k</sub> is the kth element 
-	    formatted with the default format.
-	</dl>
-
-	<dt>$(B 'b','d','o','x','X')
-	<dd> The corresponding argument must be an integral type
-	and is formatted as an integer. If the argument is a signed type
-	and the $(I FormatChar) is $(B d) it is converted to
-	a signed string of characters, otherwise it is treated as
-	unsigned. An argument of type $(B bool) is formatted as '1'
-	or '0'. The base used is binary for $(B b), octal for $(B o),
-	decimal
-	for $(B d), and hexadecimal for $(B x) or $(B X).
-	$(B x) formats using lower case letters, $(B X) uppercase.
-	If there are fewer resulting digits than the $(I Precision),
-	leading zeros are used as necessary.
-	If the $(I Precision) is 0 and the number is 0, no digits
-	result.
-
-	<dt>$(B 'e','E')
-	<dd> A floating point number is formatted as one digit before
-	the decimal point, $(I Precision) digits after, the $(I FormatChar),
-	&plusmn;, followed by at least a two digit exponent: $(I d.dddddd)e$(I &plusmn;dd).
-	If there is no $(I Precision), six
-	digits are generated after the decimal point.
-	If the $(I Precision) is 0, no decimal point is generated.
-
-	<dt>$(B 'f','F')
-	<dd> A floating point number is formatted in decimal notation.
-	The $(I Precision) specifies the number of digits generated
-	after the decimal point. It defaults to six. At least one digit
-	is generated before the decimal point. If the $(I Precision)
-	is zero, no decimal point is generated.
-
-	<dt>$(B 'g','G')
-	<dd> A floating point number is formatted in either $(B e) or
-	$(B f) format for $(B g); $(B E) or $(B F) format for
-	$(B G).
-	The $(B f) format is used if the exponent for an $(B e) format
-	is greater than -5 and less than the $(I Precision).
-	The $(I Precision) specifies the number of significant
-	digits, and defaults to six.
-	Trailing zeros are elided after the decimal point, if the fractional
-	part is zero then no decimal point is generated.
-
-	<dt>$(B 'a','A')
-	<dd> A floating point number is formatted in hexadecimal
-	exponential notation 0x$(I h.hhhhhh)p$(I &plusmn;d).
-	There is one hexadecimal digit before the decimal point, and as
-	many after as specified by the $(I Precision).
-	If the $(I Precision) is zero, no decimal point is generated.
-	If there is no $(I Precision), as many hexadecimal digits as
-	necessary to exactly represent the mantissa are generated.
-	The exponent is written in as few digits as possible,
-	but at least one, is in decimal, and represents a power of 2 as in
-	$(I h.hhhhhh)*2<sup>$(I &plusmn;d)</sup>.
-	The exponent for zero is zero.
-	The hexadecimal digits, x and p are in upper case if the
-	$(I FormatChar) is upper case.
-    </dl>
-
-    Floating point NaN's are formatted as $(B nan) if the
-    $(I FormatChar) is lower case, or $(B NAN) if upper.
-    Floating point infinities are formatted as $(B inf) or
-    $(B infinity) if the
-    $(I FormatChar) is lower case, or $(B INF) or $(B INFINITY) if upper.
-    </dl>
-
-Example:
-
--------------------------
-import std.c.stdio;
-import std.format;
-
-void formattedPrint(...)
-{
-    void putc(char c)
-    {
-	fputc(c, stdout);
-    }
-
-    std.format.doFormat(&putc, _arguments, _argptr);
-}
-
-...
-
-int x = 27;
-// prints 'The answer is 27:6'
-formattedPrint("The answer is %s:", x, 6);
-------------------------
- */
-
-void doFormat(void delegate(dchar) putc, TypeInfo[] arguments, void* argptr)
-{   //printf("doFormat(...)\n");
-    int j;
-    TypeInfo ti;
-    Mangle m;
-    uint flags;
-    int field_width;
-    int precision;
-
-    enum : uint
-    {
-	FLdash = 1,
-	FLplus = 2,
-	FLspace = 4,
-	FLhash = 8,
-	FLlngdbl = 0x20,
-	FL0pad = 0x40,
-	FLprecision = 0x80,
-    }
-
-    static TypeInfo skipCI(TypeInfo valti)
-    {
-      while (1)
-      {
-	if (valti.classinfo.name.length == 18 &&
-	    valti.classinfo.name[9..18] == "Invariant")
-	    valti =	(cast(TypeInfo_Invariant)valti).next;
-	else if (valti.classinfo.name.length == 14 &&
-	    valti.classinfo.name[9..14] == "Const")
-	    valti =	(cast(TypeInfo_Const)valti).next;
-	else
-	    break;
-      }
-      return valti;
-    }
-
-    void formatArg(char fc)
-    {
-	bool vbit;
-	ulong vnumber;
-	char vchar;
-	dchar vdchar;
-	Object vobject;
-	real vreal;
-	creal vcreal;
-	Mangle m2;
-	int signed = 0;
-	uint base = 10;
-	int uc;
-	char[ulong.sizeof * 8] tmpbuf;	// long enough to print long in binary
-	char* prefix = "";
-	string s;
-
-	void putstr(char[] s)
-	{
-	    //printf("flags = 0x%x\n", flags);
-	    int prepad = 0;
-	    int postpad = 0;
-	    int padding = field_width - (strlen(prefix) + s.length);
-	    if (padding > 0)
-	    {
-		if (flags & FLdash)
-		    postpad = padding;
-		else
-		    prepad = padding;
-	    }
-
-	    if (flags & FL0pad)
-	    {
-		while (*prefix)
-		    putc(*prefix++);
-		while (prepad--)
-		    putc('0');
-	    }
-	    else
-	    {
-		while (prepad--)
-		    putc(' ');
-		while (*prefix)
-		    putc(*prefix++);
-	    }
-
-	    foreach (dchar c; s)
-		putc(c);
-
-	    while (postpad--)
-		putc(' ');
-	}
-
-	void putreal(real v)
-	{
-	    //printf("putreal %Lg\n", vreal); // no 80 bit float
-        //printf("putreal %g\n", vreal);
-
-	    switch (fc)
-	    {
-		case 's':
-		    fc = 'g';
-		    break;
-
-		case 'f', 'F', 'e', 'E', 'g', 'G', 'a', 'A':
-		    break;
-
-		default:
-		    //printf("fc = '%c'\n", fc);
-		Lerror:
-		    throw new FormatError("floating");
-	    }
-	    version (DigitalMarsC)
-	    {
-		int sl;
-		char[] fbuf = tmpbuf;
-		if (!(flags & FLprecision))
-		    precision = 6;
-		while (1)
-		{
-		    sl = fbuf.length;
-		    prefix = (*__pfloatfmt)(fc, flags | FLlngdbl,
-			    precision, &v, cast(char*)fbuf, &sl, field_width);
-		    if (sl != -1)
-			break;
-		    sl = fbuf.length * 2;
-		    fbuf = (cast(char*)alloca(sl * char.sizeof))[0 .. sl];
-		}
-		putstr(fbuf[0 .. sl]);
-	    }
-	    else
-	    {
-		int sl;
-		char[] fbuf = tmpbuf;
-		char[12] format;
-		format[0] = '%';
-		int i = 1;
-		if (flags & FLdash)
-		    format[i++] = '-';
-		if (flags & FLplus)
-		    format[i++] = '+';
-		if (flags & FLspace)
-		    format[i++] = ' ';
-		if (flags & FLhash)
-		    format[i++] = '#';
-		if (flags & FL0pad)
-		    format[i++] = '0';
-		format[i + 0] = '*';
-		format[i + 1] = '.';
-		format[i + 2] = '*';
-        format[i + 3] = fc;
-        format[i + 4] = 0;
-		//format[i + 3] = 'L'; // no 80 bit yet
-		//format[i + 4] = fc;
-		//format[i + 5] = 0;
-		if (!(flags & FLprecision))
-		    precision = -1;
-		while (1)
-		{   int n;
-
-		    sl = fbuf.length;
-		    n = snprintf(fbuf.ptr, sl, format.ptr, field_width, precision, v);
-		    //printf("format = '%s', n = %d\n", cast(char*)format, n);
-		    if (n >= 0 && n < sl)
-		    {	sl = n;
-			break;
-		    }
-		    if (n < 0)
-			sl = sl * 2;
-		    else
-			sl = n + 1;
-		    fbuf = (cast(char*)alloca(sl * char.sizeof))[0 .. sl];
-		}
-		putstr(fbuf[0 .. sl]);
-	    }
-	    return;
-	}
-
-	static Mangle getMan(TypeInfo ti)
-	{
-	  auto m = cast(Mangle)ti.classinfo.name[9];
-	  if (ti.classinfo.name.length == 20 &&
-	      ti.classinfo.name[9..20] == "StaticArray")
-		m = cast(Mangle)'G';
-	  return m;
-	}
-
-	void putArray(void* p, size_t len, TypeInfo valti)
-	{
-	  //printf("\nputArray(len = %u), tsize = %u\n", len, valti.tsize());
-	  putc('[');
-	  valti = skipCI(valti);
-	  size_t tsize = valti.tsize();
-	  auto argptrSave = argptr;
-	  auto tiSave = ti;
-	  auto mSave = m;
-	  ti = valti;
-      auto className = valti.classinfo.name;
-	  printf("\n%.*s\n", className.length, className.ptr);
-	  m = getMan(valti);
-	  while (len--)
-	  {
-	    //doFormat(putc, (&valti)[0 .. 1], p);
-	    argptr = p;
-	    formatArg('s');
-
-	    p += tsize;
-	    if (len > 0) putc(',');
-	  }
-	  m = mSave;
-	  ti = tiSave;
-	  argptr = argptrSave;
-	  putc(']');
-	}
-
-	void putAArray(ubyte[long] vaa, TypeInfo valti, TypeInfo keyti)
-	{
-	  putc('[');
-	  bool comma=false;
-	  auto argptrSave = argptr;
-	  auto tiSave = ti;
-	  auto mSave = m;
-	  valti = skipCI(valti);
-	  keyti = skipCI(keyti);
-	  foreach(inout fakevalue; vaa)
-	  {
-	    if (comma) putc(',');
-	    comma = true;
-	    // the key comes before the value
-	    ubyte* key = &fakevalue - long.sizeof;
-
-	    //doFormat(putc, (&keyti)[0..1], key);
-	    argptr = key;
-	    ti = keyti;
-	    m = getMan(keyti);
-	    formatArg('s');
-
-	    putc(':');
-	    auto keysize = keyti.tsize;
-	    keysize = (keysize + 3) & ~3;
-	    ubyte* value = key + keysize;
-	    //doFormat(putc, (&valti)[0..1], value);
-	    argptr = value;
-	    ti = valti;
-	    m = getMan(valti);
-	    formatArg('s');
-	  }
-	  m = mSave;
-	  ti = tiSave;
-	  argptr = argptrSave;
-	  putc(']');
-	}
-
-	//printf("formatArg(fc = '%c', m = '%c')\n", fc, m);
-	switch (m)
-	{
-	    case Mangle.Tbool:
-		vbit = va_arg!(bool)(argptr);
-		if (fc != 's')
-		{   vnumber = vbit;
-		    goto Lnumber;
-		}
-		putstr(vbit ? "true" : "false");
-		return;
-
-
-	    case Mangle.Tchar:
-		vchar = va_arg!(char)(argptr);
-		if (fc != 's')
-		{   vnumber = vchar;
-		    goto Lnumber;
-		}
-	    L2:
-		putstr((&vchar)[0 .. 1]);
-		return;
-
-	    case Mangle.Twchar:
-		vdchar = va_arg!(wchar)(argptr);
-		goto L1;
-
-	    case Mangle.Tdchar:
-		vdchar = va_arg!(dchar)(argptr);
-	    L1:
-		if (fc != 's')
-		{   vnumber = vdchar;
-		    goto Lnumber;
-		}
-		if (vdchar <= 0x7F)
-		{   vchar = cast(char)vdchar;
-		    goto L2;
-		}
-		else
-		{   if (!isValidDchar(vdchar))
-			throw new UtfException("invalid dchar in format", 0);
-		    char[4] vbuf;
-		    putstr(toUTF8(vbuf, vdchar));
-		}
-		return;
-
-
-	    case Mangle.Tbyte:
-		signed = 1;
-		vnumber = va_arg!(byte)(argptr);
-		goto Lnumber;
-
-	    case Mangle.Tubyte:
-		vnumber = va_arg!(ubyte)(argptr);
-		goto Lnumber;
-
-	    case Mangle.Tshort:
-		signed = 1;
-		vnumber = va_arg!(short)(argptr);
-		goto Lnumber;
-
-	    case Mangle.Tushort:
-		vnumber = va_arg!(ushort)(argptr);
-		goto Lnumber;
-
-	    case Mangle.Tint:
-		signed = 1;
-		vnumber = va_arg!(int)(argptr);
-		goto Lnumber;
-
-	    case Mangle.Tuint:
-	    Luint:
-		vnumber = va_arg!(uint)(argptr);
-		goto Lnumber;
-
-	    case Mangle.Tlong:
-		signed = 1;
-		vnumber = cast(ulong)va_arg!(long)(argptr);
-		goto Lnumber;
-
-	    case Mangle.Tulong:
-	    Lulong:
-		vnumber = va_arg!(ulong)(argptr);
-		goto Lnumber;
-
-	    case Mangle.Tclass:
-		vobject = va_arg!(Object)(argptr);
-		if (vobject is null)
-		    s = "null";
-		else
-		    s = vobject.toString();
-		goto Lputstr;
-
-	    case Mangle.Tpointer:
-		vnumber = cast(ulong)va_arg!(void*)(argptr);
-		uc = 1;
-		flags |= FL0pad;
-		if (!(flags & FLprecision))
-		{   flags |= FLprecision;
-		    precision = (void*).sizeof;
-		}
-		base = 16;
-		goto Lnumber;
-
-
-	    case Mangle.Tfloat:
-	    case Mangle.Tifloat:
-		if (fc == 'x' || fc == 'X')
-		    goto Luint;
-		vreal = va_arg!(float)(argptr);
-		goto Lreal;
-
-	    case Mangle.Tdouble:
-	    case Mangle.Tidouble:
-		if (fc == 'x' || fc == 'X')
-		    goto Lulong;
-		vreal = va_arg!(double)(argptr);
-		goto Lreal;
-
-	    case Mangle.Treal:
-	    case Mangle.Tireal:
-		vreal = va_arg!(real)(argptr);
-		goto Lreal;
-
-
-	    case Mangle.Tcfloat:
-		vcreal = va_arg!(cfloat)(argptr);
-		goto Lcomplex;
-
-	    case Mangle.Tcdouble:
-		vcreal = va_arg!(cdouble)(argptr);
-		goto Lcomplex;
-
-	    case Mangle.Tcreal:
-		vcreal = va_arg!(creal)(argptr);
-		goto Lcomplex;
-
-	    case Mangle.Tsarray:
-        //printf("static array\n");
-		putArray(argptr, (cast(TypeInfo_StaticArray)ti).len, (cast(TypeInfo_StaticArray)ti).next);
-		return;
-
-	    case Mangle.Tarray:
-        //printf("dynamic array\n");
-		int mi = 10;
-	        if (ti.classinfo.name.length == 14 &&
-		    ti.classinfo.name[9..14] == "Array") 
-		{ // array of non-primitive types
-		  TypeInfo tn = (cast(TypeInfo_Array)ti).next;
-		  tn = skipCI(tn);
-		  switch (cast(Mangle)tn.classinfo.name[9])
-		  {
-		    case Mangle.Tchar:  goto LarrayChar;
-		    case Mangle.Twchar: goto LarrayWchar;
-		    case Mangle.Tdchar: goto LarrayDchar;
-		    default:
-			break;
-		  }
-		  void[] va = va_arg!(void[])(argptr);
-		  putArray(va.ptr, va.length, tn);
-		  return;
-		}
-		if (ti.classinfo.name.length == 25 &&
-		    ti.classinfo.name[9..25] == "AssociativeArray") 
-		{ // associative array
-		  ubyte[long] vaa = va_arg!(ubyte[long])(argptr);
-		  putAArray(vaa,
-			(cast(TypeInfo_AssociativeArray)ti).next,
-			(cast(TypeInfo_AssociativeArray)ti).key);
-		  return;
-		}
-
-        //printf("primitive type\n");
-		while (1)
-		{
-		    m2 = cast(Mangle)ti.classinfo.name[mi];
-		    switch (m2)
-		    {
-			case Mangle.Tchar:
-			LarrayChar:
-			    s = va_arg!(char[])(argptr);
-			    goto Lputstr;
-
-			case Mangle.Twchar:
-			LarrayWchar:
-			    wchar[] sw = va_arg!(wchar[])(argptr);
-			    s = toUTF8(sw);
-			    goto Lputstr;
-
-			case Mangle.Tdchar:
-			LarrayDchar:
-			    dchar[] sd = va_arg!(dchar[])(argptr);
-			    s = toUTF8(sd);
-			Lputstr:
-			    if (fc != 's')
-				throw new FormatError("string");
-			    if (flags & FLprecision && precision < s.length)
-				s = s[0 .. precision];
-			    putstr(s);
-			    break;
-
-			case Mangle.Tconst:
-			case Mangle.Tinvariant:
-			    mi++;
-			    continue;
-
-			default:
-                //printf("primitive type default handling\n");
-			    TypeInfo ti2 = primitiveTypeInfo(m2);
-			    if (!ti2)
-			      goto Lerror;
-			    void[] va = va_arg!(void[])(argptr);
-			    putArray(va.ptr, va.length, ti2);
-		    }
-		    return;
-		}
-
-	    case Mangle.Ttypedef:
-		ti = (cast(TypeInfo_Typedef)ti).base;
-		m = cast(Mangle)ti.classinfo.name[9];
-		formatArg(fc);
-		return;
-
-	    case Mangle.Tenum:
-		ti = (cast(TypeInfo_Enum)ti).base;
-		m = cast(Mangle)ti.classinfo.name[9];
-		formatArg(fc);
-		return;
-
-	    case Mangle.Tstruct:
-	    {	TypeInfo_Struct tis = cast(TypeInfo_Struct)ti;
-		if (tis.xtoString is null)
-		    throw new FormatError("Can't convert " ~ tis.toString() ~ " to string: \"string toString()\" not defined");
-		s = tis.xtoString(argptr);
-		argptr += (tis.tsize() + 3) & ~3;
-		goto Lputstr;
-	    }
-
-	    default:
-		goto Lerror;
-	}
-
-    Lnumber:
-	switch (fc)
-	{
-	    case 's':
-	    case 'd':
-		if (signed)
-		{   if (cast(long)vnumber < 0)
-		    {	prefix = "-";
-			vnumber = -vnumber;
-		    }
-		    else if (flags & FLplus)
-			prefix = "+";
-		    else if (flags & FLspace)
-			prefix = " ";
-		}
-		break;
-
-	    case 'b':
-		signed = 0;
-		base = 2;
-		break;
-
-	    case 'o':
-		signed = 0;
-		base = 8;
-		break;
-
-	    case 'X':
-		uc = 1;
-		if (flags & FLhash && vnumber)
-		    prefix = "0X";
-		signed = 0;
-		base = 16;
-		break;
-
-	    case 'x':
-		if (flags & FLhash && vnumber)
-		    prefix = "0x";
-		signed = 0;
-		base = 16;
-		break;
-
-	    default:
-		goto Lerror;
-	}
-
-	if (!signed)
-	{
-	    switch (m)
-	    {
-		case Mangle.Tbyte:
-		    vnumber &= 0xFF;
-		    break;
-
-		case Mangle.Tshort:
-		    vnumber &= 0xFFFF;
-		    break;
-
-		case Mangle.Tint:
-		    vnumber &= 0xFFFFFFFF;
-		    break;
-
-		default:
-		    break;
-	    }
-	}
-
-	if (flags & FLprecision && fc != 'p')
-	    flags &= ~FL0pad;
-
-	if (vnumber < base)
-	{
-	    if (vnumber == 0 && precision == 0 && flags & FLprecision &&
-		!(fc == 'o' && flags & FLhash))
-	    {
-		putstr(null);
-		return;
-	    }
-	    if (precision == 0 || !(flags & FLprecision))
-	    {	vchar = cast(char)('0' + vnumber);
-		if (vnumber < 10)
-		    vchar = cast(char)('0' + vnumber);
-		else
-		    vchar = cast(char)((uc ? 'A' - 10 : 'a' - 10) + vnumber);
-		goto L2;
-	    }
-	}
-
-	int n = tmpbuf.length;
-	char c;
-	int hexoffset = uc ? ('A' - ('9' + 1)) : ('a' - ('9' + 1));
-
-	while (vnumber)
-	{
-	    c = cast(char)((vnumber % base) + '0');
-	    if (c > '9')
-		c += hexoffset;
-	    vnumber /= base;
-	    tmpbuf[--n] = c;
-	}
-	if (tmpbuf.length - n < precision && precision < tmpbuf.length)
-	{
-	    int m = tmpbuf.length - precision;
-	    tmpbuf[m .. n] = '0';
-	    n = m;
-	}
-	else if (flags & FLhash && fc == 'o')
-	    prefix = "0";
-	putstr(tmpbuf[n .. tmpbuf.length]);
-	return;
-
-    Lreal:
-	putreal(vreal);
-	return;
-
-    Lcomplex:
-	putreal(vcreal.re);
-	putc('+');
-	putreal(vcreal.im);
-	putc('i');
-	return;
-
-    Lerror:
-	throw new FormatError("formatArg");
-    }
-
-
-    //printf("arguments length: %u\n", arguments.length);
-    for (j = 0; j < arguments.length; )
-    {	ti = arguments[j++];
-	//printf("test1: '%.*s' %d\n", ti.classinfo.name.length, ti.classinfo.name.ptr, ti.classinfo.name.length);
-	//ti.print();
-
-	flags = 0;
-	precision = 0;
-	field_width = 0;
-
-	ti = skipCI(ti);
-	int mi = 9;
-	do
-	{
-	    if (ti.classinfo.name.length <= mi)
-		goto Lerror;
-	    m = cast(Mangle)ti.classinfo.name[mi++];
-	} while (m == Mangle.Tconst || m == Mangle.Tinvariant);
-
-	if (m == Mangle.Tarray)
-	{
-	    if (ti.classinfo.name.length == 14 &&
-		ti.classinfo.name[9..14] == "Array") 
-	    {
-	      TypeInfo tn = (cast(TypeInfo_Array)ti).next;
-	      tn = skipCI(tn);
-	      switch (cast(Mangle)tn.classinfo.name[9])
-	      {
-		case Mangle.Tchar:
-		case Mangle.Twchar:
-		case Mangle.Tdchar:
-		    ti = tn;
-		    mi = 9;
-		    break;
-		default:
-		    break;
-	      }
-	    }
-	L1:
-	    Mangle m2 = cast(Mangle)ti.classinfo.name[mi];
-	    string  fmt;			// format string
-	    wstring wfmt;
-	    dstring dfmt;
-
-	    /* For performance reasons, this code takes advantage of the
-	     * fact that most format strings will be ASCII, and that the
-	     * format specifiers are always ASCII. This means we only need
-	     * to deal with UTF in a couple of isolated spots.
-	     */
-
-	    switch (m2)
-	    {
-		case Mangle.Tchar:
-		    fmt = va_arg!(char[])(argptr);
-		    break;
-
-		case Mangle.Twchar:
-		    wfmt = va_arg!(wchar[])(argptr);
-		    fmt = toUTF8(wfmt);
-		    break;
-
-		case Mangle.Tdchar:
-		    dfmt = va_arg!(dchar[])(argptr);
-		    fmt = toUTF8(dfmt);
-		    break;
-
-		case Mangle.Tconst:
-		case Mangle.Tinvariant:
-		    mi++;
-		    goto L1;
-
-		default:
-		    formatArg('s');
-		    continue;
-	    }
-
-	    for (size_t i = 0; i < fmt.length; )
-	    {	dchar c = fmt[i++];
-
-		dchar getFmtChar()
-		{   // Valid format specifier characters will never be UTF
-		    if (i == fmt.length)
-			throw new FormatError("invalid specifier");
-		    return fmt[i++];
-		}
-
-		int getFmtInt()
-		{   int n;
-
-		    while (1)
-		    {
-			n = n * 10 + (c - '0');
-			if (n < 0)	// overflow
-			    throw new FormatError("int overflow");
-			c = getFmtChar();
-			if (c < '0' || c > '9')
-			    break;
-		    }
-		    return n;
-		}
-
-		int getFmtStar()
-		{   Mangle m;
-		    TypeInfo ti;
-
-		    if (j == arguments.length)
-			throw new FormatError("too few arguments");
-		    ti = arguments[j++];
-		    m = cast(Mangle)ti.classinfo.name[9];
-		    if (m != Mangle.Tint)
-			throw new FormatError("int argument expected");
-		    return va_arg!(int)(argptr);
-		}
-
-		if (c != '%')
-		{
-		    if (c > 0x7F)	// if UTF sequence
-		    {
-			i--;		// back up and decode UTF sequence
-			c = std.utf.decode(fmt, i);
-		    }
-		Lputc:
-		    putc(c);
-		    continue;
-		}
-
-		// Get flags {-+ #}
-		flags = 0;
-		while (1)
-		{
-		    c = getFmtChar();
-		    switch (c)
-		    {
-			case '-':	flags |= FLdash;	continue;
-			case '+':	flags |= FLplus;	continue;
-			case ' ':	flags |= FLspace;	continue;
-			case '#':	flags |= FLhash;	continue;
-			case '0':	flags |= FL0pad;	continue;
-
-			case '%':	if (flags == 0)
-					    goto Lputc;
-			default:	break;
-		    }
-		    break;
-		}
-
-		// Get field width
-		field_width = 0;
-		if (c == '*')
-		{
-		    field_width = getFmtStar();
-		    if (field_width < 0)
-		    {   flags |= FLdash;
-			field_width = -field_width;
-		    }
-
-		    c = getFmtChar();
-		}
-		else if (c >= '0' && c <= '9')
-		    field_width = getFmtInt();
-
-		if (flags & FLplus)
-		    flags &= ~FLspace;
-		if (flags & FLdash)
-		    flags &= ~FL0pad;
-
-		// Get precision
-		precision = 0;
-		if (c == '.')
-		{   flags |= FLprecision;
-		    //flags &= ~FL0pad;
-
-		    c = getFmtChar();
-		    if (c == '*')
-		    {
-			precision = getFmtStar();
-			if (precision < 0)
-			{   precision = 0;
-			    flags &= ~FLprecision;
-			}
-
-			c = getFmtChar();
-		    }
-		    else if (c >= '0' && c <= '9')
-			precision = getFmtInt();
-		}
-
-		if (j == arguments.length)
-		    goto Lerror;
-		ti = arguments[j++];
-		ti = skipCI(ti);
-		mi = 9;
-		do
-		{
-		    m = cast(Mangle)ti.classinfo.name[mi++];
-		} while (m == Mangle.Tconst || m == Mangle.Tinvariant);
-
-		if (c > 0x7F)		// if UTF sequence
-		    goto Lerror;	// format specifiers can't be UTF
-		formatArg(cast(char)c);
-	    }
-	}
-	else
-	{
-	    formatArg('s');
-	}
-    }
-    return;
-
-Lerror:
-    throw new FormatError();
-}
-
-/* ======================== Unit Tests ====================================== */
-
-unittest
-{
-    int i;
-    string s;
-
-    debug(format) printf("std.format.format.unittest\n");
- 
-    s = std.string.format("hello world! %s %s ", true, 57, 1_000_000_000, 'x', " foo");
-    assert(s == "hello world! true 57 1000000000x foo");
-
-    s = std.string.format(1.67, " %A ", -1.28, float.nan);
-    /* The host C library is used to format floats.
-     * C99 doesn't specify what the hex digit before the decimal point
-     * is for %A.
-     */
-    version (linux)
-	assert(s == "1.67 -0XA.3D70A3D70A3D8P-3 nan");
-    else
-	assert(s == "1.67 -0X1.47AE147AE147BP+0 nan");
-
-    s = std.string.format("%x %X", 0x1234AF, 0xAFAFAFAF);
-    assert(s == "1234af AFAFAFAF");
-
-    s = std.string.format("%b %o", 0x1234AF, 0xAFAFAFAF);
-    assert(s == "100100011010010101111 25753727657");
-
-    s = std.string.format("%d %s", 0x1234AF, 0xAFAFAFAF);
-    assert(s == "1193135 2947526575");
-
-    s = std.string.format("%s", 1.2 + 3.4i);
-    assert(s == "1.2+3.4i");
-
-    s = std.string.format("%x %X", 1.32, 6.78f);
-    assert(s == "3ff51eb851eb851f 40D8F5C3");
-
-    s = std.string.format("%#06.*f",2,12.345);
-    assert(s == "012.35");
-
-    s = std.string.format("%#0*.*f",6,2,12.345);
-    assert(s == "012.35");
-
-    s = std.string.format("%7.4g:", 12.678);
-    assert(s == "  12.68:");
-
-    s = std.string.format("%7.4g:", 12.678L);
-    assert(s == "  12.68:");
-
-    s = std.string.format("%04f|%05d|%#05x|%#5x",-4.,-10,1,1);
-    assert(s == "-4.000000|-0010|0x001|  0x1");
-
-    i = -10;
-    s = std.string.format("%d|%3d|%03d|%1d|%01.4f",i,i,i,i,cast(double) i);
-    assert(s == "-10|-10|-10|-10|-10.0000");
-
-    i = -5;
-    s = std.string.format("%d|%3d|%03d|%1d|%01.4f",i,i,i,i,cast(double) i);
-    assert(s == "-5| -5|-05|-5|-5.0000");
-
-    i = 0;
-    s = std.string.format("%d|%3d|%03d|%1d|%01.4f",i,i,i,i,cast(double) i);
-    assert(s == "0|  0|000|0|0.0000");
-
-    i = 5;
-    s = std.string.format("%d|%3d|%03d|%1d|%01.4f",i,i,i,i,cast(double) i);
-    assert(s == "5|  5|005|5|5.0000");
-
-    i = 10;
-    s = std.string.format("%d|%3d|%03d|%1d|%01.4f",i,i,i,i,cast(double) i);
-    assert(s == "10| 10|010|10|10.0000");
-
-    s = std.string.format("%.0d", 0);
-    assert(s == "");
-
-    s = std.string.format("%.g", .34);
-    assert(s == "0.3");
-
-    s = std.string.format("%.0g", .34);
-    assert(s == "0.3");
-
-    s = std.string.format("%.2g", .34);
-    assert(s == "0.34");
-
-    s = std.string.format("%0.0008f", 1e-08);
-    assert(s == "0.00000001");
-
-    s = std.string.format("%0.0008f", 1e-05);
-    assert(s == "0.00001000");
-
-    s = "helloworld";
-    string r;
-    r = std.string.format("%.2s", s[0..5]);
-    assert(r == "he");
-    r = std.string.format("%.20s", s[0..5]);
-    assert(r == "hello");
-    r = std.string.format("%8s", s[0..5]);
-    assert(r == "   hello");
-
-    byte[] arrbyte = new byte[4];
-    arrbyte[0] = 100;
-    arrbyte[1] = -99;
-    arrbyte[3] = 0;
-    r = std.string.format(arrbyte);
-    assert(r == "[100,-99,0,0]");
-
-    ubyte[] arrubyte = new ubyte[4];
-    arrubyte[0] = 100;
-    arrubyte[1] = 200;
-    arrubyte[3] = 0;
-    r = std.string.format(arrubyte);
-    assert(r == "[100,200,0,0]");
-
-    short[] arrshort = new short[4];
-    arrshort[0] = 100;
-    arrshort[1] = -999;
-    arrshort[3] = 0;
-    r = std.string.format(arrshort);
-    assert(r == "[100,-999,0,0]");
-    r = std.string.format("%s",arrshort);
-    assert(r == "[100,-999,0,0]");
-
-    ushort[] arrushort = new ushort[4];
-    arrushort[0] = 100;
-    arrushort[1] = 20_000;
-    arrushort[3] = 0;
-    r = std.string.format(arrushort);
-    assert(r == "[100,20000,0,0]");
-
-    int[] arrint = new int[4];
-    arrint[0] = 100;
-    arrint[1] = -999;
-    arrint[3] = 0;
-    r = std.string.format(arrint);
-    assert(r == "[100,-999,0,0]");
-    r = std.string.format("%s",arrint);
-    assert(r == "[100,-999,0,0]");
-
-    long[] arrlong = new long[4];
-    arrlong[0] = 100;
-    arrlong[1] = -999;
-    arrlong[3] = 0;
-    r = std.string.format(arrlong);
-    assert(r == "[100,-999,0,0]");
-    r = std.string.format("%s",arrlong);
-    assert(r == "[100,-999,0,0]");
-
-    ulong[] arrulong = new ulong[4];
-    arrulong[0] = 100;
-    arrulong[1] = 999;
-    arrulong[3] = 0;
-    r = std.string.format(arrulong);
-    assert(r == "[100,999,0,0]");
-
-    string[] arr2 = new string[4];
-    arr2[0] = "hello";
-    arr2[1] = "world";
-    arr2[3] = "foo";
-    r = std.string.format(arr2);
-    assert(r == "[hello,world,,foo]");
-
-    r = std.string.format("%.8d", 7);
-    assert(r == "00000007");
-    r = std.string.format("%.8x", 10);
-    assert(r == "0000000a");
-
-    r = std.string.format("%-3d", 7);
-    assert(r == "7  ");
-
-    r = std.string.format("%*d", -3, 7);
-    assert(r == "7  ");
-
-    r = std.string.format("%.*d", -3, 7);
-    assert(r == "7");
-
-    typedef int myint;
-    myint m = -7;
-    r = std.string.format(m);
-    assert(r == "-7");
-
-    r = std.string.format("abc"c);
-    assert(r == "abc");
-    r = std.string.format("def"w);
-    assert(r == "def");
-    r = std.string.format("ghi"d);
-    assert(r == "ghi");
-
-    void* p = cast(void*)0xDEADBEEF;
-    r = std.string.format(p);
-    assert(r == "DEADBEEF");
-
-    r = std.string.format("%#x", 0xabcd);
-    assert(r == "0xabcd");
-    r = std.string.format("%#X", 0xABCD);
-    assert(r == "0XABCD");
-
-    r = std.string.format("%#o", 012345);
-    assert(r == "012345");
-    r = std.string.format("%o", 9);
-    assert(r == "11");
-
-    r = std.string.format("%+d", 123);
-    assert(r == "+123");
-    r = std.string.format("%+d", -123);
-    assert(r == "-123");
-    r = std.string.format("% d", 123);
-    assert(r == " 123");
-    r = std.string.format("% d", -123);
-    assert(r == "-123");
-
-    r = std.string.format("%%");
-    assert(r == "%");
-
-    r = std.string.format("%d", true);
-    assert(r == "1");
-    r = std.string.format("%d", false);
-    assert(r == "0");
-
-    r = std.string.format("%d", 'a');
-    assert(r == "97");
-    wchar wc = 'a';
-    r = std.string.format("%d", wc);
-    assert(r == "97");
-    dchar dc = 'a';
-    r = std.string.format("%d", dc);
-    assert(r == "97");
-
-    byte b = byte.max;
-    r = std.string.format("%x", b);
-    assert(r == "7f");
-    r = std.string.format("%x", ++b);
-    assert(r == "80");
-    r = std.string.format("%x", ++b);
-    assert(r == "81");
-
-    short sh = short.max;
-    r = std.string.format("%x", sh);
-    assert(r == "7fff");
-    r = std.string.format("%x", ++sh);
-    assert(r == "8000");
-    r = std.string.format("%x", ++sh);
-    assert(r == "8001");
-
-    i = int.max;
-    r = std.string.format("%x", i);
-    assert(r == "7fffffff");
-    r = std.string.format("%x", ++i);
-    assert(r == "80000000");
-    r = std.string.format("%x", ++i);
-    assert(r == "80000001");
-
-    r = std.string.format("%x", 10);
-    assert(r == "a");
-    r = std.string.format("%X", 10);
-    assert(r == "A");
-    r = std.string.format("%x", 15);
-    assert(r == "f");
-    r = std.string.format("%X", 15);
-    assert(r == "F");
-
-    Object c = null;
-    r = std.string.format(c);
-    assert(r == "null");
-
-    enum TestEnum
-    {
-	    Value1, Value2
-    }
-    r = std.string.format("%s", TestEnum.Value2);
-    assert(r == "1");
-
-    char[5][int] aa = ([3:"hello", 4:"betty"]);
-    r = std.string.format("%s", aa.values);
-    assert(r == "[[h,e,l,l,o],[b,e,t,t,y]]");
-    r = std.string.format("%s", aa);
-    assert(r == "[3:[h,e,l,l,o],4:[b,e,t,t,y]]");
-
-    static const dchar[] ds = ['a','b'];
-    for (int j = 0; j < ds.length; ++j)
-    {
-	r = std.string.format(" %d", ds[j]);
-	if (j == 0)
-	    assert(r == " 97");
-	else
-	    assert(r == " 98");
-    }
-
-    r = std.string.format(">%14d<, ", 15, [1,2,3]);
-    assert(r == ">            15<, [1,2,3]");
-}
-
+
+// Written in the D programming language.
+
+/**
+ * This module implements the workhorse functionality for string and I/O formatting.
+ * It's comparable to C99's vsprintf().
+ *
+ * Macros:
+ *	WIKI = Phobos/StdFormat
+ */
+
+/*
+ *  Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *  Modified for LLVMDC by Tomas Lindquist Olsen
+ *
+ *  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.format;
+
+//debug=format;		// uncomment to turn on debugging printf's
+
+import std.stdarg;	// caller will need va_list
+
+private import std.utf;
+private import std.c.stdlib;
+private import std.c.string;
+private import std.string;
+
+version (Windows)
+{
+    version (DigitalMars)
+    {
+	version = DigitalMarsC;
+    }
+}
+
+version (DigitalMarsC)
+{
+    // This is DMC's internal floating point formatting function
+    extern (C)
+    {
+	extern char* function(int c, int flags, int precision, real* pdval,
+	    char* buf, int* psl, int width) __pfloatfmt;
+    }
+}
+else
+{
+    // Use C99 snprintf
+    extern (C) int snprintf(char* s, size_t n, char* format, ...);
+}
+
+/**********************************************************************
+ * Signals a mismatch between a format and its corresponding argument.
+ */
+class FormatError : Error
+{
+  private:
+
+    this()
+    {
+	super("std.format");
+    }
+
+    this(char[] msg)
+    {
+	super("std.format " ~ msg);
+    }
+}
+
+
+enum Mangle : char
+{
+    Tvoid     = 'v',
+    Tbool     = 'b',
+    Tbyte     = 'g',
+    Tubyte    = 'h',
+    Tshort    = 's',
+    Tushort   = 't',
+    Tint      = 'i',
+    Tuint     = 'k',
+    Tlong     = 'l',
+    Tulong    = 'm',
+    Tfloat    = 'f',
+    Tdouble   = 'd',
+    Treal     = 'e',
+
+    Tifloat   = 'o',
+    Tidouble  = 'p',
+    Tireal    = 'j',
+    Tcfloat   = 'q',
+    Tcdouble  = 'r',
+    Tcreal    = 'c',
+
+    Tchar     = 'a',
+    Twchar    = 'u',
+    Tdchar    = 'w',
+
+    Tarray    = 'A',
+    Tsarray   = 'G',
+    Taarray   = 'H',
+    Tpointer  = 'P',
+    Tfunction = 'F',
+    Tident    = 'I',
+    Tclass    = 'C',
+    Tstruct   = 'S',
+    Tenum     = 'E',
+    Ttypedef  = 'T',
+    Tdelegate = 'D',
+
+    Tconst    = 'x',
+    Tinvariant = 'y',
+}
+
+// return the TypeInfo for a primitive type and null otherwise.
+// This is required since for arrays of ints we only have the mangled
+// char to work from. If arrays always subclassed TypeInfo_Array this
+// routine could go away.
+private TypeInfo primitiveTypeInfo(Mangle m) 
+{
+  TypeInfo ti;
+
+  switch (m)
+    {
+    case Mangle.Tvoid:
+      ti = typeid(void);break;
+    case Mangle.Tbool:
+      ti = typeid(bool);break;
+    case Mangle.Tbyte:
+      ti = typeid(byte);break;
+    case Mangle.Tubyte:
+      ti = typeid(ubyte);break;
+    case Mangle.Tshort:
+      ti = typeid(short);break;
+    case Mangle.Tushort:
+      ti = typeid(ushort);break;
+    case Mangle.Tint:
+      ti = typeid(int);break;
+    case Mangle.Tuint:
+      ti = typeid(uint);break;
+    case Mangle.Tlong:
+      ti = typeid(long);break;
+    case Mangle.Tulong:
+      ti = typeid(ulong);break;
+    case Mangle.Tfloat:
+      ti = typeid(float);break;
+    case Mangle.Tdouble:
+      ti = typeid(double);break;
+    case Mangle.Treal:
+      ti = typeid(real);break;
+    case Mangle.Tifloat:
+      ti = typeid(ifloat);break;
+    case Mangle.Tidouble:
+      ti = typeid(idouble);break;
+    case Mangle.Tireal:
+      ti = typeid(ireal);break;
+    case Mangle.Tcfloat:
+      ti = typeid(cfloat);break;
+    case Mangle.Tcdouble:
+      ti = typeid(cdouble);break;
+    case Mangle.Tcreal:
+      ti = typeid(creal);break;
+    case Mangle.Tchar:
+      ti = typeid(char);break;
+    case Mangle.Twchar:
+      ti = typeid(wchar);break;
+    case Mangle.Tdchar:
+      ti = typeid(dchar);
+    default:
+      ti = null;
+    }
+  return ti;
+}
+
+/************************************
+ * Interprets variadic argument list pointed to by argptr whose types are given
+ * by arguments[], formats them according to embedded format strings in the
+ * variadic argument list, and sends the resulting characters to putc.
+ *
+ * The variadic arguments are consumed in order.
+ * Each is formatted into a sequence of chars, using the default format
+ * specification for its type, and the
+ * characters are sequentially passed to putc.
+ * If a char[], wchar[], or dchar[]
+ * argument is encountered, it is interpreted as a format string. As many
+ * arguments as specified in the format string are consumed and formatted
+ * according to the format specifications in that string and passed to putc. If
+ * there are too few remaining arguments, a FormatError is thrown. If there are
+ * more remaining arguments than needed by the format specification, the default
+ * processing of arguments resumes until they are all consumed.
+ *
+ * Params:
+ *	putc =	Output is sent do this delegate, character by character.
+ *	arguments = Array of TypeInfo's, one for each argument to be formatted.
+ *	argptr = Points to variadic argument list.
+ *
+ * Throws:
+ *	Mismatched arguments and formats result in a FormatError being thrown.
+ *
+ * Format_String:
+ *	<a name="format-string">$(I Format strings)</a>
+ *	consist of characters interspersed with
+ *	$(I format specifications). Characters are simply copied
+ *	to the output (such as putc) after any necessary conversion
+ *	to the corresponding UTF-8 sequence.
+ *
+ *	A $(I format specification) starts with a '%' character,
+ *	and has the following grammar:
+
+<pre>
+$(I FormatSpecification):
+    $(B '%%')
+    $(B '%') $(I Flags) $(I Width) $(I Precision) $(I FormatChar)
+
+$(I Flags):
+    $(I empty)
+    $(B '-') $(I Flags)
+    $(B '+') $(I Flags)
+    $(B '#') $(I Flags)
+    $(B '0') $(I Flags)
+    $(B ' ') $(I Flags)
+
+$(I Width):
+    $(I empty)
+    $(I Integer)
+    $(B '*')
+
+$(I Precision):
+    $(I empty)
+    $(B '.')
+    $(B '.') $(I Integer)
+    $(B '.*')
+
+$(I Integer):
+    $(I Digit)
+    $(I Digit) $(I Integer)
+
+$(I Digit):
+    $(B '0')
+    $(B '1')
+    $(B '2')
+    $(B '3')
+    $(B '4')
+    $(B '5')
+    $(B '6')
+    $(B '7')
+    $(B '8')
+    $(B '9')
+
+$(I FormatChar):
+    $(B 's')
+    $(B 'b')
+    $(B 'd')
+    $(B 'o')
+    $(B 'x')
+    $(B 'X')
+    $(B 'e')
+    $(B 'E')
+    $(B 'f')
+    $(B 'F')
+    $(B 'g')
+    $(B 'G')
+    $(B 'a')
+    $(B 'A')
+</pre>
+    <dl>
+    <dt>$(I Flags)
+    <dl>
+	<dt>$(B '-')
+	<dd>
+	Left justify the result in the field.
+	It overrides any $(B 0) flag.
+
+	<dt>$(B '+')
+	<dd>Prefix positive numbers in a signed conversion with a $(B +).
+	It overrides any $(I space) flag.
+
+	<dt>$(B '#')
+	<dd>Use alternative formatting:
+	<dl>
+	    <dt>For $(B 'o'):
+	    <dd> Add to precision as necessary so that the first digit
+	    of the octal formatting is a '0', even if both the argument
+	    and the $(I Precision) are zero.
+	    <dt> For $(B 'x') ($(B 'X')):
+	    <dd> If non-zero, prefix result with $(B 0x) ($(B 0X)).
+	    <dt> For floating point formatting:
+	    <dd> Always insert the decimal point.
+	    <dt> For $(B 'g') ($(B 'G')):
+	    <dd> Do not elide trailing zeros.
+	</dl>
+
+	<dt>$(B '0')
+	<dd> For integer and floating point formatting when not nan or
+	infinity, use leading zeros
+	to pad rather than spaces.
+	Ignore if there's a $(I Precision).
+
+	<dt>$(B ' ')
+	<dd>Prefix positive numbers in a signed conversion with a space.
+    </dl>
+
+    <dt>$(I Width)
+    <dd>
+    Specifies the minimum field width.
+    If the width is a $(B *), the next argument, which must be
+    of type $(B int), is taken as the width.
+    If the width is negative, it is as if the $(B -) was given
+    as a $(I Flags) character.
+
+    <dt>$(I Precision)
+    <dd> Gives the precision for numeric conversions.
+    If the precision is a $(B *), the next argument, which must be
+    of type $(B int), is taken as the precision. If it is negative,
+    it is as if there was no $(I Precision).
+
+    <dt>$(I FormatChar)
+    <dd>
+    <dl>
+	<dt>$(B 's')
+	<dd>The corresponding argument is formatted in a manner consistent
+	with its type:
+	<dl>
+	    <dt>$(B bool)
+	    <dd>The result is <tt>'true'</tt> or <tt>'false'</tt>.
+	    <dt>integral types
+	    <dd>The $(B %d) format is used.
+	    <dt>floating point types
+	    <dd>The $(B %g) format is used.
+	    <dt>string types
+	    <dd>The result is the string converted to UTF-8.
+	    A $(I Precision) specifies the maximum number of characters
+	    to use in the result.
+	    <dt>classes derived from $(B Object)
+	    <dd>The result is the string returned from the class instance's
+	    $(B .toString()) method.
+	    A $(I Precision) specifies the maximum number of characters
+	    to use in the result.
+	    <dt>non-string static and dynamic arrays
+	    <dd>The result is [s<sub>0</sub>, s<sub>1</sub>, ...]
+	    where s<sub>k</sub> is the kth element 
+	    formatted with the default format.
+	</dl>
+
+	<dt>$(B 'b','d','o','x','X')
+	<dd> The corresponding argument must be an integral type
+	and is formatted as an integer. If the argument is a signed type
+	and the $(I FormatChar) is $(B d) it is converted to
+	a signed string of characters, otherwise it is treated as
+	unsigned. An argument of type $(B bool) is formatted as '1'
+	or '0'. The base used is binary for $(B b), octal for $(B o),
+	decimal
+	for $(B d), and hexadecimal for $(B x) or $(B X).
+	$(B x) formats using lower case letters, $(B X) uppercase.
+	If there are fewer resulting digits than the $(I Precision),
+	leading zeros are used as necessary.
+	If the $(I Precision) is 0 and the number is 0, no digits
+	result.
+
+	<dt>$(B 'e','E')
+	<dd> A floating point number is formatted as one digit before
+	the decimal point, $(I Precision) digits after, the $(I FormatChar),
+	&plusmn;, followed by at least a two digit exponent: $(I d.dddddd)e$(I &plusmn;dd).
+	If there is no $(I Precision), six
+	digits are generated after the decimal point.
+	If the $(I Precision) is 0, no decimal point is generated.
+
+	<dt>$(B 'f','F')
+	<dd> A floating point number is formatted in decimal notation.
+	The $(I Precision) specifies the number of digits generated
+	after the decimal point. It defaults to six. At least one digit
+	is generated before the decimal point. If the $(I Precision)
+	is zero, no decimal point is generated.
+
+	<dt>$(B 'g','G')
+	<dd> A floating point number is formatted in either $(B e) or
+	$(B f) format for $(B g); $(B E) or $(B F) format for
+	$(B G).
+	The $(B f) format is used if the exponent for an $(B e) format
+	is greater than -5 and less than the $(I Precision).
+	The $(I Precision) specifies the number of significant
+	digits, and defaults to six.
+	Trailing zeros are elided after the decimal point, if the fractional
+	part is zero then no decimal point is generated.
+
+	<dt>$(B 'a','A')
+	<dd> A floating point number is formatted in hexadecimal
+	exponential notation 0x$(I h.hhhhhh)p$(I &plusmn;d).
+	There is one hexadecimal digit before the decimal point, and as
+	many after as specified by the $(I Precision).
+	If the $(I Precision) is zero, no decimal point is generated.
+	If there is no $(I Precision), as many hexadecimal digits as
+	necessary to exactly represent the mantissa are generated.
+	The exponent is written in as few digits as possible,
+	but at least one, is in decimal, and represents a power of 2 as in
+	$(I h.hhhhhh)*2<sup>$(I &plusmn;d)</sup>.
+	The exponent for zero is zero.
+	The hexadecimal digits, x and p are in upper case if the
+	$(I FormatChar) is upper case.
+    </dl>
+
+    Floating point NaN's are formatted as $(B nan) if the
+    $(I FormatChar) is lower case, or $(B NAN) if upper.
+    Floating point infinities are formatted as $(B inf) or
+    $(B infinity) if the
+    $(I FormatChar) is lower case, or $(B INF) or $(B INFINITY) if upper.
+    </dl>
+
+Example:
+
+-------------------------
+import std.c.stdio;
+import std.format;
+
+void formattedPrint(...)
+{
+    void putc(char c)
+    {
+	fputc(c, stdout);
+    }
+
+    std.format.doFormat(&putc, _arguments, _argptr);
+}
+
+...
+
+int x = 27;
+// prints 'The answer is 27:6'
+formattedPrint("The answer is %s:", x, 6);
+------------------------
+ */
+
+void doFormat(void delegate(dchar) putc, TypeInfo[] arguments, void* argptr)
+{   //printf("doFormat(...)\n");
+    int j;
+    TypeInfo ti;
+    Mangle m;
+    uint flags;
+    int field_width;
+    int precision;
+
+    enum : uint
+    {
+	FLdash = 1,
+	FLplus = 2,
+	FLspace = 4,
+	FLhash = 8,
+	FLlngdbl = 0x20,
+	FL0pad = 0x40,
+	FLprecision = 0x80,
+    }
+
+    static TypeInfo skipCI(TypeInfo valti)
+    {
+      while (1)
+      {
+	if (valti.classinfo.name.length == 18 &&
+	    valti.classinfo.name[9..18] == "Invariant")
+	    valti =	(cast(TypeInfo_Invariant)valti).next;
+	else if (valti.classinfo.name.length == 14 &&
+	    valti.classinfo.name[9..14] == "Const")
+	    valti =	(cast(TypeInfo_Const)valti).next;
+	else
+	    break;
+      }
+      return valti;
+    }
+
+    void formatArg(char fc)
+    {
+	bool vbit;
+	ulong vnumber;
+	char vchar;
+	dchar vdchar;
+	Object vobject;
+	real vreal;
+	creal vcreal;
+	Mangle m2;
+	int signed = 0;
+	uint base = 10;
+	int uc;
+	char[ulong.sizeof * 8] tmpbuf;	// long enough to print long in binary
+	char* prefix = "";
+	string s;
+
+	void putstr(char[] s)
+	{
+	    //printf("flags = 0x%x\n", flags);
+	    int prepad = 0;
+	    int postpad = 0;
+	    int padding = field_width - (strlen(prefix) + s.length);
+	    if (padding > 0)
+	    {
+		if (flags & FLdash)
+		    postpad = padding;
+		else
+		    prepad = padding;
+	    }
+
+	    if (flags & FL0pad)
+	    {
+		while (*prefix)
+		    putc(*prefix++);
+		while (prepad--)
+		    putc('0');
+	    }
+	    else
+	    {
+		while (prepad--)
+		    putc(' ');
+		while (*prefix)
+		    putc(*prefix++);
+	    }
+
+	    foreach (dchar c; s)
+		putc(c);
+
+	    while (postpad--)
+		putc(' ');
+	}
+
+	void putreal(real v)
+	{
+	    //printf("putreal %Lg\n", vreal); // no 80 bit float
+        //printf("putreal %g\n", vreal);
+
+	    switch (fc)
+	    {
+		case 's':
+		    fc = 'g';
+		    break;
+
+		case 'f', 'F', 'e', 'E', 'g', 'G', 'a', 'A':
+		    break;
+
+		default:
+		    //printf("fc = '%c'\n", fc);
+		Lerror:
+		    throw new FormatError("floating");
+	    }
+	    version (DigitalMarsC)
+	    {
+		int sl;
+		char[] fbuf = tmpbuf;
+		if (!(flags & FLprecision))
+		    precision = 6;
+		while (1)
+		{
+		    sl = fbuf.length;
+		    prefix = (*__pfloatfmt)(fc, flags | FLlngdbl,
+			    precision, &v, cast(char*)fbuf, &sl, field_width);
+		    if (sl != -1)
+			break;
+		    sl = fbuf.length * 2;
+		    fbuf = (cast(char*)/*alloca*/malloc(sl * char.sizeof))[0 .. sl];
+		}
+		putstr(fbuf[0 .. sl]);
+	    }
+	    else
+	    {
+		int sl;
+		char[] fbuf = tmpbuf;
+		char[12] format;
+		format[0] = '%';
+		int i = 1;
+		if (flags & FLdash)
+		    format[i++] = '-';
+		if (flags & FLplus)
+		    format[i++] = '+';
+		if (flags & FLspace)
+		    format[i++] = ' ';
+		if (flags & FLhash)
+		    format[i++] = '#';
+		if (flags & FL0pad)
+		    format[i++] = '0';
+		format[i + 0] = '*';
+		format[i + 1] = '.';
+		format[i + 2] = '*';
+        format[i + 3] = fc;
+        format[i + 4] = 0;
+		//format[i + 3] = 'L'; // no 80 bit yet
+		//format[i + 4] = fc;
+		//format[i + 5] = 0;
+		if (!(flags & FLprecision))
+		    precision = -1;
+		while (1)
+		{   int n;
+
+		    sl = fbuf.length;
+		    n = snprintf(fbuf.ptr, sl, format.ptr, field_width, precision, v);
+		    //printf("format = '%s', n = %d\n", cast(char*)format, n);
+		    if (n >= 0 && n < sl)
+		    {	sl = n;
+			break;
+		    }
+		    if (n < 0)
+			sl = sl * 2;
+		    else
+			sl = n + 1;
+		    fbuf = (cast(char*)/*alloca*/malloc(sl * char.sizeof))[0 .. sl];
+		}
+		putstr(fbuf[0 .. sl]);
+	    }
+	    return;
+	}
+
+	static Mangle getMan(TypeInfo ti)
+	{
+	  auto m = cast(Mangle)ti.classinfo.name[9];
+	  if (ti.classinfo.name.length == 20 &&
+	      ti.classinfo.name[9..20] == "StaticArray")
+		m = cast(Mangle)'G';
+	  return m;
+	}
+
+	void putArray(void* p, size_t len, TypeInfo valti)
+	{
+	  //printf("\nputArray(len = %u), tsize = %u\n", len, valti.tsize());
+	  putc('[');
+	  valti = skipCI(valti);
+	  size_t tsize = valti.tsize();
+	  auto argptrSave = argptr;
+	  auto tiSave = ti;
+	  auto mSave = m;
+	  ti = valti;
+      auto className = valti.classinfo.name;
+	  printf("\n%.*s\n", className.length, className.ptr);
+	  m = getMan(valti);
+	  while (len--)
+	  {
+	    //doFormat(putc, (&valti)[0 .. 1], p);
+	    argptr = p;
+	    formatArg('s');
+
+	    p += tsize;
+	    if (len > 0) putc(',');
+	  }
+	  m = mSave;
+	  ti = tiSave;
+	  argptr = argptrSave;
+	  putc(']');
+	}
+
+	void putAArray(ubyte[long] vaa, TypeInfo valti, TypeInfo keyti)
+	{
+	  putc('[');
+	  bool comma=false;
+	  auto argptrSave = argptr;
+	  auto tiSave = ti;
+	  auto mSave = m;
+	  valti = skipCI(valti);
+	  keyti = skipCI(keyti);
+	  foreach(inout fakevalue; vaa)
+	  {
+	    if (comma) putc(',');
+	    comma = true;
+	    // the key comes before the value
+	    ubyte* key = &fakevalue - long.sizeof;
+
+	    //doFormat(putc, (&keyti)[0..1], key);
+	    argptr = key;
+	    ti = keyti;
+	    m = getMan(keyti);
+	    formatArg('s');
+
+	    putc(':');
+	    auto keysize = keyti.tsize;
+	    keysize = (keysize + 3) & ~3;
+	    ubyte* value = key + keysize;
+	    //doFormat(putc, (&valti)[0..1], value);
+	    argptr = value;
+	    ti = valti;
+	    m = getMan(valti);
+	    formatArg('s');
+	  }
+	  m = mSave;
+	  ti = tiSave;
+	  argptr = argptrSave;
+	  putc(']');
+	}
+
+	//printf("formatArg(fc = '%c', m = '%c')\n", fc, m);
+	switch (m)
+	{
+	    case Mangle.Tbool:
+		vbit = va_arg!(bool)(argptr);
+		if (fc != 's')
+		{   vnumber = vbit;
+		    goto Lnumber;
+		}
+		putstr(vbit ? "true" : "false");
+		return;
+
+
+	    case Mangle.Tchar:
+		vchar = va_arg!(char)(argptr);
+		if (fc != 's')
+		{   vnumber = vchar;
+		    goto Lnumber;
+		}
+	    L2:
+		putstr((&vchar)[0 .. 1]);
+		return;
+
+	    case Mangle.Twchar:
+		vdchar = va_arg!(wchar)(argptr);
+		goto L1;
+
+	    case Mangle.Tdchar:
+		vdchar = va_arg!(dchar)(argptr);
+	    L1:
+		if (fc != 's')
+		{   vnumber = vdchar;
+		    goto Lnumber;
+		}
+		if (vdchar <= 0x7F)
+		{   vchar = cast(char)vdchar;
+		    goto L2;
+		}
+		else
+		{   if (!isValidDchar(vdchar))
+			throw new UtfException("invalid dchar in format", 0);
+		    char[4] vbuf;
+		    putstr(toUTF8(vbuf, vdchar));
+		}
+		return;
+
+
+	    case Mangle.Tbyte:
+		signed = 1;
+		vnumber = va_arg!(byte)(argptr);
+		goto Lnumber;
+
+	    case Mangle.Tubyte:
+		vnumber = va_arg!(ubyte)(argptr);
+		goto Lnumber;
+
+	    case Mangle.Tshort:
+		signed = 1;
+		vnumber = va_arg!(short)(argptr);
+		goto Lnumber;
+
+	    case Mangle.Tushort:
+		vnumber = va_arg!(ushort)(argptr);
+		goto Lnumber;
+
+	    case Mangle.Tint:
+		signed = 1;
+		vnumber = va_arg!(int)(argptr);
+		goto Lnumber;
+
+	    case Mangle.Tuint:
+	    Luint:
+		vnumber = va_arg!(uint)(argptr);
+		goto Lnumber;
+
+	    case Mangle.Tlong:
+		signed = 1;
+		vnumber = cast(ulong)va_arg!(long)(argptr);
+		goto Lnumber;
+
+	    case Mangle.Tulong:
+	    Lulong:
+		vnumber = va_arg!(ulong)(argptr);
+		goto Lnumber;
+
+	    case Mangle.Tclass:
+		vobject = va_arg!(Object)(argptr);
+		if (vobject is null)
+		    s = "null";
+		else
+		    s = vobject.toString();
+		goto Lputstr;
+
+	    case Mangle.Tpointer:
+		vnumber = cast(ulong)va_arg!(void*)(argptr);
+		uc = 1;
+		flags |= FL0pad;
+		if (!(flags & FLprecision))
+		{   flags |= FLprecision;
+		    precision = (void*).sizeof;
+		}
+		base = 16;
+		goto Lnumber;
+
+
+	    case Mangle.Tfloat:
+	    case Mangle.Tifloat:
+		if (fc == 'x' || fc == 'X')
+		    goto Luint;
+		vreal = va_arg!(float)(argptr);
+		goto Lreal;
+
+	    case Mangle.Tdouble:
+	    case Mangle.Tidouble:
+		if (fc == 'x' || fc == 'X')
+		    goto Lulong;
+		vreal = va_arg!(double)(argptr);
+		goto Lreal;
+
+	    case Mangle.Treal:
+	    case Mangle.Tireal:
+		vreal = va_arg!(real)(argptr);
+		goto Lreal;
+
+
+	    case Mangle.Tcfloat:
+		vcreal = va_arg!(cfloat)(argptr);
+		goto Lcomplex;
+
+	    case Mangle.Tcdouble:
+		vcreal = va_arg!(cdouble)(argptr);
+		goto Lcomplex;
+
+	    case Mangle.Tcreal:
+		vcreal = va_arg!(creal)(argptr);
+		goto Lcomplex;
+
+	    case Mangle.Tsarray:
+        //printf("static array\n");
+		putArray(argptr, (cast(TypeInfo_StaticArray)ti).len, (cast(TypeInfo_StaticArray)ti).next);
+		return;
+
+	    case Mangle.Tarray:
+        //printf("dynamic array\n");
+		int mi = 10;
+	        if (ti.classinfo.name.length == 14 &&
+		    ti.classinfo.name[9..14] == "Array") 
+		{ // array of non-primitive types
+		  TypeInfo tn = (cast(TypeInfo_Array)ti).next;
+		  tn = skipCI(tn);
+		  switch (cast(Mangle)tn.classinfo.name[9])
+		  {
+		    case Mangle.Tchar:  goto LarrayChar;
+		    case Mangle.Twchar: goto LarrayWchar;
+		    case Mangle.Tdchar: goto LarrayDchar;
+		    default:
+			break;
+		  }
+		  void[] va = va_arg!(void[])(argptr);
+		  putArray(va.ptr, va.length, tn);
+		  return;
+		}
+		if (ti.classinfo.name.length == 25 &&
+		    ti.classinfo.name[9..25] == "AssociativeArray") 
+		{ // associative array
+		  ubyte[long] vaa = va_arg!(ubyte[long])(argptr);
+		  putAArray(vaa,
+			(cast(TypeInfo_AssociativeArray)ti).next,
+			(cast(TypeInfo_AssociativeArray)ti).key);
+		  return;
+		}
+
+        //printf("primitive type\n");
+		while (1)
+		{
+		    m2 = cast(Mangle)ti.classinfo.name[mi];
+		    switch (m2)
+		    {
+			case Mangle.Tchar:
+			LarrayChar:
+			    s = va_arg!(char[])(argptr);
+			    goto Lputstr;
+
+			case Mangle.Twchar:
+			LarrayWchar:
+			    wchar[] sw = va_arg!(wchar[])(argptr);
+			    s = toUTF8(sw);
+			    goto Lputstr;
+
+			case Mangle.Tdchar:
+			LarrayDchar:
+			    dchar[] sd = va_arg!(dchar[])(argptr);
+			    s = toUTF8(sd);
+			Lputstr:
+			    if (fc != 's')
+				throw new FormatError("string");
+			    if (flags & FLprecision && precision < s.length)
+				s = s[0 .. precision];
+			    putstr(s);
+			    break;
+
+			case Mangle.Tconst:
+			case Mangle.Tinvariant:
+			    mi++;
+			    continue;
+
+			default:
+                //printf("primitive type default handling\n");
+			    TypeInfo ti2 = primitiveTypeInfo(m2);
+			    if (!ti2)
+			      goto Lerror;
+			    void[] va = va_arg!(void[])(argptr);
+			    putArray(va.ptr, va.length, ti2);
+		    }
+		    return;
+		}
+
+	    case Mangle.Ttypedef:
+		ti = (cast(TypeInfo_Typedef)ti).base;
+		m = cast(Mangle)ti.classinfo.name[9];
+		formatArg(fc);
+		return;
+
+	    case Mangle.Tenum:
+		ti = (cast(TypeInfo_Enum)ti).base;
+		m = cast(Mangle)ti.classinfo.name[9];
+		formatArg(fc);
+		return;
+
+	    case Mangle.Tstruct:
+	    {	TypeInfo_Struct tis = cast(TypeInfo_Struct)ti;
+		if (tis.xtoString is null)
+		    throw new FormatError("Can't convert " ~ tis.toString() ~ " to string: \"string toString()\" not defined");
+		s = tis.xtoString(argptr);
+		argptr += (tis.tsize() + 3) & ~3;
+		goto Lputstr;
+	    }
+
+	    default:
+		goto Lerror;
+	}
+
+    Lnumber:
+	switch (fc)
+	{
+	    case 's':
+	    case 'd':
+		if (signed)
+		{   if (cast(long)vnumber < 0)
+		    {	prefix = "-";
+			vnumber = -vnumber;
+		    }
+		    else if (flags & FLplus)
+			prefix = "+";
+		    else if (flags & FLspace)
+			prefix = " ";
+		}
+		break;
+
+	    case 'b':
+		signed = 0;
+		base = 2;
+		break;
+
+	    case 'o':
+		signed = 0;
+		base = 8;
+		break;
+
+	    case 'X':
+		uc = 1;
+		if (flags & FLhash && vnumber)
+		    prefix = "0X";
+		signed = 0;
+		base = 16;
+		break;
+
+	    case 'x':
+		if (flags & FLhash && vnumber)
+		    prefix = "0x";
+		signed = 0;
+		base = 16;
+		break;
+
+	    default:
+		goto Lerror;
+	}
+
+	if (!signed)
+	{
+	    switch (m)
+	    {
+		case Mangle.Tbyte:
+		    vnumber &= 0xFF;
+		    break;
+
+		case Mangle.Tshort:
+		    vnumber &= 0xFFFF;
+		    break;
+
+		case Mangle.Tint:
+		    vnumber &= 0xFFFFFFFF;
+		    break;
+
+		default:
+		    break;
+	    }
+	}
+
+	if (flags & FLprecision && fc != 'p')
+	    flags &= ~FL0pad;
+
+	if (vnumber < base)
+	{
+	    if (vnumber == 0 && precision == 0 && flags & FLprecision &&
+		!(fc == 'o' && flags & FLhash))
+	    {
+		putstr(null);
+		return;
+	    }
+	    if (precision == 0 || !(flags & FLprecision))
+	    {	vchar = cast(char)('0' + vnumber);
+		if (vnumber < 10)
+		    vchar = cast(char)('0' + vnumber);
+		else
+		    vchar = cast(char)((uc ? 'A' - 10 : 'a' - 10) + vnumber);
+		goto L2;
+	    }
+	}
+
+	int n = tmpbuf.length;
+	char c;
+	int hexoffset = uc ? ('A' - ('9' + 1)) : ('a' - ('9' + 1));
+
+	while (vnumber)
+	{
+	    c = cast(char)((vnumber % base) + '0');
+	    if (c > '9')
+		c += hexoffset;
+	    vnumber /= base;
+	    tmpbuf[--n] = c;
+	}
+	if (tmpbuf.length - n < precision && precision < tmpbuf.length)
+	{
+	    int m = tmpbuf.length - precision;
+	    tmpbuf[m .. n] = '0';
+	    n = m;
+	}
+	else if (flags & FLhash && fc == 'o')
+	    prefix = "0";
+	putstr(tmpbuf[n .. tmpbuf.length]);
+	return;
+
+    Lreal:
+	putreal(vreal);
+	return;
+
+    Lcomplex:
+	putreal(vcreal.re);
+	putc('+');
+	putreal(vcreal.im);
+	putc('i');
+	return;
+
+    Lerror:
+	throw new FormatError("formatArg");
+    }
+
+
+    //printf("arguments length: %u\n", arguments.length);
+    for (j = 0; j < arguments.length; )
+    {	ti = arguments[j++];
+	//printf("test1: '%.*s' %d\n", ti.classinfo.name.length, ti.classinfo.name.ptr, ti.classinfo.name.length);
+	//ti.print();
+
+	flags = 0;
+	precision = 0;
+	field_width = 0;
+
+	ti = skipCI(ti);
+	int mi = 9;
+	do
+	{
+	    if (ti.classinfo.name.length <= mi)
+		goto Lerror;
+	    m = cast(Mangle)ti.classinfo.name[mi++];
+	} while (m == Mangle.Tconst || m == Mangle.Tinvariant);
+
+	if (m == Mangle.Tarray)
+	{
+	    if (ti.classinfo.name.length == 14 &&
+		ti.classinfo.name[9..14] == "Array") 
+	    {
+	      TypeInfo tn = (cast(TypeInfo_Array)ti).next;
+	      tn = skipCI(tn);
+	      switch (cast(Mangle)tn.classinfo.name[9])
+	      {
+		case Mangle.Tchar:
+		case Mangle.Twchar:
+		case Mangle.Tdchar:
+		    ti = tn;
+		    mi = 9;
+		    break;
+		default:
+		    break;
+	      }
+	    }
+	L1:
+	    Mangle m2 = cast(Mangle)ti.classinfo.name[mi];
+	    string  fmt;			// format string
+	    wstring wfmt;
+	    dstring dfmt;
+
+	    /* For performance reasons, this code takes advantage of the
+	     * fact that most format strings will be ASCII, and that the
+	     * format specifiers are always ASCII. This means we only need
+	     * to deal with UTF in a couple of isolated spots.
+	     */
+
+	    switch (m2)
+	    {
+		case Mangle.Tchar:
+		    fmt = va_arg!(char[])(argptr);
+		    break;
+
+		case Mangle.Twchar:
+		    wfmt = va_arg!(wchar[])(argptr);
+		    fmt = toUTF8(wfmt);
+		    break;
+
+		case Mangle.Tdchar:
+		    dfmt = va_arg!(dchar[])(argptr);
+		    fmt = toUTF8(dfmt);
+		    break;
+
+		case Mangle.Tconst:
+		case Mangle.Tinvariant:
+		    mi++;
+		    goto L1;
+
+		default:
+		    formatArg('s');
+		    continue;
+	    }
+
+	    for (size_t i = 0; i < fmt.length; )
+	    {	dchar c = fmt[i++];
+
+		dchar getFmtChar()
+		{   // Valid format specifier characters will never be UTF
+		    if (i == fmt.length)
+			throw new FormatError("invalid specifier");
+		    return fmt[i++];
+		}
+
+		int getFmtInt()
+		{   int n;
+
+		    while (1)
+		    {
+			n = n * 10 + (c - '0');
+			if (n < 0)	// overflow
+			    throw new FormatError("int overflow");
+			c = getFmtChar();
+			if (c < '0' || c > '9')
+			    break;
+		    }
+		    return n;
+		}
+
+		int getFmtStar()
+		{   Mangle m;
+		    TypeInfo ti;
+
+		    if (j == arguments.length)
+			throw new FormatError("too few arguments");
+		    ti = arguments[j++];
+		    m = cast(Mangle)ti.classinfo.name[9];
+		    if (m != Mangle.Tint)
+			throw new FormatError("int argument expected");
+		    return va_arg!(int)(argptr);
+		}
+
+		if (c != '%')
+		{
+		    if (c > 0x7F)	// if UTF sequence
+		    {
+			i--;		// back up and decode UTF sequence
+			c = std.utf.decode(fmt, i);
+		    }
+		Lputc:
+		    putc(c);
+		    continue;
+		}
+
+		// Get flags {-+ #}
+		flags = 0;
+		while (1)
+		{
+		    c = getFmtChar();
+		    switch (c)
+		    {
+			case '-':	flags |= FLdash;	continue;
+			case '+':	flags |= FLplus;	continue;
+			case ' ':	flags |= FLspace;	continue;
+			case '#':	flags |= FLhash;	continue;
+			case '0':	flags |= FL0pad;	continue;
+
+			case '%':	if (flags == 0)
+					    goto Lputc;
+			default:	break;
+		    }
+		    break;
+		}
+
+		// Get field width
+		field_width = 0;
+		if (c == '*')
+		{
+		    field_width = getFmtStar();
+		    if (field_width < 0)
+		    {   flags |= FLdash;
+			field_width = -field_width;
+		    }
+
+		    c = getFmtChar();
+		}
+		else if (c >= '0' && c <= '9')
+		    field_width = getFmtInt();
+
+		if (flags & FLplus)
+		    flags &= ~FLspace;
+		if (flags & FLdash)
+		    flags &= ~FL0pad;
+
+		// Get precision
+		precision = 0;
+		if (c == '.')
+		{   flags |= FLprecision;
+		    //flags &= ~FL0pad;
+
+		    c = getFmtChar();
+		    if (c == '*')
+		    {
+			precision = getFmtStar();
+			if (precision < 0)
+			{   precision = 0;
+			    flags &= ~FLprecision;
+			}
+
+			c = getFmtChar();
+		    }
+		    else if (c >= '0' && c <= '9')
+			precision = getFmtInt();
+		}
+
+		if (j == arguments.length)
+		    goto Lerror;
+		ti = arguments[j++];
+		ti = skipCI(ti);
+		mi = 9;
+		do
+		{
+		    m = cast(Mangle)ti.classinfo.name[mi++];
+		} while (m == Mangle.Tconst || m == Mangle.Tinvariant);
+
+		if (c > 0x7F)		// if UTF sequence
+		    goto Lerror;	// format specifiers can't be UTF
+		formatArg(cast(char)c);
+	    }
+	}
+	else
+	{
+	    formatArg('s');
+	}
+    }
+    return;
+
+Lerror:
+    throw new FormatError();
+}
+
+/* ======================== Unit Tests ====================================== */
+
+unittest
+{
+    int i;
+    string s;
+
+    debug(format) printf("std.format.format.unittest\n");
+ 
+    s = std.string.format("hello world! %s %s ", true, 57, 1_000_000_000, 'x', " foo");
+    assert(s == "hello world! true 57 1000000000x foo");
+
+    s = std.string.format(1.67, " %A ", -1.28, float.nan);
+    /* The host C library is used to format floats.
+     * C99 doesn't specify what the hex digit before the decimal point
+     * is for %A.
+     */
+    version (linux)
+	assert(s == "1.67 -0XA.3D70A3D70A3D8P-3 nan");
+    else
+	assert(s == "1.67 -0X1.47AE147AE147BP+0 nan");
+
+    s = std.string.format("%x %X", 0x1234AF, 0xAFAFAFAF);
+    assert(s == "1234af AFAFAFAF");
+
+    s = std.string.format("%b %o", 0x1234AF, 0xAFAFAFAF);
+    assert(s == "100100011010010101111 25753727657");
+
+    s = std.string.format("%d %s", 0x1234AF, 0xAFAFAFAF);
+    assert(s == "1193135 2947526575");
+
+    s = std.string.format("%s", 1.2 + 3.4i);
+    assert(s == "1.2+3.4i");
+
+    s = std.string.format("%x %X", 1.32, 6.78f);
+    assert(s == "3ff51eb851eb851f 40D8F5C3");
+
+    s = std.string.format("%#06.*f",2,12.345);
+    assert(s == "012.35");
+
+    s = std.string.format("%#0*.*f",6,2,12.345);
+    assert(s == "012.35");
+
+    s = std.string.format("%7.4g:", 12.678);
+    assert(s == "  12.68:");
+
+    s = std.string.format("%7.4g:", 12.678L);
+    assert(s == "  12.68:");
+
+    s = std.string.format("%04f|%05d|%#05x|%#5x",-4.,-10,1,1);
+    assert(s == "-4.000000|-0010|0x001|  0x1");
+
+    i = -10;
+    s = std.string.format("%d|%3d|%03d|%1d|%01.4f",i,i,i,i,cast(double) i);
+    assert(s == "-10|-10|-10|-10|-10.0000");
+
+    i = -5;
+    s = std.string.format("%d|%3d|%03d|%1d|%01.4f",i,i,i,i,cast(double) i);
+    assert(s == "-5| -5|-05|-5|-5.0000");
+
+    i = 0;
+    s = std.string.format("%d|%3d|%03d|%1d|%01.4f",i,i,i,i,cast(double) i);
+    assert(s == "0|  0|000|0|0.0000");
+
+    i = 5;
+    s = std.string.format("%d|%3d|%03d|%1d|%01.4f",i,i,i,i,cast(double) i);
+    assert(s == "5|  5|005|5|5.0000");
+
+    i = 10;
+    s = std.string.format("%d|%3d|%03d|%1d|%01.4f",i,i,i,i,cast(double) i);
+    assert(s == "10| 10|010|10|10.0000");
+
+    s = std.string.format("%.0d", 0);
+    assert(s == "");
+
+    s = std.string.format("%.g", .34);
+    assert(s == "0.3");
+
+    s = std.string.format("%.0g", .34);
+    assert(s == "0.3");
+
+    s = std.string.format("%.2g", .34);
+    assert(s == "0.34");
+
+    s = std.string.format("%0.0008f", 1e-08);
+    assert(s == "0.00000001");
+
+    s = std.string.format("%0.0008f", 1e-05);
+    assert(s == "0.00001000");
+
+    s = "helloworld";
+    string r;
+    r = std.string.format("%.2s", s[0..5]);
+    assert(r == "he");
+    r = std.string.format("%.20s", s[0..5]);
+    assert(r == "hello");
+    r = std.string.format("%8s", s[0..5]);
+    assert(r == "   hello");
+
+    byte[] arrbyte = new byte[4];
+    arrbyte[0] = 100;
+    arrbyte[1] = -99;
+    arrbyte[3] = 0;
+    r = std.string.format(arrbyte);
+    assert(r == "[100,-99,0,0]");
+
+    ubyte[] arrubyte = new ubyte[4];
+    arrubyte[0] = 100;
+    arrubyte[1] = 200;
+    arrubyte[3] = 0;
+    r = std.string.format(arrubyte);
+    assert(r == "[100,200,0,0]");
+
+    short[] arrshort = new short[4];
+    arrshort[0] = 100;
+    arrshort[1] = -999;
+    arrshort[3] = 0;
+    r = std.string.format(arrshort);
+    assert(r == "[100,-999,0,0]");
+    r = std.string.format("%s",arrshort);
+    assert(r == "[100,-999,0,0]");
+
+    ushort[] arrushort = new ushort[4];
+    arrushort[0] = 100;
+    arrushort[1] = 20_000;
+    arrushort[3] = 0;
+    r = std.string.format(arrushort);
+    assert(r == "[100,20000,0,0]");
+
+    int[] arrint = new int[4];
+    arrint[0] = 100;
+    arrint[1] = -999;
+    arrint[3] = 0;
+    r = std.string.format(arrint);
+    assert(r == "[100,-999,0,0]");
+    r = std.string.format("%s",arrint);
+    assert(r == "[100,-999,0,0]");
+
+    long[] arrlong = new long[4];
+    arrlong[0] = 100;
+    arrlong[1] = -999;
+    arrlong[3] = 0;
+    r = std.string.format(arrlong);
+    assert(r == "[100,-999,0,0]");
+    r = std.string.format("%s",arrlong);
+    assert(r == "[100,-999,0,0]");
+
+    ulong[] arrulong = new ulong[4];
+    arrulong[0] = 100;
+    arrulong[1] = 999;
+    arrulong[3] = 0;
+    r = std.string.format(arrulong);
+    assert(r == "[100,999,0,0]");
+
+    string[] arr2 = new string[4];
+    arr2[0] = "hello";
+    arr2[1] = "world";
+    arr2[3] = "foo";
+    r = std.string.format(arr2);
+    assert(r == "[hello,world,,foo]");
+
+    r = std.string.format("%.8d", 7);
+    assert(r == "00000007");
+    r = std.string.format("%.8x", 10);
+    assert(r == "0000000a");
+
+    r = std.string.format("%-3d", 7);
+    assert(r == "7  ");
+
+    r = std.string.format("%*d", -3, 7);
+    assert(r == "7  ");
+
+    r = std.string.format("%.*d", -3, 7);
+    assert(r == "7");
+
+    typedef int myint;
+    myint m = -7;
+    r = std.string.format(m);
+    assert(r == "-7");
+
+    r = std.string.format("abc"c);
+    assert(r == "abc");
+    r = std.string.format("def"w);
+    assert(r == "def");
+    r = std.string.format("ghi"d);
+    assert(r == "ghi");
+
+    void* p = cast(void*)0xDEADBEEF;
+    r = std.string.format(p);
+    assert(r == "DEADBEEF");
+
+    r = std.string.format("%#x", 0xabcd);
+    assert(r == "0xabcd");
+    r = std.string.format("%#X", 0xABCD);
+    assert(r == "0XABCD");
+
+    r = std.string.format("%#o", 012345);
+    assert(r == "012345");
+    r = std.string.format("%o", 9);
+    assert(r == "11");
+
+    r = std.string.format("%+d", 123);
+    assert(r == "+123");
+    r = std.string.format("%+d", -123);
+    assert(r == "-123");
+    r = std.string.format("% d", 123);
+    assert(r == " 123");
+    r = std.string.format("% d", -123);
+    assert(r == "-123");
+
+    r = std.string.format("%%");
+    assert(r == "%");
+
+    r = std.string.format("%d", true);
+    assert(r == "1");
+    r = std.string.format("%d", false);
+    assert(r == "0");
+
+    r = std.string.format("%d", 'a');
+    assert(r == "97");
+    wchar wc = 'a';
+    r = std.string.format("%d", wc);
+    assert(r == "97");
+    dchar dc = 'a';
+    r = std.string.format("%d", dc);
+    assert(r == "97");
+
+    byte b = byte.max;
+    r = std.string.format("%x", b);
+    assert(r == "7f");
+    r = std.string.format("%x", ++b);
+    assert(r == "80");
+    r = std.string.format("%x", ++b);
+    assert(r == "81");
+
+    short sh = short.max;
+    r = std.string.format("%x", sh);
+    assert(r == "7fff");
+    r = std.string.format("%x", ++sh);
+    assert(r == "8000");
+    r = std.string.format("%x", ++sh);
+    assert(r == "8001");
+
+    i = int.max;
+    r = std.string.format("%x", i);
+    assert(r == "7fffffff");
+    r = std.string.format("%x", ++i);
+    assert(r == "80000000");
+    r = std.string.format("%x", ++i);
+    assert(r == "80000001");
+
+    r = std.string.format("%x", 10);
+    assert(r == "a");
+    r = std.string.format("%X", 10);
+    assert(r == "A");
+    r = std.string.format("%x", 15);
+    assert(r == "f");
+    r = std.string.format("%X", 15);
+    assert(r == "F");
+
+    Object c = null;
+    r = std.string.format(c);
+    assert(r == "null");
+
+    enum TestEnum
+    {
+	    Value1, Value2
+    }
+    r = std.string.format("%s", TestEnum.Value2);
+    assert(r == "1");
+
+    char[5][int] aa = ([3:"hello", 4:"betty"]);
+    r = std.string.format("%s", aa.values);
+    assert(r == "[[h,e,l,l,o],[b,e,t,t,y]]");
+    r = std.string.format("%s", aa);
+    assert(r == "[3:[h,e,l,l,o],4:[b,e,t,t,y]]");
+
+    static const dchar[] ds = ['a','b'];
+    for (int j = 0; j < ds.length; ++j)
+    {
+	r = std.string.format(" %d", ds[j]);
+	if (j == 0)
+	    assert(r == " 97");
+	else
+	    assert(r == " 98");
+    }
+
+    r = std.string.format(">%14d<, ", 15, [1,2,3]);
+    assert(r == ">            15<, [1,2,3]");
+}
+
--- a/lphobos/std/mmfile.d	Mon Oct 06 21:27:29 2008 +0200
+++ b/lphobos/std/mmfile.d	Mon Oct 06 21:40:33 2008 +0200
@@ -39,6 +39,8 @@
 private import std.c.stdlib;
 private import std.string;
 
+version(linux) version = Unix;
+
 //debug = MMFILE;
 
 version (Win32)
--- a/lphobos/std/outbuffer.d	Mon Oct 06 21:27:29 2008 +0200
+++ b/lphobos/std/outbuffer.d	Mon Oct 06 21:40:33 2008 +0200
@@ -268,7 +268,7 @@
 		if (count != -1)
 		    break;
 		psize *= 2;
-		p = cast(char *) alloca(psize);	// buffer too small, try again with larger size
+		p = cast(char *) /*alloca*/malloc(psize);	// buffer too small, try again with larger size
 	    }
 	    else version(GNU) {
 		count = vsnprintf(p,psize,f,args_copy);
@@ -278,7 +278,7 @@
 		    psize = count + 1;
 		else
 		    break;
-		p = cast(char *) alloca(psize);	// buffer too small, try again with larger size
+		p = cast(char *) /*alloca*/std.gc.malloc(psize);	// buffer too small, try again with larger size
 	    }
 	    else version(linux)
 	    {
@@ -294,7 +294,7 @@
 		    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
+		p = cast(char *) /*alloca*/std.gc.malloc(psize);	// buffer too small, try again with larger size
 	    }
 	}
 	write(p[0 .. count]);
--- a/lphobos/std/outofmemory.d	Mon Oct 06 21:27:29 2008 +0200
+++ b/lphobos/std/outofmemory.d	Mon Oct 06 21:40:33 2008 +0200
@@ -33,10 +33,11 @@
 
 extern (C) void _d_OutOfMemory()
 {
-    assert(0);
-    /*throw cast(OutOfMemoryException)
+    printf("Out of memory!\n");
+    *(cast(int*) 0) = 0;
+    throw cast(OutOfMemoryException)
 	  cast(void *)
-	  OutOfMemoryException.classinfo.init;*/
+	  OutOfMemoryException.classinfo.init;
 }
 
 static this()
--- a/lphobos/std/path.d	Mon Oct 06 21:27:29 2008 +0200
+++ b/lphobos/std/path.d	Mon Oct 06 21:40:33 2008 +0200
@@ -29,6 +29,8 @@
 
 import std.string;
 
+version(linux) version = Unix;
+
 version(Unix)
 {
     import std.c.stdlib;
--- a/lphobos/std/process.d	Mon Oct 06 21:27:29 2008 +0200
+++ b/lphobos/std/process.d	Mon Oct 06 21:40:33 2008 +0200
@@ -43,6 +43,8 @@
 private import std.string;
 private import std.c.process;
 
+version(linux) version = Unix;
+
 /**
  * Execute command in a _command shell.
  *
--- a/lphobos/std/random.d	Mon Oct 06 21:27:29 2008 +0200
+++ b/lphobos/std/random.d	Mon Oct 06 21:40:33 2008 +0200
@@ -17,6 +17,8 @@
 // Segments of the code in this file Copyright (c) 1997 by Rick Booth
 // From "Inner Loops" by Rick Booth, Addison-Wesley
 
+version(linux) version = Unix;
+
 version (Win32)
 {
     extern(Windows) int QueryPerformanceCounter(ulong *count);
--- a/lphobos/std/regexp.d	Mon Oct 06 21:27:29 2008 +0200
+++ b/lphobos/std/regexp.d	Mon Oct 06 21:40:33 2008 +0200
@@ -1820,7 +1820,7 @@
 		if (!psave && count < m)
 		{
 		    //version (Win32)
-			psave = cast(regmatch_t *)alloca((re_nsub + 1) * regmatch_t.sizeof);
+			psave = cast(regmatch_t *)/*alloca*/malloc((re_nsub + 1) * regmatch_t.sizeof);
 		    //else
 			//psave = new regmatch_t[re_nsub + 1];
 		}
--- a/lphobos/std/socket.d	Mon Oct 06 21:27:29 2008 +0200
+++ b/lphobos/std/socket.d	Mon Oct 06 21:40:33 2008 +0200
@@ -44,7 +44,7 @@
 
 private import std.string, std.stdint, std.c.string, std.c.stdlib;
 
-
+version(linux) version = Unix;
 version(Unix) version = BsdSockets;
 
 version (skyos) { /* nothging */ }
--- a/lphobos/std/stream.d	Mon Oct 06 21:27:29 2008 +0200
+++ b/lphobos/std/stream.d	Mon Oct 06 21:40:33 2008 +0200
@@ -1139,7 +1139,7 @@
 	if (count != -1)
 	  break;
 	psize *= 2;
-	p = cast(char*) alloca(psize);
+	p = cast(char*) /*alloca*/malloc(psize);
       } else version (Unix) {
 	count = vsnprintf(p, psize, f, args_copy);
 	if (count == -1)
@@ -1148,7 +1148,7 @@
 	  psize = count + 1;
 	else
 	  break;
-	p = cast(char*) alloca(psize);
+	p = cast(char*) /*alloca*/malloc(psize);
       } else
 	  throw new Exception("unsupported platform");
     }
@@ -1779,6 +1779,8 @@
   Append = 10 // includes FileMode.Out
 }
 
+version(linux) version = Unix;
+
 version (Win32) {
   private import std.c.windows.windows;
   extern (Windows) {
@@ -2232,7 +2234,8 @@
  * 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 {
+/// This causes a crash in -O2
+/+class EndianStream : FilterStream {
 
   Endian endian;        /// Endianness property of the source stream.
 
@@ -2510,6 +2513,7 @@
     em.position(0);
   }
 }
++/
 
 /***
  * Parameterized subclass that wraps an array-like buffer with a stream