bug-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] NSScanner: Add string to long long hex conversion support


From: Abbas Raza
Subject: Re: [PATCH] NSScanner: Add string to long long hex conversion support
Date: Mon, 5 Sep 2016 21:47:11 +1000

Hi,

Did you find anything wrong with this patch? Please let me know if it needs corrections.

Thanks !

Best Regards,

Abbas Raza


On 1 September 2016 at 14:45, Abbas Raza <abbas.raza.1707@gmail.com> wrote:

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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]