Make pointer to string conversion safer
This commit is contained in:
parent
f334e6a1a0
commit
3a24e9e462
@ -14,10 +14,12 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.format;
|
module tanya.format;
|
||||||
|
|
||||||
import core.stdc.stdarg;
|
import tanya.container.string;
|
||||||
|
import tanya.encoding.ascii;
|
||||||
public import tanya.format.conv;
|
public import tanya.format.conv;
|
||||||
import tanya.memory.op;
|
import tanya.memory.op;
|
||||||
import tanya.meta.metafunction;
|
import tanya.meta.metafunction;
|
||||||
|
import tanya.meta.trait;
|
||||||
import tanya.range.array;
|
import tanya.range.array;
|
||||||
|
|
||||||
private enum special = 0x7000;
|
private enum special = 0x7000;
|
||||||
@ -106,8 +108,6 @@ private static const double[13] negativeTopError = [
|
|||||||
|
|
||||||
private enum ulong tenTo19th = 1000000000000000000UL;
|
private enum ulong tenTo19th = 1000000000000000000UL;
|
||||||
|
|
||||||
package static const string hex = "0123456789abcdefxp";
|
|
||||||
|
|
||||||
private void ddmultlo(A, B, C, D, E, F)(ref A oh,
|
private void ddmultlo(A, B, C, D, E, F)(ref A oh,
|
||||||
ref B ol,
|
ref B ol,
|
||||||
ref C xh,
|
ref C xh,
|
||||||
@ -135,7 +135,7 @@ private void ddrenorm(T, U)(ref T oh, ref U ol)
|
|||||||
private void raise2Power10(double* ohi,
|
private void raise2Power10(double* ohi,
|
||||||
double* olo,
|
double* olo,
|
||||||
double d,
|
double d,
|
||||||
int power) pure nothrow @nogc
|
int power) @nogc nothrow pure
|
||||||
{
|
{
|
||||||
double ph, pl;
|
double ph, pl;
|
||||||
if ((power >= 0) && (power <= 22))
|
if ((power >= 0) && (power <= 22))
|
||||||
@ -232,7 +232,7 @@ private int real2String(ref const(char)* start,
|
|||||||
char* out_,
|
char* out_,
|
||||||
out int decimalPos,
|
out int decimalPos,
|
||||||
double value,
|
double value,
|
||||||
uint fracDigits) pure nothrow @nogc
|
uint fracDigits) @nogc nothrow pure
|
||||||
{
|
{
|
||||||
long bits = 0;
|
long bits = 0;
|
||||||
int e, tens;
|
int e, tens;
|
||||||
@ -426,7 +426,7 @@ private int real2String(ref const(char)* start,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void leadSign(bool negative, ref char[8] sign)
|
private void leadSign(bool negative, ref char[8] sign)
|
||||||
pure nothrow @nogc
|
@nogc nothrow pure
|
||||||
{
|
{
|
||||||
sign[0] = 0;
|
sign[0] = 0;
|
||||||
if (negative)
|
if (negative)
|
||||||
@ -448,7 +448,7 @@ private void copyFp(T, U)(ref T dest, ref U src)
|
|||||||
private void ddmulthi(ref double oh,
|
private void ddmulthi(ref double oh,
|
||||||
ref double ol,
|
ref double ol,
|
||||||
ref double xh,
|
ref double xh,
|
||||||
const ref double yh) pure nothrow @nogc
|
const ref double yh) @nogc nothrow pure
|
||||||
{
|
{
|
||||||
double ahi, bhi;
|
double ahi, bhi;
|
||||||
long bt;
|
long bt;
|
||||||
@ -464,11 +464,10 @@ private void ddmulthi(ref double oh,
|
|||||||
ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo;
|
ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo;
|
||||||
}
|
}
|
||||||
|
|
||||||
private char[] vsprintf(string fmt, Args...)(return char[] buf, va_list va)
|
package(tanya) String format(string fmt, Args...)(char[] buf, Args args)
|
||||||
pure nothrow @nogc
|
|
||||||
{
|
{
|
||||||
|
String result;
|
||||||
char* bf = buf.ptr;
|
char* bf = buf.ptr;
|
||||||
int tlen;
|
|
||||||
|
|
||||||
// Ok, we have a percent, read the modifiers first.
|
// Ok, we have a percent, read the modifiers first.
|
||||||
int precision = -1;
|
int precision = -1;
|
||||||
@ -488,65 +487,24 @@ pure nothrow @nogc
|
|||||||
int decimalPos;
|
int decimalPos;
|
||||||
const(char)* sn;
|
const(char)* sn;
|
||||||
|
|
||||||
static if (fmt[0] == 's') // String
|
static if (isSomeString!(Args[0])) // String
|
||||||
{
|
{
|
||||||
// Get the string.
|
if (args[0] is null)
|
||||||
s = va_arg!(char[])(va).ptr;
|
|
||||||
if (s is null)
|
|
||||||
{
|
{
|
||||||
s = cast(char*) "null";
|
result.insertBack("null");
|
||||||
}
|
}
|
||||||
// Get the length.
|
else
|
||||||
sn = s;
|
|
||||||
for (;;)
|
|
||||||
{
|
{
|
||||||
if (((cast(size_t) sn) & 3) == 0)
|
result.insertBack(args[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else static if (isSomeChar!(Args[0])) // Char
|
||||||
{
|
{
|
||||||
break;
|
result.insertBack(args[0]);
|
||||||
}
|
}
|
||||||
lchk:
|
else static if (isFloatingPoint!(Args[0])) // Float
|
||||||
if (sn[0] == 0)
|
|
||||||
{
|
{
|
||||||
goto ld;
|
fv = args[0];
|
||||||
}
|
|
||||||
++sn;
|
|
||||||
}
|
|
||||||
n = 0xffffffff;
|
|
||||||
while (n)
|
|
||||||
{
|
|
||||||
uint v = *cast(uint*) sn;
|
|
||||||
if ((v - 0x01010101) & (~v) & 0x80808080UL)
|
|
||||||
{
|
|
||||||
goto lchk;
|
|
||||||
}
|
|
||||||
sn += 4;
|
|
||||||
--n;
|
|
||||||
}
|
|
||||||
goto lchk;
|
|
||||||
|
|
||||||
ld:
|
|
||||||
l = cast(uint) (sn - s);
|
|
||||||
|
|
||||||
lead[0] = 0;
|
|
||||||
tail[0] = 0;
|
|
||||||
precision = 0;
|
|
||||||
decimalPos = 0;
|
|
||||||
// Copy the string in.
|
|
||||||
}
|
|
||||||
else static if (fmt[0] == 'c') // Char
|
|
||||||
{
|
|
||||||
// Get the character.
|
|
||||||
s = num.ptr + num.length - 1;
|
|
||||||
*s = cast(char) va_arg!int(va);
|
|
||||||
l = 1;
|
|
||||||
lead[0] = 0;
|
|
||||||
tail[0] = 0;
|
|
||||||
precision = 0;
|
|
||||||
decimalPos = 0;
|
|
||||||
}
|
|
||||||
else static if (fmt[0] == 'g') // Float
|
|
||||||
{
|
|
||||||
fv = va_arg!double(va);
|
|
||||||
if (precision == -1)
|
if (precision == -1)
|
||||||
{
|
{
|
||||||
precision = 6;
|
precision = 6;
|
||||||
@ -642,7 +600,7 @@ pure nothrow @nogc
|
|||||||
tz = precision - (l - 1);
|
tz = precision - (l - 1);
|
||||||
precision = 0;
|
precision = 0;
|
||||||
// Dump the exponent.
|
// Dump the exponent.
|
||||||
tail[1] = hex[0xe];
|
tail[1] = 'e';
|
||||||
decimalPos -= 1;
|
decimalPos -= 1;
|
||||||
if (decimalPos < 0)
|
if (decimalPos < 0)
|
||||||
{
|
{
|
||||||
@ -808,67 +766,51 @@ pure nothrow @nogc
|
|||||||
l = cast(uint) (s - (num.ptr + 64));
|
l = cast(uint) (s - (num.ptr + 64));
|
||||||
s = num.ptr + 64;
|
s = num.ptr + 64;
|
||||||
}
|
}
|
||||||
else static if (fmt[0] == 'p') // Pointer
|
else static if (isPointer!(Args[0])) // Pointer
|
||||||
{
|
{
|
||||||
l = (4 << 4) | (4 << 8);
|
|
||||||
lead[0] = 2;
|
|
||||||
lead[1] = '0';
|
|
||||||
lead[2] = 'x';
|
|
||||||
|
|
||||||
// Get the number.
|
// Get the number.
|
||||||
static if (size_t.sizeof == 8)
|
n64 = cast(size_t) args[0];
|
||||||
{
|
size_t position = num.length;
|
||||||
n64 = va_arg!ulong(va);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
n64 = va_arg!uint(va);
|
|
||||||
}
|
|
||||||
|
|
||||||
s = num.ptr + num.length;
|
do // Write at least "0" if the pointer is null.
|
||||||
decimalPos = 0;
|
|
||||||
// Clear tail, and clear leading if value is zero.
|
|
||||||
tail[0] = 0;
|
|
||||||
if (n64 == 0)
|
|
||||||
{
|
{
|
||||||
lead[0] = 0;
|
num[--position] = lowerHexDigits[cast(size_t) (n64 & 15)];
|
||||||
|
n64 >>= 4;
|
||||||
}
|
}
|
||||||
// Convert to string.
|
while (n64 != 0);
|
||||||
for (;;)
|
|
||||||
{
|
result.insertBack("0x");
|
||||||
*--s = hex[cast(size_t) (n64 & ((1 << (l >> 8)) - 1))];
|
result.insertBack(num[position .. $]);
|
||||||
n64 >>= l >> 8;
|
|
||||||
if (n64 == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
else static if (isIntegral!(Args[0])) // Integer
|
||||||
// Get the length that we copied.
|
|
||||||
l = cast(uint)((num.ptr + num.length) - s);
|
|
||||||
}
|
|
||||||
else static if (fmt[0] == 'u' || fmt[0] == 'i' || fmt[0] == 'l') // Integer
|
|
||||||
{
|
{
|
||||||
// Get the integer and abs it.
|
// Get the integer and abs it.
|
||||||
if (fmt[0] == 'l')
|
static if (Args[0].sizeof == 8)
|
||||||
{
|
{
|
||||||
long i64 = va_arg!long(va);
|
long k64 = args[0];
|
||||||
n64 = cast(ulong) i64;
|
n64 = cast(ulong) k64;
|
||||||
if ((fmt[0] != 'u') && (i64 < 0))
|
static if (isSigned!(Args[0]))
|
||||||
{
|
{
|
||||||
n64 = cast(ulong) -i64;
|
if (k64 < 0)
|
||||||
|
{
|
||||||
|
n64 = cast(ulong) -k64;
|
||||||
negative = true;
|
negative = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int i = va_arg!int(va);
|
int k = args[0];
|
||||||
n64 = cast(uint) i;
|
n64 = cast(uint) k;
|
||||||
if ((fmt[0] != 'u') && (i < 0))
|
static if (isSigned!(Args[0]))
|
||||||
{
|
{
|
||||||
n64 = cast(uint) -i;
|
if (k < 0)
|
||||||
|
{
|
||||||
|
n64 = cast(uint) -k;
|
||||||
negative = true;
|
negative = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Convert to string.
|
// Convert to string.
|
||||||
s = num.ptr + num.length;
|
s = num.ptr + num.length;
|
||||||
@ -934,6 +876,10 @@ pure nothrow @nogc
|
|||||||
static assert(false);
|
static assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result.length > 0)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
scopy:
|
scopy:
|
||||||
// Get fw=leading/trailing space, precision=leading zeros.
|
// Get fw=leading/trailing space, precision=leading zeros.
|
||||||
if (precision < cast(int) l)
|
if (precision < cast(int) l)
|
||||||
@ -1057,76 +1003,68 @@ scopy:
|
|||||||
}
|
}
|
||||||
|
|
||||||
*bf = 0;
|
*bf = 0;
|
||||||
return buf[0 .. tlen + cast(int) (bf - buf.ptr)];
|
result = String(buf[0 .. cast(int) (bf - buf.ptr)]);
|
||||||
}
|
|
||||||
|
|
||||||
char[] format(string fmt, Args...)(return char[] buf, ...)
|
|
||||||
nothrow
|
|
||||||
{
|
|
||||||
va_list va;
|
|
||||||
va_start(va, buf);
|
|
||||||
auto result = vsprintf!(fmt, Args)(buf, va);
|
|
||||||
va_end(va);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
nothrow unittest
|
@nogc pure unittest
|
||||||
{
|
{
|
||||||
char[318] buffer;
|
char[318] buffer;
|
||||||
|
|
||||||
// Modifiers.
|
// Modifiers.
|
||||||
assert(format!("g", double)(buffer, 8.5) == "8.5");
|
assert(format!("{}")(buffer, 8.5) == "8.5");
|
||||||
assert(format!("g", double)(buffer, 8.6) == "8.6");
|
assert(format!("{}")(buffer, 8.6) == "8.6");
|
||||||
assert(format!("i", int)(buffer, 1000) == "1000");
|
assert(format!("{}")(buffer, 1000) == "1000");
|
||||||
assert(format!("i", int)(buffer, 1) == "1");
|
assert(format!("{}")(buffer, 1) == "1");
|
||||||
assert(format!("g", double)(buffer, 10.25) == "10.25");
|
assert(format!("{}")(buffer, 10.25) == "10.25");
|
||||||
assert(format!("i", int)(buffer, 1) == "1");
|
assert(format!("{}")(buffer, 1) == "1");
|
||||||
assert(format!("g", double)(buffer, 0.01) == "0.01");
|
assert(format!("{}")(buffer, 0.01) == "0.01");
|
||||||
|
|
||||||
// Integer size.
|
// Integer size.
|
||||||
assert(format!("i", short)(buffer, 10) == "10");
|
assert(format!("{}")(buffer, 10) == "10");
|
||||||
assert(format!("l", long)(buffer, 10L) == "10");
|
assert(format!("{}")(buffer, 10L) == "10");
|
||||||
|
|
||||||
// String printing.
|
// String printing.
|
||||||
assert(format!("s", string)(buffer, "Some weired string") == "Some weired string");
|
assert(format!("{}")(buffer, "Some weired string") == "Some weired string");
|
||||||
assert(format!("s", string)(buffer, cast(string) null) == "null");
|
assert(format!("{}")(buffer, cast(string) null) == "null");
|
||||||
assert(format!("c", char)(buffer, 'c') == "c");
|
assert(format!("{}")(buffer, 'c') == "c");
|
||||||
|
|
||||||
// Integer conversions.
|
// Integer conversions.
|
||||||
assert(format!("i", int)(buffer, 8) == "8");
|
assert(format!("{}")(buffer, 8) == "8");
|
||||||
assert(format!("i", int)(buffer, 8) == "8");
|
assert(format!("{}")(buffer, 8) == "8");
|
||||||
assert(format!("i", int)(buffer, -8) == "-8");
|
assert(format!("{}")(buffer, -8) == "-8");
|
||||||
assert(format!("l", long)(buffer, -8L) == "-8");
|
assert(format!("{}")(buffer, -8L) == "-8");
|
||||||
assert(format!("u", uint)(buffer, 8) == "8");
|
assert(format!("{}")(buffer, 8) == "8");
|
||||||
assert(format!("i", int)(buffer, 100000001) == "100000001");
|
assert(format!("{}")(buffer, 100000001) == "100000001");
|
||||||
assert(format!("i", int)(buffer, 99999999L) == "99999999");
|
assert(format!("{}")(buffer, 99999999L) == "99999999");
|
||||||
|
|
||||||
// Floating point conversions.
|
// Floating point conversions.
|
||||||
assert(format!("g", double)(buffer, 0.1234) == "0.1234");
|
assert(format!("{}")(buffer, 0.1234) == "0.1234");
|
||||||
assert(format!("g", double)(buffer, 0.3) == "0.3");
|
assert(format!("{}")(buffer, 0.3) == "0.3");
|
||||||
assert(format!("g", double)(buffer, 0.333333333333) == "0.333333");
|
assert(format!("{}")(buffer, 0.333333333333) == "0.333333");
|
||||||
assert(format!("g", double)(buffer, 38234.1234) == "38234.1");
|
assert(format!("{}")(buffer, 38234.1234) == "38234.1");
|
||||||
assert(format!("g", double)(buffer, -0.3) == "-0.3");
|
assert(format!("{}")(buffer, -0.3) == "-0.3");
|
||||||
assert(format!("g", double)(buffer, 0.000000000000000006) == "6e-18");
|
assert(format!("{}")(buffer, 0.000000000000000006) == "6e-18");
|
||||||
assert(format!("g", double)(buffer, 0.0) == "0");
|
assert(format!("{}")(buffer, 0.0) == "0");
|
||||||
assert(format!("g", double)(buffer, double.init) == "NaN");
|
assert(format!("{}")(buffer, double.init) == "NaN");
|
||||||
assert(format!("g", double)(buffer, -double.init) == "-NaN");
|
assert(format!("{}")(buffer, -double.init) == "-NaN");
|
||||||
assert(format!("g", double)(buffer, double.infinity) == "Inf");
|
assert(format!("{}")(buffer, double.infinity) == "Inf");
|
||||||
assert(format!("g", double)(buffer, -double.infinity) == "-Inf");
|
assert(format!("{}")(buffer, -double.infinity) == "-Inf");
|
||||||
assert(format!("g", double)(buffer, 0.000000000000000000000000003) == "3e-27");
|
assert(format!("{}")(buffer, 0.000000000000000000000000003) == "3e-27");
|
||||||
assert(format!("g", double)(buffer, 0.23432e304) == "2.3432e+303");
|
assert(format!("{}")(buffer, 0.23432e304) == "2.3432e+303");
|
||||||
assert(format!("g", double)(buffer, -0.23432e8) == "-2.3432e+07");
|
assert(format!("{}")(buffer, -0.23432e8) == "-2.3432e+07");
|
||||||
assert(format!("g", double)(buffer, 1e-307) == "1e-307");
|
assert(format!("{}")(buffer, 1e-307) == "1e-307");
|
||||||
assert(format!("g", double)(buffer, 1e+8) == "1e+08");
|
assert(format!("{}")(buffer, 1e+8) == "1e+08");
|
||||||
assert(format!("g", double)(buffer, 111234.1) == "111234");
|
assert(format!("{}")(buffer, 111234.1) == "111234");
|
||||||
assert(format!("g", double)(buffer, 0.999) == "0.999");
|
assert(format!("{}")(buffer, 0.999) == "0.999");
|
||||||
assert(format!("g", double)(buffer, 0x1p-16382L)); // "6.95336e-310"
|
assert(format!("{}")(buffer, 0x1p-16382L) == "0");
|
||||||
assert(format!("g", double)(buffer, 1e+3) == "1000");
|
assert(format!("{}")(buffer, 1e+3) == "1000");
|
||||||
assert(format!("g", double)(buffer, 38234.1234) == "38234.1");
|
assert(format!("{}")(buffer, 38234.1234) == "38234.1");
|
||||||
|
|
||||||
// Pointer convesions.
|
// Pointer convesions.
|
||||||
assert(format!("p", void*)(buffer, cast(void*) 1) == "0x1");
|
assert(format!("{}")(buffer, cast(void*) 1) == "0x1");
|
||||||
assert(format!("p", void*)(buffer, cast(void*) 20) == "0x14");
|
assert(format!("{}")(buffer, cast(void*) 20) == "0x14");
|
||||||
|
assert(format!("{}")(buffer, cast(void*) null) == "0x0");
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct FormatSpec
|
private struct FormatSpec
|
||||||
|
Loading…
Reference in New Issue
Block a user