A couple of locale fixes

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@17167 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-Macdonald 2003-07-07 09:05:53 +00:00
parent 55aa234ddb
commit afb5488c8b
6 changed files with 229 additions and 14 deletions

View file

@ -3,6 +3,10 @@
* Source/Source/GSFFCallInvocation.m: gs_objc_msg_forward() trust the
selector we are given. Rather than trying to find a better one.
* Source/GSFFIInvocation.m: ditto
* Source/NSScanner.m: Add a couple of internal utility functions.
* Source/NSString.m: Fix floatValue and doubelValue to use non
localised conversions.
* Source/GSString.m: ditto.
2003-07-06 Adam Fedor <fedor@gnu.org>

View file

@ -2002,3 +2002,4 @@ group_number (unichar *w, unichar *rear_ptr, const char *grouping,
}
return w;
}

View file

@ -1004,21 +1004,25 @@ dataUsingEncoding_u(ivars self, NSStringEncoding encoding, BOOL flag)
}
}
extern BOOL GSScanDouble(unichar*, unsigned, double*);
static inline double
doubleValue_c(ivars self)
{
if (self->_count == 0)
{
return 0;
return 0.0;
}
else
{
unsigned len = self->_count < 32 ? self->_count : 31;
unsigned char buf[len+1];
unsigned l = self->_count < 32 ? self->_count : 32;
unichar buf[l];
unichar *b = buf;
double d = 0.0;
memcpy(buf, self->_contents.c, len);
buf[len] = '\0';
return atof(buf);
GSToUnicode(&b, &l, self->_contents.c, l, intEnc, 0, 0);
GSScanDouble(b, l, &d);
return d;
}
}
@ -1027,16 +1031,14 @@ doubleValue_u(ivars self)
{
if (self->_count == 0)
{
return 0;
return 0.0;
}
else
{
unsigned int l = self->_count < 10 ? self->_count : 9;
unsigned char buf[l+1];
unsigned char *b = buf;
double d = 0.0;
GSFromUnicode(&b, &l, self->_contents.u, l, intEnc, 0, GSUniTerminate);
return atof(buf);
GSScanDouble(self->_contents.u, self->_count, &d);
return d;
}
}

View file

@ -646,6 +646,10 @@ static Class doubleNumberClass;
return NSCopyObject(self, 0, zone);
}
/**
* Returns the string representation of this number using a non-localised
* conversion (decimal point is '.' irrespective of the locale).
*/
- (NSString*) description
{
return [self descriptionWithLocale: nil];

View file

@ -1113,3 +1113,181 @@ typedef struct {
}
@end
/*
* Some utilities
*/
BOOL
GSScanInt(unichar *buf, unsigned length, int *result)
{
unsigned int num = 0;
const unsigned int limit = UINT_MAX / 10;
BOOL negative = NO;
BOOL overflow = NO;
BOOL got_digits = NO;
unsigned int pos = 0;
/* Check for sign */
if (pos < length)
{
switch (buf[pos])
{
case '+':
pos++;
break;
case '-':
negative = YES;
pos++;
break;
}
}
/* Process digits */
while (pos < length)
{
unichar digit = buf[pos];
if ((digit < '0') || (digit > '9'))
break;
if (!overflow)
{
if (num >= limit)
overflow = YES;
else
num = num * 10 + (digit - '0');
}
pos++;
got_digits = YES;
}
/* Save result */
if (!got_digits)
{
return NO;
}
if (result)
{
if (overflow
|| (num > (negative ? (unsigned int)INT_MIN : (unsigned int)INT_MAX)))
*result = negative ? INT_MIN: INT_MAX;
else if (negative)
*result = -num;
else
*result = num;
}
return YES;
}
/**
* Scan in a double value in the standard locale ('.' as decimal point).<br />
* Return YES on success, NO on failure.<br />
* The value pointed to by result is unmodified on failure.<br />
* No value is returned in result if it is a null pointer.
*/
BOOL
GSScanDouble(unichar *buf, unsigned length, double *result)
{
unichar c = 0;
double num = 0.0;
long int exponent = 0;
BOOL negative = NO;
BOOL got_dot = NO;
BOOL got_digit = NO;
unsigned pos = 0;
/* Skip whitespace */
while (pos < length && isspace((int)buf[pos]))
{
pos++;
}
/* Check for sign */
if (pos < length)
{
switch (buf[pos])
{
case '+':
pos++;
break;
case '-':
negative = YES;
pos++;
break;
}
}
/* Process number */
while (pos < length)
{
c = buf[pos];
if ((c >= '0') && (c <= '9'))
{
/* Ensure that the number being accumulated will not overflow. */
if (num >= (DBL_MAX / 10.000000001))
{
++exponent;
}
else
{
num = (num * 10.0) + (c - '0');
got_digit = YES;
}
/* Keep track of the number of digits after the decimal point.
If we just divided by 10 here, we would lose precision. */
if (got_dot)
{
--exponent;
}
}
else if (!got_dot && (c == '.'))
{
/* Note that we have found the decimal point. */
got_dot = YES;
}
else
{
/* Any other character terminates the number. */
break;
}
pos++;
}
if (!got_digit)
{
return NO;
}
/* Check for trailing exponent */
if ((pos < length) && ((c == 'e') || (c == 'E')))
{
int expval;
pos++;
if (GSScanInt(&buf[pos], length - pos, &expval) == YES)
{
/* Check for exponent overflow */
if (num)
{
if ((exponent > 0) && (expval > (LONG_MAX - exponent)))
exponent = LONG_MAX;
else if ((exponent < 0) && (expval < (LONG_MIN - exponent)))
exponent = LONG_MIN;
else
exponent += expval;
}
}
else
{
return NO;
}
}
if (result)
{
if (num && exponent)
num *= pow(10.0, (double) exponent);
if (negative)
*result = -num;
else
*result = num;
}
return YES;
}

View file

@ -2425,14 +2425,40 @@ handle_printf_atsign (FILE *stream,
return [self intValue] != 0 ? YES : NO;
}
extern BOOL GSScanDouble(unichar*, unsigned, double*);
/**
* Returns the strings content as a double. Skips leading whitespace.<br />
* Conversion is not localised (ie uses '.' as the decimal separator).<br />
* Returns 0.0 on underflow or if the string does not contain a number.
*/
- (double) doubleValue
{
return atof([self lossyCString]);
unichar buf[32];
unsigned len = [self length];
double d = 0.0;
if (len > 32) len = 32;
[self getCharacters: buf range: NSMakeRange(0, len)];
GSScanDouble(buf, len, &d);
return d;
}
/**
* Returns the strings content as a double. Skips leading whitespace.<br />
* Conversion is not localised (ie uses '.' as the decimal separator).<br />
* Returns 0.0 on underflow or if the string does not contain a number.
*/
- (float) floatValue
{
return (float) atof([self lossyCString]);
unichar buf[32];
unsigned len = [self length];
double d = 0.0;
if (len > 32) len = 32;
[self getCharacters: buf range: NSMakeRange(0, len)];
GSScanDouble(buf, len, &d);
return (float)d;
}
- (int) intValue