mirror of
https://github.com/dlang/phobos.git
synced 2025-04-29 06:30:28 +03:00
801 lines
16 KiB
D
801 lines
16 KiB
D
/*
|
|
* Copyright (C) 2004 by Digital Mars, www.digitalmars.com
|
|
* Written by Walter Bright
|
|
*
|
|
* This software is provided 'as-is', without any express or implied
|
|
* warranty. In no event will the authors be held liable for any damages
|
|
* arising from the use of this software.
|
|
*
|
|
* Permission is granted to anyone to use this software for any purpose,
|
|
* including commercial applications, and to alter it and redistribute it
|
|
* freely, subject to the following restrictions:
|
|
*
|
|
* o The origin of this software must not be misrepresented; you must not
|
|
* claim that you wrote the original software. If you use this software
|
|
* in a product, an acknowledgment in the product documentation would be
|
|
* appreciated but is not required.
|
|
* o Altered source versions must be plainly marked as such, and must not
|
|
* be misrepresented as being the original software.
|
|
* o This notice may not be removed or altered from any source
|
|
* distribution.
|
|
*/
|
|
|
|
module std.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.string;
|
|
|
|
version (Windows)
|
|
{
|
|
version (DigitalMars)
|
|
{
|
|
version = DigitalMarsC;
|
|
}
|
|
}
|
|
|
|
version (DigitalMarsC)
|
|
{
|
|
// This is DMC's internal floating point formatting function
|
|
extern (C) 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, ...);
|
|
}
|
|
|
|
enum Mangle : char
|
|
{
|
|
Tvoid = 'v',
|
|
Tbit = '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',
|
|
}
|
|
|
|
|
|
/************************************
|
|
* Convert arguments to tchar's according to format strings and feed to putc().
|
|
* This is the core workhorse routine for all the various formatters.
|
|
*/
|
|
|
|
void doFormat(void delegate(dchar) putc, TypeInfo[] arguments, va_list argptr)
|
|
{ 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,
|
|
}
|
|
|
|
|
|
void formatArg(char fc)
|
|
{
|
|
bit 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 = "";
|
|
char[] s;
|
|
|
|
void putstr(char[] s)
|
|
{
|
|
//printf("flags = x%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);
|
|
|
|
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] = 'L';
|
|
format[i + 4] = fc;
|
|
format[i + 5] = 0;
|
|
if (!(flags & FLprecision))
|
|
precision = -1;
|
|
while (1)
|
|
{ int n;
|
|
|
|
sl = fbuf.length;
|
|
n = snprintf(fbuf, sl, format, 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;
|
|
}
|
|
|
|
|
|
//printf("formatArg(fc = '%c', m = '%c')\n", fc, m);
|
|
switch (m)
|
|
{
|
|
case Mangle.Tbit:
|
|
vbit = va_arg!(bit)(argptr);
|
|
if (fc != 's')
|
|
{ vnumber = vbit;
|
|
goto Lnumber;
|
|
}
|
|
putstr(vbit ? "true" : "false");
|
|
return;
|
|
|
|
|
|
case Mangle.Tchar:
|
|
if (fc != 's')
|
|
goto Lerror;
|
|
vchar = va_arg!(char)(argptr);
|
|
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')
|
|
goto Lerror;
|
|
if (vdchar <= 0x7F)
|
|
{ vchar = cast(char)vdchar;
|
|
goto L2;
|
|
}
|
|
else
|
|
{ if (!isValidDchar(vdchar))
|
|
throw new UtfError("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 = 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);
|
|
s = vobject.toString();
|
|
goto Lputstr;
|
|
|
|
case Mangle.Tpointer:
|
|
vnumber = cast(ulong)va_arg!(void*)(argptr);
|
|
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.Tarray:
|
|
m2 = cast(Mangle)ti.classinfo.name[10];
|
|
switch (m2)
|
|
{
|
|
case Mangle.Tchar:
|
|
s = va_arg!(char[])(argptr);
|
|
goto Lputstr;
|
|
|
|
case Mangle.Twchar:
|
|
wchar[] sw = va_arg!(wchar[])(argptr);
|
|
s = toUTF8(sw);
|
|
goto Lputstr;
|
|
|
|
case Mangle.Tdchar:
|
|
dchar[] sd = va_arg!(dchar[])(argptr);
|
|
s = toUTF8(sd);
|
|
Lputstr:
|
|
if (flags & FLprecision && precision < s.length)
|
|
s = s[0 .. precision];
|
|
putstr(s);
|
|
break;
|
|
|
|
default:
|
|
goto Lerror;
|
|
}
|
|
return;
|
|
|
|
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 (flags & FLprecision && fc != 'p')
|
|
flags &= ~FL0pad;
|
|
|
|
if (vnumber < 10)
|
|
{
|
|
if (vnumber == 0 && precision == 0 && flags & FLprecision &&
|
|
!(fc == 'o' && flags & FLhash))
|
|
{
|
|
putstr(null);
|
|
}
|
|
else
|
|
{ vchar = '0' + vnumber;
|
|
goto L2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int n = tmpbuf.length;
|
|
char c;
|
|
int hexoffset = uc ? ('A' - ('9' + 1)) : ('a' - ('9' + 1));
|
|
|
|
while (vnumber)
|
|
{
|
|
c = (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");
|
|
}
|
|
|
|
|
|
for (j = 0; j < arguments.length; )
|
|
{ ti = arguments[j++];
|
|
//printf("test1: '%.*s' %d\n", ti.classinfo.name, ti.classinfo.name.length);
|
|
//ti.print();
|
|
if (ti.classinfo.name.length < 10)
|
|
goto Lerror;
|
|
m = cast(Mangle)ti.classinfo.name[9];
|
|
|
|
if (m == Mangle.Tarray)
|
|
{
|
|
Mangle m2 = cast(Mangle)ti.classinfo.name[10];
|
|
char[] fmt; // format string
|
|
wchar[] wfmt;
|
|
dchar[] 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;
|
|
|
|
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++];
|
|
m = cast(Mangle)ti.classinfo.name[9];
|
|
|
|
if (c > 0x7F) // if UTF sequence
|
|
goto Lerror; // format specifiers can't be UTF
|
|
formatArg(cast(char)c);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
field_width = 0;
|
|
flags = 0;
|
|
precision = 0;
|
|
formatArg('s');
|
|
}
|
|
}
|
|
return;
|
|
|
|
Lerror:
|
|
throw new FormatError();
|
|
}
|
|
|
|
|
|
class FormatError : Error
|
|
{
|
|
private:
|
|
|
|
this()
|
|
{
|
|
super("std.format");
|
|
}
|
|
|
|
this(char[] msg)
|
|
{
|
|
super("std.format " ~ msg);
|
|
}
|
|
}
|
|
|
|
/* ======================== Unit Tests ====================================== */
|
|
|
|
unittest
|
|
{
|
|
int i;
|
|
char[] 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);
|
|
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("%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";
|
|
char[] 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");
|
|
}
|
|
|