[PATCH] NSScanner: Add string to long long hex conversion support
Abbas Raza <[email protected]>
| Newsgroups | gmane.comp.lib.gnustep.bugs |
|---|---|
| Message-ID | <CABUCQqF74=qDC3fdGq2zWQGdx52j29_g-a7B+O7pfp-07P_PLw@mail.gmail.com> |
Signed-off-by: Abbas Raza <[email protected]> --- Headers/Foundation/NSScanner.h | 3 +- Source/NSScanner.m | 143 ++++++++++++++++++++++++++++++ +++++++++-- Tests/base/NSScanner/test01.m | 17 +++++ 3 files changed, 157 insertions(+), 6 deletions(-) diff --git a/Headers/Foundation/NSScanner.h b/Headers/Foundation/NSScanner.h index a3b61dd..b103642 100644 --- a/Headers/Foundation/NSScanner.h +++ b/Headers/Foundation/NSScanner.h @@ -94,6 +94,7 @@ extern "C" { - (BOOL) scanInt: (int*)value; - (BOOL) scanHexInt: (unsigned int*)value; - (BOOL) scanLongLong: (long long*)value; +- (BOOL) scanHexLongLong: (unsigned long long*)value; - (BOOL) scanFloat: (float*)value; - (BOOL) scanDouble: (double*)value; - (BOOL) scanString: (NSString*)string intoString: (NSString**)value; @@ -116,8 +117,6 @@ extern "C" { /** Not implemented */ - (BOOL) scanHexFloat: (float *)result; /** Not implemented */ -- (BOOL) scanHexLongLong: (unsigned long long *)result; -/** Not implemented */ - (BOOL) scanInteger: (NSInteger *)value; #endif @end diff --git a/Source/NSScanner.m b/Source/NSScanner.m index 26c3077..149be49 100644 --- a/Source/NSScanner.m +++ b/Source/NSScanner.m @@ -629,6 +629,145 @@ typedef GSString *ivars; #endif /* defined(LLONG_MAX) */ } +/* + * Scan an unsigned long long of the given radix into value. + * Internal version used by scanHexLongLong: . + */ +- (BOOL) scanUnsignedLongLong_: (unsigned long long int*)value + radix: (NSUInteger)radix + gotDigits: (BOOL)gotDigits +{ +#if defined(ULLONG_MAX) + unsigned long long int num = 0; + unsigned long long int numLimit, digitLimit, digitValue; + BOOL overflow = NO; + unsigned int saveScanLocation = _scanLocation; + + /* Set limits */ + numLimit = ULLONG_MAX / radix; + digitLimit = ULLONG_MAX % radix; + + /* Process digits */ + while (_scanLocation < myLength()) + { + unichar digit = myCharacter(_scanLocation); + + switch (digit) + { + case '0': digitValue = 0; break; + case '1': digitValue = 1; break; + case '2': digitValue = 2; break; + case '3': digitValue = 3; break; + case '4': digitValue = 4; break; + case '5': digitValue = 5; break; + case '6': digitValue = 6; break; + case '7': digitValue = 7; break; + case '8': digitValue = 8; break; + case '9': digitValue = 9; break; + case 'a': digitValue = 0xA; break; + case 'b': digitValue = 0xB; break; + case 'c': digitValue = 0xC; break; + case 'd': digitValue = 0xD; break; + case 'e': digitValue = 0xE; break; + case 'f': digitValue = 0xF; break; + case 'A': digitValue = 0xA; break; + case 'B': digitValue = 0xB; break; + case 'C': digitValue = 0xC; break; + case 'D': digitValue = 0xD; break; + case 'E': digitValue = 0xE; break; + case 'F': digitValue = 0xF; break; + default: + digitValue = radix; + break; + } + if (digitValue >= radix) + break; + if (!overflow) + { + if ((num > numLimit) + || ((num == numLimit) && (digitValue > digitLimit))) + overflow = YES; + else + num = num * radix + digitValue; + } + _scanLocation++; + gotDigits = YES; + } + + /* Save result */ + if (!gotDigits) + { + _scanLocation = saveScanLocation; + return NO; + } + if (value) + { + if (overflow) + *value = ULLONG_MAX; + else + *value = num; + } + return YES; +#else /* defined(ULLONG_MAX) */ + /* + * Provide compile-time warning and run-time exception. + */ +# warning "Can't use unsigned long long variables." + [NSException raise: NSGenericException + format: @"Can't use unsigned long long variables."]; + return NO; +#endif /* defined(ULLONG_MAX) */ +} + +/** + * After initial skipping (if any), this method scans a hexadecimal + * long long value (optionally prefixed by "0x" or "0X"), + * placing it in <em>longLongValue</em> if that is not null. + * <br/> + * Returns YES if anything is scanned, NO otherwise. + * <br/> + * On overflow, ULLONG_MAX or ULLONG_MAX is put into <em>longLongValue</em> + * <br/> + * Scans past any excess digits + */ +- (BOOL) scanHexLongLong: (unsigned long long*)value +{ + unsigned int saveScanLocation = _scanLocation; + + /* Skip whitespace */ + if (!skipToNextField()) + { + _scanLocation = saveScanLocation; + return NO; + } + + if ((_scanLocation < myLength()) && (myCharacter(_scanLocation) == '0')) + { + _scanLocation++; + if (_scanLocation < myLength()) + { + switch (myCharacter(_scanLocation)) + { + case 'x': + case 'X': + _scanLocation++; // Scan beyond the 0x prefix + break; + default: + _scanLocation--; // Scan from the initial digit + break; + } + } + else + { + _scanLocation--; // Just scan the zero. + } + } + if ([self scanUnsignedLongLong_: value radix: 16 gotDigits: NO]) + return YES; + _scanLocation = saveScanLocation; + return NO; +} + /** * Not implemented. */ @@ -1140,10 +1279,6 @@ typedef GSString *ivars; { return NO; // FIXME } -- (BOOL) scanHexLongLong: (unsigned long long *)result -{ - return NO; // FIXME -} - (BOOL) scanInteger: (NSInteger *)value { #if GS_SIZEOF_VOIDP == GS_SIZEOF_INT diff --git a/Tests/base/NSScanner/test01.m b/Tests/base/NSScanner/test01.m index 63dd912..13cc29e 100644 --- a/Tests/base/NSScanner/test01.m +++ b/Tests/base/NSScanner/test01.m @@ -51,6 +51,19 @@ static BOOL scanHex(NSString *str, return ((expectValue == 1) ? (expectedValue == *retp) : YES && expectedScanLoc == [scn scanLocation]); } + +static BOOL scanHexLongLong(NSString *str, + int expectValue, + unsigned long long expectedValue, + int expectedScanLoc, + int *retp) +{ + NSScanner *scn = [NSScanner scannerWithString:str]; + [scn scanHexLongLong:retp]; + return ((expectValue == 1) ? (expectedValue == *retp) : YES + && expectedScanLoc == [scn scanLocation]); +} + static BOOL scanDouble(NSString *str, double expectedValue, double *retp) @@ -104,6 +117,10 @@ int main() PASS(scanHex(@"1234FOO", 1, 0x1234F, 5, &ret) && scanHex(@"01234FOO", 1, 0x1234F, 6, &ret), "NSScanner hex (non-digits terminate scan)"); + + PASS(scanHexLongLong(@"1234FOO", 1, 0x1234F, 5, &ret) + && scanHexLongLong(@"01234FOO", 1, 0x1234F, 6, &ret), + "NSScanner hex long long (non-digits terminate scan)"); /* dbl1 = 123.456; dbl2 = 123.45678901234567890123456789012345678901234567; dbl3 = 1.23456789; -- 2.1.4 _______________________________________________ Bug-gnustep mailing list [email protected] https://lists.gnu.org/mailman/listinfo/bug-gnustep