# HG changeset patch # User Tomas Lindquist Olsen # Date 1223322033 -7200 # Node ID 88e23f8c23542720c43dbbf13bdbc7dc567ab31b # Parent 99f32e96774681c48ed1992037034414b054f90a Applied downs' latest Phobos patch diff -r 99f32e967746 -r 88e23f8c2354 lphobos/build.sh --- 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" diff -r 99f32e967746 -r 88e23f8c2354 lphobos/gc/gc.d --- 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 :) +} diff -r 99f32e967746 -r 88e23f8c2354 lphobos/internal/adi.d --- 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); +} diff -r 99f32e967746 -r 88e23f8c2354 lphobos/internal/eh.d --- 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"); diff -r 99f32e967746 -r 88e23f8c2354 lphobos/llvmdc.conf --- 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 diff -r 99f32e967746 -r 88e23f8c2354 lphobos/object.d --- 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); } + diff -r 99f32e967746 -r 88e23f8c2354 lphobos/std/dateparse.d --- 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]; diff -r 99f32e967746 -r 88e23f8c2354 lphobos/std/file.d --- 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) diff -r 99f32e967746 -r 88e23f8c2354 lphobos/std/format.d --- 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: - * $(I Format strings) - * 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: - -
-$(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')
-
-
-
$(I Flags) -
-
$(B '-') -
- Left justify the result in the field. - It overrides any $(B 0) flag. - -
$(B '+') -
Prefix positive numbers in a signed conversion with a $(B +). - It overrides any $(I space) flag. - -
$(B '#') -
Use alternative formatting: -
-
For $(B 'o'): -
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. -
For $(B 'x') ($(B 'X')): -
If non-zero, prefix result with $(B 0x) ($(B 0X)). -
For floating point formatting: -
Always insert the decimal point. -
For $(B 'g') ($(B 'G')): -
Do not elide trailing zeros. -
- -
$(B '0') -
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). - -
$(B ' ') -
Prefix positive numbers in a signed conversion with a space. -
- -
$(I Width) -
- 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. - -
$(I Precision) -
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). - -
$(I FormatChar) -
-
-
$(B 's') -
The corresponding argument is formatted in a manner consistent - with its type: -
-
$(B bool) -
The result is 'true' or 'false'. -
integral types -
The $(B %d) format is used. -
floating point types -
The $(B %g) format is used. -
string types -
The result is the string converted to UTF-8. - A $(I Precision) specifies the maximum number of characters - to use in the result. -
classes derived from $(B Object) -
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. -
non-string static and dynamic arrays -
The result is [s0, s1, ...] - where sk is the kth element - formatted with the default format. -
- -
$(B 'b','d','o','x','X') -
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. - -
$(B 'e','E') -
A floating point number is formatted as one digit before - the decimal point, $(I Precision) digits after, the $(I FormatChar), - ±, followed by at least a two digit exponent: $(I d.dddddd)e$(I ±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. - -
$(B 'f','F') -
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. - -
$(B 'g','G') -
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. - -
$(B 'a','A') -
A floating point number is formatted in hexadecimal - exponential notation 0x$(I h.hhhhhh)p$(I ±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$(I ±d). - The exponent for zero is zero. - The hexadecimal digits, x and p are in upper case if the - $(I FormatChar) is upper case. -
- - 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. -
- -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: + * $(I Format strings) + * 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: + +
+$(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')
+
+
+
$(I Flags) +
+
$(B '-') +
+ Left justify the result in the field. + It overrides any $(B 0) flag. + +
$(B '+') +
Prefix positive numbers in a signed conversion with a $(B +). + It overrides any $(I space) flag. + +
$(B '#') +
Use alternative formatting: +
+
For $(B 'o'): +
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. +
For $(B 'x') ($(B 'X')): +
If non-zero, prefix result with $(B 0x) ($(B 0X)). +
For floating point formatting: +
Always insert the decimal point. +
For $(B 'g') ($(B 'G')): +
Do not elide trailing zeros. +
+ +
$(B '0') +
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). + +
$(B ' ') +
Prefix positive numbers in a signed conversion with a space. +
+ +
$(I Width) +
+ 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. + +
$(I Precision) +
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). + +
$(I FormatChar) +
+
+
$(B 's') +
The corresponding argument is formatted in a manner consistent + with its type: +
+
$(B bool) +
The result is 'true' or 'false'. +
integral types +
The $(B %d) format is used. +
floating point types +
The $(B %g) format is used. +
string types +
The result is the string converted to UTF-8. + A $(I Precision) specifies the maximum number of characters + to use in the result. +
classes derived from $(B Object) +
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. +
non-string static and dynamic arrays +
The result is [s0, s1, ...] + where sk is the kth element + formatted with the default format. +
+ +
$(B 'b','d','o','x','X') +
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. + +
$(B 'e','E') +
A floating point number is formatted as one digit before + the decimal point, $(I Precision) digits after, the $(I FormatChar), + ±, followed by at least a two digit exponent: $(I d.dddddd)e$(I ±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. + +
$(B 'f','F') +
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. + +
$(B 'g','G') +
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. + +
$(B 'a','A') +
A floating point number is formatted in hexadecimal + exponential notation 0x$(I h.hhhhhh)p$(I ±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$(I ±d). + The exponent for zero is zero. + The hexadecimal digits, x and p are in upper case if the + $(I FormatChar) is upper case. +
+ + 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. +
+ +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]"); +} + diff -r 99f32e967746 -r 88e23f8c2354 lphobos/std/mmfile.d --- 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) diff -r 99f32e967746 -r 88e23f8c2354 lphobos/std/outbuffer.d --- 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]); diff -r 99f32e967746 -r 88e23f8c2354 lphobos/std/outofmemory.d --- 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() diff -r 99f32e967746 -r 88e23f8c2354 lphobos/std/path.d --- 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; diff -r 99f32e967746 -r 88e23f8c2354 lphobos/std/process.d --- 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. * diff -r 99f32e967746 -r 88e23f8c2354 lphobos/std/random.d --- 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); diff -r 99f32e967746 -r 88e23f8c2354 lphobos/std/regexp.d --- 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]; } diff -r 99f32e967746 -r 88e23f8c2354 lphobos/std/socket.d --- 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 */ } diff -r 99f32e967746 -r 88e23f8c2354 lphobos/std/stream.d --- 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