|
From: | Abbas Raza |
Subject: | Re: [PATCH] NSScanner: Add string to long long hex conversion support |
Date: | Mon, 5 Sep 2016 21:47:11 +1000 |
Best Regards,
Abbas Raza
Signed-off-by: Abbas Raza <abbas.raza.1707@gmail.com>
---
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
[Prev in Thread] | Current Thread | [Next in Thread] |