aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/undead/doformat.d
diff options
context:
space:
mode:
Diffstat (limited to 'src/undead/doformat.d')
-rw-r--r--src/undead/doformat.d1620
1 files changed, 0 insertions, 1620 deletions
diff --git a/src/undead/doformat.d b/src/undead/doformat.d
deleted file mode 100644
index 4fc0daf..0000000
--- a/src/undead/doformat.d
+++ /dev/null
@@ -1,1620 +0,0 @@
-// Written in the D programming language.
-
-/**
- Copyright: Copyright Digital Mars 2000-2013.
-
- License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
-
- Authors: $(HTTP walterbright.com, Walter Bright), $(HTTP erdani.com,
- Andrei Alexandrescu), and Kenji Hara
-
- Source: $(PHOBOSSRC std/_format.d)
- */
-module undead.doformat;
-
-//debug=format; // uncomment to turn on debugging printf's
-
-import core.vararg;
-import std.exception;
-import std.meta;
-import std.range.primitives;
-import std.traits;
-import std.format;
-
-version(CRuntime_DigitalMars)
-{
- version = DigitalMarsC;
-}
-
-version (DigitalMarsC)
-{
- // This is DMC's internal floating point formatting function
- extern (C)
- {
- extern shared char* function(int c, int flags, int precision,
- in real* pdval,
- char* buf, size_t* psl, int width) __pfloatfmt;
- }
-}
-
-/**********************************************************************
- * Signals a mismatch between a format and its corresponding argument.
- */
-class FormatException : Exception
-{
- @safe pure nothrow
- this()
- {
- super("format error");
- }
-
- @safe pure nothrow
- this(string msg, string fn = __FILE__, size_t ln = __LINE__, Throwable next = null)
- {
- super(msg, fn, ln, next);
- }
-}
-
-
-// Legacy implementation
-
-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',
- Timmutable = '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)
-{
- // BUG: should fix this in static this() to avoid double checked locking bug
- __gshared TypeInfo[Mangle] dic;
- if (!dic.length)
- {
- dic = [
- Mangle.Tvoid : typeid(void),
- Mangle.Tbool : typeid(bool),
- Mangle.Tbyte : typeid(byte),
- Mangle.Tubyte : typeid(ubyte),
- Mangle.Tshort : typeid(short),
- Mangle.Tushort : typeid(ushort),
- Mangle.Tint : typeid(int),
- Mangle.Tuint : typeid(uint),
- Mangle.Tlong : typeid(long),
- Mangle.Tulong : typeid(ulong),
- Mangle.Tfloat : typeid(float),
- Mangle.Tdouble : typeid(double),
- Mangle.Treal : typeid(real),
- Mangle.Tifloat : typeid(ifloat),
- Mangle.Tidouble : typeid(idouble),
- Mangle.Tireal : typeid(ireal),
- Mangle.Tcfloat : typeid(cfloat),
- Mangle.Tcdouble : typeid(cdouble),
- Mangle.Tcreal : typeid(creal),
- Mangle.Tchar : typeid(char),
- Mangle.Twchar : typeid(wchar),
- Mangle.Tdchar : typeid(dchar)
- ];
- }
- auto p = m in dic;
- return p ? *p : null;
-}
-
-// This stuff has been removed from the docs and is planned for deprecation.
-/*
- * 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 $(D char[]), $(D wchar[]), or $(D 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
- * $(D FormatException) 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 $(D TypeInfo)s, one for each argument to be formatted.
- * argptr = Points to variadic argument list.
- *
- * Throws:
- * Mismatched arguments and formats result in a $(D FormatException) being thrown.
- *
- * Format_String:
- * <a name="format-string">$(I Format strings)</a>
- * consist of characters interspersed with
- * $(I format specifications). Characters are simply copied
- * to the output (such as putc) after any necessary conversion
- * to the corresponding UTF-8 sequence.
- *
- * A $(I format specification) starts with a '%' character,
- * and has the following grammar:
-
-$(CONSOLE
-$(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')
-)
- $(DL
- $(DT $(I Flags))
- $(DL
- $(DT $(B '-'))
- $(DD
- Left justify the result in the field.
- It overrides any $(B 0) flag.)
-
- $(DT $(B '+'))
- $(DD Prefix positive numbers in a signed conversion with a $(B +).
- It overrides any $(I space) flag.)
-
- $(DT $(B '#'))
- $(DD Use alternative formatting:
- $(DL
- $(DT For $(B 'o'):)
- $(DD Add to precision as necessary so that the first digit
- of the octal formatting is a '0', even if both the argument
- and the $(I Precision) are zero.)
- $(DT For $(B 'x') ($(B 'X')):)
- $(DD If non-zero, prefix result with $(B 0x) ($(B 0X)).)
- $(DT For floating point formatting:)
- $(DD Always insert the decimal point.)
- $(DT For $(B 'g') ($(B 'G')):)
- $(DD Do not elide trailing zeros.)
- ))
-
- $(DT $(B '0'))
- $(DD For integer and floating point formatting when not nan or
- infinity, use leading zeros
- to pad rather than spaces.
- Ignore if there's a $(I Precision).)
-
- $(DT $(B ' '))
- $(DD Prefix positive numbers in a signed conversion with a space.)
- )
-
- $(DT $(I Width))
- $(DD
- Specifies the minimum field width.
- If the width is a $(B *), the next argument, which must be
- of type $(B int), is taken as the width.
- If the width is negative, it is as if the $(B -) was given
- as a $(I Flags) character.)
-
- $(DT $(I Precision))
- $(DD Gives the precision for numeric conversions.
- If the precision is a $(B *), the next argument, which must be
- of type $(B int), is taken as the precision. If it is negative,
- it is as if there was no $(I Precision).)
-
- $(DT $(I FormatChar))
- $(DD
- $(DL
- $(DT $(B 's'))
- $(DD The corresponding argument is formatted in a manner consistent
- with its type:
- $(DL
- $(DT $(B bool))
- $(DD The result is <tt>'true'</tt> or <tt>'false'</tt>.)
- $(DT integral types)
- $(DD The $(B %d) format is used.)
- $(DT floating point types)
- $(DD The $(B %g) format is used.)
- $(DT string types)
- $(DD The result is the string converted to UTF-8.)
- A $(I Precision) specifies the maximum number of characters
- to use in the result.
- $(DT classes derived from $(B Object))
- $(DD The result is the string returned from the class instance's
- $(B .toString()) method.
- A $(I Precision) specifies the maximum number of characters
- to use in the result.)
- $(DT non-string static and dynamic arrays)
- $(DD The result is [s<sub>0</sub>, s<sub>1</sub>, ...]
- where s<sub>k</sub> is the kth element
- formatted with the default format.)
- ))
-
- $(DT $(B 'b','d','o','x','X'))
- $(DD The corresponding argument must be an integral type
- and is formatted as an integer. If the argument is a signed type
- and the $(I FormatChar) is $(B d) it is converted to
- a signed string of characters, otherwise it is treated as
- unsigned. An argument of type $(B bool) is formatted as '1'
- or '0'. The base used is binary for $(B b), octal for $(B o),
- decimal
- for $(B d), and hexadecimal for $(B x) or $(B X).
- $(B x) formats using lower case letters, $(B X) uppercase.
- If there are fewer resulting digits than the $(I Precision),
- leading zeros are used as necessary.
- If the $(I Precision) is 0 and the number is 0, no digits
- result.)
-
- $(DT $(B 'e','E'))
- $(DD A floating point number is formatted as one digit before
- the decimal point, $(I Precision) digits after, the $(I FormatChar),
- &plusmn;, followed by at least a two digit exponent: $(I d.dddddd)e$(I &plusmn;dd).
- If there is no $(I Precision), six
- digits are generated after the decimal point.
- If the $(I Precision) is 0, no decimal point is generated.)
-
- $(DT $(B 'f','F'))
- $(DD A floating point number is formatted in decimal notation.
- The $(I Precision) specifies the number of digits generated
- after the decimal point. It defaults to six. At least one digit
- is generated before the decimal point. If the $(I Precision)
- is zero, no decimal point is generated.)
-
- $(DT $(B 'g','G'))
- $(DD A floating point number is formatted in either $(B e) or
- $(B f) format for $(B g); $(B E) or $(B F) format for
- $(B G).
- The $(B f) format is used if the exponent for an $(B e) format
- is greater than -5 and less than the $(I Precision).
- The $(I Precision) specifies the number of significant
- digits, and defaults to six.
- Trailing zeros are elided after the decimal point, if the fractional
- part is zero then no decimal point is generated.)
-
- $(DT $(B 'a','A'))
- $(DD A floating point number is formatted in hexadecimal
- exponential notation 0x$(I h.hhhhhh)p$(I &plusmn;d).
- There is one hexadecimal digit before the decimal point, and as
- many after as specified by the $(I Precision).
- If the $(I Precision) is zero, no decimal point is generated.
- If there is no $(I Precision), as many hexadecimal digits as
- necessary to exactly represent the mantissa are generated.
- The exponent is written in as few digits as possible,
- but at least one, is in decimal, and represents a power of 2 as in
- $(I h.hhhhhh)*2<sup>$(I &plusmn;d)</sup>.
- The exponent for zero is zero.
- The hexadecimal digits, x and p are in upper case if the
- $(I FormatChar) is upper case.)
- )
-
- 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 core.stdc.stdio;
-import std.format;
-
-void myPrint(...)
-{
- void putc(dchar c)
- {
- fputc(c, stdout);
- }
-
- std.format.doFormat(&putc, _arguments, _argptr);
-}
-
-void main()
-{
- int x = 27;
-
- // prints 'The answer is 27:6'
- myPrint("The answer is %s:", x, 6);
-}
-------------------------
- */
-void doFormat()(scope void delegate(dchar) putc, TypeInfo[] arguments, va_list ap)
-{
- import std.utf : toUCSindex, isValidDchar, UTFException, toUTF8;
- import core.stdc.string : strlen;
- import core.stdc.stdlib : alloca, malloc, realloc, free;
- import core.stdc.stdio : snprintf;
-
- size_t bufLength = 1024;
- void* argBuffer = malloc(bufLength);
- scope(exit) free(argBuffer);
-
- size_t bufUsed = 0;
- foreach (ti; arguments)
- {
- // Ensure the required alignment
- bufUsed += ti.talign - 1;
- bufUsed -= (cast(size_t)argBuffer + bufUsed) & (ti.talign - 1);
- auto pos = bufUsed;
- // Align to next word boundary
- bufUsed += ti.tsize + size_t.sizeof - 1;
- bufUsed -= (cast(size_t)argBuffer + bufUsed) & (size_t.sizeof - 1);
- // Resize buffer if necessary
- while (bufUsed > bufLength)
- {
- bufLength *= 2;
- argBuffer = realloc(argBuffer, bufLength);
- }
- // Copy argument into buffer
- va_arg(ap, ti, argBuffer + pos);
- }
-
- auto argptr = argBuffer;
- void* skipArg(TypeInfo ti)
- {
- // Ensure the required alignment
- argptr += ti.talign - 1;
- argptr -= cast(size_t)argptr & (ti.talign - 1);
- auto p = argptr;
- // Align to next word boundary
- argptr += ti.tsize + size_t.sizeof - 1;
- argptr -= cast(size_t)argptr & (size_t.sizeof - 1);
- return p;
- }
- auto getArg(T)()
- {
- return *cast(T*)skipArg(typeid(T));
- }
-
- 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)
- {
- for (;;)
- {
- if (typeid(valti).name.length == 18 &&
- typeid(valti).name[9..18] == "Invariant")
- valti = (cast(TypeInfo_Invariant)valti).base;
- else if (typeid(valti).name.length == 14 &&
- typeid(valti).name[9..14] == "Const")
- valti = (cast(TypeInfo_Const)valti).base;
- 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
- const(char)* prefix = "";
- string s;
-
- void putstr(const char[] s)
- {
- //printf("putstr: s = %.*s, flags = x%x\n", s.length, s.ptr, flags);
- ptrdiff_t padding = field_width -
- (strlen(prefix) + toUCSindex(s, s.length));
- ptrdiff_t prepad = 0;
- ptrdiff_t postpad = 0;
- 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);
-
- 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 FormatException("incompatible format character for floating point type");
- }
- version (DigitalMarsC)
- {
- uint 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
- {
- ptrdiff_t 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] = 'L';
- format[i + 4] = fc;
- format[i + 5] = 0;
- if (!(flags & FLprecision))
- precision = -1;
- while (1)
- {
- sl = fbuf.length;
- int n;
- version (CRuntime_Microsoft)
- {
- import std.math : isNaN, isInfinity;
- if (isNaN(v)) // snprintf writes 1.#QNAN
- n = snprintf(fbuf.ptr, sl, "nan");
- else if (isInfinity(v)) // snprintf writes 1.#INF
- n = snprintf(fbuf.ptr, sl, v < 0 ? "-inf" : "inf");
- else
- n = snprintf(fbuf.ptr, sl, format.ptr, field_width,
- precision, cast(double)v);
- }
- else
- 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)typeid(ti).name[9];
- if (typeid(ti).name.length == 20 &&
- typeid(ti).name[9..20] == "StaticArray")
- m = cast(Mangle)'G';
- return m;
- }
-
- /* p = pointer to the first element in the array
- * len = number of elements in the array
- * valti = type of the elements
- */
- 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;
- //printf("\n%.*s\n", typeid(valti).name.length, typeid(valti).name.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 (ref fakevalue; vaa)
- {
- if (comma) putc(',');
- comma = true;
- void *pkey = &fakevalue;
- version (D_LP64)
- pkey -= (long.sizeof + 15) & ~(15);
- else
- pkey -= (long.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
-
- // the key comes before the value
- auto keysize = keyti.tsize;
- version (D_LP64)
- auto keysizet = (keysize + 15) & ~(15);
- else
- auto keysizet = (keysize + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
-
- void* pvalue = pkey + keysizet;
-
- //doFormat(putc, (&keyti)[0..1], pkey);
- m = getMan(keyti);
- argptr = pkey;
-
- ti = keyti;
- formatArg('s');
-
- putc(':');
- //doFormat(putc, (&valti)[0..1], pvalue);
- m = getMan(valti);
- argptr = pvalue;
-
- ti = valti;
- formatArg('s');
- }
- m = mSave;
- ti = tiSave;
- argptr = argptrSave;
- putc(']');
- }
-
- //printf("formatArg(fc = '%c', m = '%c')\n", fc, m);
- int mi;
- switch (m)
- {
- case Mangle.Tbool:
- vbit = getArg!(bool)();
- if (fc != 's')
- { vnumber = vbit;
- goto Lnumber;
- }
- putstr(vbit ? "true" : "false");
- return;
-
- case Mangle.Tchar:
- vchar = getArg!(char)();
- if (fc != 's')
- { vnumber = vchar;
- goto Lnumber;
- }
- L2:
- putstr((&vchar)[0 .. 1]);
- return;
-
- case Mangle.Twchar:
- vdchar = getArg!(wchar)();
- goto L1;
-
- case Mangle.Tdchar:
- vdchar = getArg!(dchar)();
- 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");
- char[4] vbuf;
- putstr(toUTF8(vbuf, vdchar));
- }
- return;
-
- case Mangle.Tbyte:
- signed = 1;
- vnumber = getArg!(byte)();
- goto Lnumber;
-
- case Mangle.Tubyte:
- vnumber = getArg!(ubyte)();
- goto Lnumber;
-
- case Mangle.Tshort:
- signed = 1;
- vnumber = getArg!(short)();
- goto Lnumber;
-
- case Mangle.Tushort:
- vnumber = getArg!(ushort)();
- goto Lnumber;
-
- case Mangle.Tint:
- signed = 1;
- vnumber = getArg!(int)();
- goto Lnumber;
-
- case Mangle.Tuint:
- Luint:
- vnumber = getArg!(uint)();
- goto Lnumber;
-
- case Mangle.Tlong:
- signed = 1;
- vnumber = cast(ulong)getArg!(long)();
- goto Lnumber;
-
- case Mangle.Tulong:
- Lulong:
- vnumber = getArg!(ulong)();
- goto Lnumber;
-
- case Mangle.Tclass:
- vobject = getArg!(Object)();
- if (vobject is null)
- s = "null";
- else
- s = vobject.toString();
- goto Lputstr;
-
- case Mangle.Tpointer:
- vnumber = cast(ulong)getArg!(void*)();
- if (fc != 'x') 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 = getArg!(float)();
- goto Lreal;
-
- case Mangle.Tdouble:
- case Mangle.Tidouble:
- if (fc == 'x' || fc == 'X')
- goto Lulong;
- vreal = getArg!(double)();
- goto Lreal;
-
- case Mangle.Treal:
- case Mangle.Tireal:
- vreal = getArg!(real)();
- goto Lreal;
-
- case Mangle.Tcfloat:
- vcreal = getArg!(cfloat)();
- goto Lcomplex;
-
- case Mangle.Tcdouble:
- vcreal = getArg!(cdouble)();
- goto Lcomplex;
-
- case Mangle.Tcreal:
- vcreal = getArg!(creal)();
- goto Lcomplex;
-
- case Mangle.Tsarray:
- putArray(argptr, (cast(TypeInfo_StaticArray)ti).len, (cast(TypeInfo_StaticArray)ti).next);
- return;
-
- case Mangle.Tarray:
- mi = 10;
- if (typeid(ti).name.length == 14 &&
- typeid(ti).name[9..14] == "Array")
- { // array of non-primitive types
- TypeInfo tn = (cast(TypeInfo_Array)ti).next;
- tn = skipCI(tn);
- switch (cast(Mangle)typeid(tn).name[9])
- {
- case Mangle.Tchar: goto LarrayChar;
- case Mangle.Twchar: goto LarrayWchar;
- case Mangle.Tdchar: goto LarrayDchar;
- default:
- break;
- }
- void[] va = getArg!(void[])();
- putArray(va.ptr, va.length, tn);
- return;
- }
- if (typeid(ti).name.length == 25 &&
- typeid(ti).name[9..25] == "AssociativeArray")
- { // associative array
- ubyte[long] vaa = getArg!(ubyte[long])();
- putAArray(vaa,
- (cast(TypeInfo_AssociativeArray)ti).next,
- (cast(TypeInfo_AssociativeArray)ti).key);
- return;
- }
-
- while (1)
- {
- m2 = cast(Mangle)typeid(ti).name[mi];
- switch (m2)
- {
- case Mangle.Tchar:
- LarrayChar:
- s = getArg!(string)();
- goto Lputstr;
-
- case Mangle.Twchar:
- LarrayWchar:
- wchar[] sw = getArg!(wchar[])();
- s = toUTF8(sw);
- goto Lputstr;
-
- case Mangle.Tdchar:
- LarrayDchar:
- s = toUTF8(getArg!(dstring)());
- Lputstr:
- if (fc != 's')
- throw new FormatException("string");
- if (flags & FLprecision && precision < s.length)
- s = s[0 .. precision];
- putstr(s);
- break;
-
- case Mangle.Tconst:
- case Mangle.Timmutable:
- mi++;
- continue;
-
- default:
- TypeInfo ti2 = primitiveTypeInfo(m2);
- if (!ti2)
- goto Lerror;
- void[] va = getArg!(void[])();
- putArray(va.ptr, va.length, ti2);
- }
- return;
- }
- assert(0);
-
- case Mangle.Ttypedef:
- ti = (cast(TypeInfo_Typedef)ti).base;
- m = cast(Mangle)typeid(ti).name[9];
- formatArg(fc);
- return;
-
- case Mangle.Tenum:
- ti = (cast(TypeInfo_Enum)ti).base;
- m = cast(Mangle)typeid(ti).name[9];
- formatArg(fc);
- return;
-
- case Mangle.Tstruct:
- { TypeInfo_Struct tis = cast(TypeInfo_Struct)ti;
- if (tis.xtoString is null)
- throw new FormatException("Can't convert " ~ tis.toString()
- ~ " to string: \"string toString()\" not defined");
- s = tis.xtoString(skipArg(tis));
- 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;
- }
- }
-
- {
- ptrdiff_t 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)
- {
- ptrdiff_t 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);
- if (vcreal.im >= 0)
- {
- putc('+');
- }
- putreal(vcreal.im);
- putc('i');
- return;
-
- Lerror:
- throw new FormatException("formatArg");
- }
-
- for (int j = 0; j < arguments.length; )
- {
- ti = arguments[j++];
- //printf("arg[%d]: '%.*s' %d\n", j, typeid(ti).name.length, typeid(ti).name.ptr, typeid(ti).name.length);
- //ti.print();
-
- flags = 0;
- precision = 0;
- field_width = 0;
-
- ti = skipCI(ti);
- int mi = 9;
- do
- {
- if (typeid(ti).name.length <= mi)
- goto Lerror;
- m = cast(Mangle)typeid(ti).name[mi++];
- } while (m == Mangle.Tconst || m == Mangle.Timmutable);
-
- if (m == Mangle.Tarray)
- {
- if (typeid(ti).name.length == 14 &&
- typeid(ti).name[9..14] == "Array")
- {
- TypeInfo tn = (cast(TypeInfo_Array)ti).next;
- tn = skipCI(tn);
- switch (cast(Mangle)typeid(tn).name[9])
- {
- case Mangle.Tchar:
- case Mangle.Twchar:
- case Mangle.Tdchar:
- ti = tn;
- mi = 9;
- break;
- default:
- break;
- }
- }
- L1:
- Mangle m2 = cast(Mangle)typeid(ti).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 = getArg!(string)();
- break;
-
- case Mangle.Twchar:
- wfmt = getArg!(wstring)();
- fmt = toUTF8(wfmt);
- break;
-
- case Mangle.Tdchar:
- dfmt = getArg!(dstring)();
- fmt = toUTF8(dfmt);
- break;
-
- case Mangle.Tconst:
- case Mangle.Timmutable:
- 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 FormatException("invalid specifier");
- return fmt[i++];
- }
-
- int getFmtInt()
- { int n;
-
- while (1)
- {
- n = n * 10 + (c - '0');
- if (n < 0) // overflow
- throw new FormatException("int overflow");
- c = getFmtChar();
- if (c < '0' || c > '9')
- break;
- }
- return n;
- }
-
- int getFmtStar()
- { Mangle m;
- TypeInfo ti;
-
- if (j == arguments.length)
- throw new FormatException("too few arguments");
- ti = arguments[j++];
- m = cast(Mangle)typeid(ti).name[9];
- if (m != Mangle.Tint)
- throw new FormatException("int argument expected");
- return getArg!(int)();
- }
-
- if (c != '%')
- {
- if (c > 0x7F) // if UTF sequence
- {
- i--; // back up and decode UTF sequence
- import std.utf : decode;
- c = 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;
- break;
-
- 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)typeid(ti).name[mi++];
- } while (m == Mangle.Tconst || m == Mangle.Timmutable);
-
- 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 FormatException();
-}
-
-
-private bool needToSwapEndianess(Char)(ref FormatSpec!Char f)
-{
- import std.system : endian, Endian;
-
- return endian == Endian.littleEndian && f.flPlus
- || endian == Endian.bigEndian && f.flDash;
-}
-
-/* ======================== Unit Tests ====================================== */
-
-unittest
-{
- import std.conv : octal;
-
- int i;
- string s;
-
- debug(format) printf("std.format.format.unittest\n");
-
- s = format("hello world! %s %s %s%s%s", true, 57, 1_000_000_000, 'x', " foo");
- assert(s == "hello world! true 57 1000000000x foo");
-
- s = format("%s %A %s", 1.67, -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 version (OSX)
- // assert(s == "1.67 -0XA.3D70A3D70A3D8P-3 nan", s);
- //else
- version (MinGW)
- assert(s == "1.67 -0XA.3D70A3D70A3D8P-3 nan", s);
- else version (CRuntime_Microsoft)
- assert(s == "1.67 -0X1.47AE14P+0 nan"
- || s == "1.67 -0X1.47AE147AE147BP+0 nan", s); // MSVCRT 14+ (VS 2015)
- else
- assert(s == "1.67 -0X1.47AE147AE147BP+0 nan", s);
-
- s = format("%x %X", 0x1234AF, 0xAFAFAFAF);
- assert(s == "1234af AFAFAFAF");
-
- s = format("%b %o", 0x1234AF, 0xAFAFAFAF);
- assert(s == "100100011010010101111 25753727657");
-
- s = format("%d %s", 0x1234AF, 0xAFAFAFAF);
- assert(s == "1193135 2947526575");
-
- //version(X86_64)
- //{
- // pragma(msg, "several format tests disabled on x86_64 due to bug 5625");
- //}
- //else
- //{
- s = format("%s", 1.2 + 3.4i);
- assert(s == "1.2+3.4i", s);
-
- //s = format("%x %X", 1.32, 6.78f);
- //assert(s == "3ff51eb851eb851f 40D8F5C3");
-
- //}
-
- s = format("%#06.*f",2,12.345);
- assert(s == "012.35");
-
- s = format("%#0*.*f",6,2,12.345);
- assert(s == "012.35");
-
- s = format("%7.4g:", 12.678);
- assert(s == " 12.68:");
-
- s = format("%7.4g:", 12.678L);
- assert(s == " 12.68:");
-
- s = format("%04f|%05d|%#05x|%#5x",-4.0,-10,1,1);
- assert(s == "-4.000000|-0010|0x001| 0x1");
-
- i = -10;
- s = 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 = 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 = 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 = 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 = format("%d|%3d|%03d|%1d|%01.4f",i,i,i,i,cast(double) i);
- assert(s == "10| 10|010|10|10.0000");
-
- s = format("%.0d", 0);
- assert(s == "");
-
- s = format("%.g", .34);
- assert(s == "0.3");
-
- s = format("%.0g", .34);
- assert(s == "0.3");
-
- s = format("%.2g", .34);
- assert(s == "0.34");
-
- s = format("%0.0008f", 1e-08);
- assert(s == "0.00000001");
-
- s = format("%0.0008f", 1e-05);
- assert(s == "0.00001000");
-
- s = "helloworld";
- string r;
- r = format("%.2s", s[0..5]);
- assert(r == "he");
- r = format("%.20s", s[0..5]);
- assert(r == "hello");
- r = format("%8s", s[0..5]);
- assert(r == " hello");
-
- byte[] arrbyte = new byte[4];
- arrbyte[0] = 100;
- arrbyte[1] = -99;
- arrbyte[3] = 0;
- r = format("%s", arrbyte);
- assert(r == "[100, -99, 0, 0]");
-
- ubyte[] arrubyte = new ubyte[4];
- arrubyte[0] = 100;
- arrubyte[1] = 200;
- arrubyte[3] = 0;
- r = format("%s", arrubyte);
- assert(r == "[100, 200, 0, 0]");
-
- short[] arrshort = new short[4];
- arrshort[0] = 100;
- arrshort[1] = -999;
- arrshort[3] = 0;
- r = 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 = format("%s", arrushort);
- assert(r == "[100, 20000, 0, 0]");
-
- int[] arrint = new int[4];
- arrint[0] = 100;
- arrint[1] = -999;
- arrint[3] = 0;
- r = format("%s", arrint);
- assert(r == "[100, -999, 0, 0]");
-
- long[] arrlong = new long[4];
- arrlong[0] = 100;
- arrlong[1] = -999;
- arrlong[3] = 0;
- r = format("%s", arrlong);
- assert(r == "[100, -999, 0, 0]");
-
- ulong[] arrulong = new ulong[4];
- arrulong[0] = 100;
- arrulong[1] = 999;
- arrulong[3] = 0;
- r = format("%s", arrulong);
- assert(r == "[100, 999, 0, 0]");
-
- string[] arr2 = new string[4];
- arr2[0] = "hello";
- arr2[1] = "world";
- arr2[3] = "foo";
- r = format("%s", arr2);
- assert(r == `["hello", "world", "", "foo"]`);
-
- r = format("%.8d", 7);
- assert(r == "00000007");
- r = format("%.8x", 10);
- assert(r == "0000000a");
-
- r = format("%-3d", 7);
- assert(r == "7 ");
-
- r = format("%*d", -3, 7);
- assert(r == "7 ");
-
- r = format("%.*d", -3, 7);
- assert(r == "7");
-
- r = format("abc"c);
- assert(r == "abc");
-
- //format() returns the same type as inputted.
- wstring wr;
- wr = format("def"w);
- assert(wr == "def"w);
-
- dstring dr;
- dr = format("ghi"d);
- assert(dr == "ghi"d);
-
- void* p = cast(void*)0xDEADBEEF;
- r = format("%s", p);
- assert(r == "DEADBEEF");
-
- r = format("%#x", 0xabcd);
- assert(r == "0xabcd");
- r = format("%#X", 0xABCD);
- assert(r == "0XABCD");
-
- r = format("%#o", octal!12345);
- assert(r == "012345");
- r = format("%o", 9);
- assert(r == "11");
- r = format("%#o", 0); // issue 15663
- assert(r == "0");
-
- r = format("%+d", 123);
- assert(r == "+123");
- r = format("%+d", -123);
- assert(r == "-123");
- r = format("% d", 123);
- assert(r == " 123");
- r = format("% d", -123);
- assert(r == "-123");
-
- r = format("%%");
- assert(r == "%");
-
- r = format("%d", true);
- assert(r == "1");
- r = format("%d", false);
- assert(r == "0");
-
- r = format("%d", 'a');
- assert(r == "97");
- wchar wc = 'a';
- r = format("%d", wc);
- assert(r == "97");
- dchar dc = 'a';
- r = format("%d", dc);
- assert(r == "97");
-
- byte b = byte.max;
- r = format("%x", b);
- assert(r == "7f");
- r = format("%x", ++b);
- assert(r == "80");
- r = format("%x", ++b);
- assert(r == "81");
-
- short sh = short.max;
- r = format("%x", sh);
- assert(r == "7fff");
- r = format("%x", ++sh);
- assert(r == "8000");
- r = format("%x", ++sh);
- assert(r == "8001");
-
- i = int.max;
- r = format("%x", i);
- assert(r == "7fffffff");
- r = format("%x", ++i);
- assert(r == "80000000");
- r = format("%x", ++i);
- assert(r == "80000001");
-
- r = format("%x", 10);
- assert(r == "a");
- r = format("%X", 10);
- assert(r == "A");
- r = format("%x", 15);
- assert(r == "f");
- r = format("%X", 15);
- assert(r == "F");
-
- Object c = null;
- r = format("%s", c);
- assert(r == "null");
-
- enum TestEnum
- {
- Value1, Value2
- }
- r = format("%s", TestEnum.Value2);
- assert(r == "Value2");
-
- immutable(char[5])[int] aa = ([3:"hello", 4:"betty"]);
- r = format("%s", aa.values);
- assert(r == `["hello", "betty"]` || r == `["betty", "hello"]`);
- r = format("%s", aa);
- assert(r == `[3:"hello", 4:"betty"]` || r == `[4:"betty", 3:"hello"]`);
-
- static const dchar[] ds = ['a','b'];
- for (int j = 0; j < ds.length; ++j)
- {
- r = format(" %d", ds[j]);
- if (j == 0)
- assert(r == " 97");
- else
- assert(r == " 98");
- }
-
- r = format(">%14d<, %s", 15, [1,2,3]);
- assert(r == "> 15<, [1, 2, 3]");
-
- assert(format("%8s", "bar") == " bar");
- assert(format("%8s", "b\u00e9ll\u00f4") == " b\u00e9ll\u00f4");
-}