diff --git a/ChangeLog b/ChangeLog index ec813be16..54a16eff4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,10 @@ 2007-12-02 David Ayers * Source/NSDecimal.m (GSDecimalDouble): Use NAN when available. + * Source/NSDecimalNumber.m ([initWithBytes:objCType:]): Implement + initialization with scalar types. Use GSPrivateDefaultLocale + to initialze intermediate string to match expectations of + initWithString. 2007-11-30 Richard Frith-Macdonald diff --git a/Source/NSDecimalNumber.m b/Source/NSDecimalNumber.m index d43ee661e..73ac0703c 100644 --- a/Source/NSDecimalNumber.m +++ b/Source/NSDecimalNumber.m @@ -26,6 +26,9 @@ $Date$ $Revision$ */ +#define _GNU_SOURCE +#include + #include "Foundation/NSCoder.h" #include "Foundation/NSDecimal.h" #include "Foundation/NSDecimalNumber.h" @@ -235,14 +238,148 @@ static NSDecimalNumber *one; */ - (id) initWithBytes: (const void*)value objCType: (const char*)type { - double tmp; - NSString *s; + unsigned long long val; + long long llval; + NSDecimal decimal; + BOOL negative, llvalSet; - memcpy(&tmp, value, sizeof(tmp)); - s = [[NSString alloc] initWithFormat: @"%g", tmp]; - self = [self initWithString: s]; - RELEASE(s); - return self; + if (strlen(type) != 1) + { + DESTROY(self); + return nil; + } + + llvalSet = YES; + negative = NO; + + switch (*type) + { + case _C_CHR: + { + signed char v = *(signed char *)value; + llval = (long long)v; + break; + } + case _C_UCHR: + { + unsigned char v = *(unsigned char *)value; + llval = (long long)v; + break; + } + case _C_SHT: + { + short v = *(short *)value; + llval = (long long)v; + break; + } + case _C_USHT: + { + unsigned short v = *(unsigned short *)value; + llval = (long long)v; + break; + } + case _C_INT: + { + int v = *(int *)value; + llval = (long long)v; + break; + } + case _C_UINT: + { + unsigned int v = *(unsigned int *)value; + llval = (long long)v; + break; + } + case _C_LNG: + { + long v = *(long *)value; + llval = (long long)v; + break; + } + case _C_ULNG: + { + unsigned long v = *(unsigned long *)value; + llval = (long long)v; + break; + } +#ifdef _C_LNGLNG + case _C_LNGLNG: +#else + case 'q': +#endif + { + long long v = *(long long *)value; + llval = (long long)v; + break; + } +#ifdef _C_ULNGLNG + case _C_ULNGLNG: +#else + case 'Q': +#endif + default: + { + llvalSet = NO; + break; + + } + } + if (llvalSet) + { + if (llval<0) + { + negative = YES; + llval *= -1; + } + val = llval; + } + else + { + switch (*type) + { + case _C_FLT: + /* FIXME: This is better implemented with GMP where available. */ + { + NSString *s; + float v = *(float *)value; + if (isnanf(v)) return notANumber; + if (isinff(v)) return (v < 0.0) ? minNumber : maxNumber; + s = [[NSString alloc] initWithFormat: @"%g" + locale: GSPrivateDefaultLocale(), (double)v]; + self = [self initWithString: s]; + RELEASE(s); + return self; + break; + } + case _C_DBL: + /* FIXME: This is better implemented with GMP where available. */ + { + NSString *s; + double v = *(double *)value; + if (isnan(v)) return notANumber; + if (isinf(v)) return (v < 0.0) ? minNumber : maxNumber; + s = [[NSString alloc] initWithFormat: @"%g" + locale: GSPrivateDefaultLocale(), v]; + self = [self initWithString: s]; + RELEASE(s); + return self; + break; + } +#ifdef _C_ULNGLNG + case _C_ULNGLNG: +#else + case 'Q': +#endif + { + val = *(unsigned long long *)value; + break; + } + } + } + + NSDecimalFromComponents(&decimal, val, + 0, negative); + return [self initWithDecimal: decimal]; } - (id) initWithDecimal: (NSDecimal)decimal