This is nsscanner.m in view mode; [Download] [Up]
/* * Test the operation of the NSScanner class. * All is well if this program produces no output. * * By default, double values differing by one least-significant-bit or * less are assumed to be equal. This behaviour can be changed with * the `-e' flag. For example, if you want only doubles that are exactly * equal to be treated as equal, use `-e0'. * * Eric Norum <eric@skatter.usask.ca> * * $Date: 1996/09/02 18:45:21 $ $Revision: 1.2 $ */ #include <Foundation/NSScanner.h> #include <limits.h> #include <float.h> #include <math.h> #include <stdio.h> /* * Doubles differing by this many least-significant-bits * or less are assumed to be `equal'. */ int DoubleCompareEqual = 1; /* * Check that scan completely consumed string */ void testFullScan (const char *message, NSString *string, NSScanner *scanner) { unsigned int scanLocation; scanLocation = [scanner scanLocation]; if (scanLocation != [string length]) printf ("%s of `%s' moves scan location to %u.\n", message, [string cString], scanLocation); } /* ************************************************************************ * scanInt: * ************************************************************************ */ /* * Test a valid scanInt operation */ void testScanIntGood (int i) { NSString *string; NSScanner *scanner; int value; string = [NSString stringWithFormat:@"%d", i]; scanner = [NSScanner scannerWithString:string]; if (![scanner scanInt:&value]) printf ("scanInt of `%s' failed.\n", [string cString]); else if (value != i) printf ("scanInt of `%s' returned value %d.\n", [string cString], value); testFullScan ("scanInt", string, scanner); [string release]; [scanner release]; } /* * Verify that scanInt handles overflow */ void testScanIntOverflow (double d) { NSString *string; NSScanner *scanner; int value; string = [NSString stringWithFormat:@"%.0f", d]; scanner = [NSScanner scannerWithString:string]; if (![scanner scanInt:&value]) printf ("scanInt of `%s' failed.\n", [string cString]); else if (value != ((d < 0) ? INT_MIN : INT_MAX)) printf ("scanInt of `%s' didn't overflow, returned %d.\n", [string cString], value); testFullScan ("scanInt", string, scanner); [string release]; [scanner release]; } /* * Test scanInt operation */ void testScanInt (void) { NSString *string; NSScanner *scanner; int i; int value; unsigned int scanLocation; /* * Check values within range */ i = INT_MAX-20; for (;;) { testScanIntGood (i); if (i == INT_MAX) break; i++; } i = INT_MIN+20; for (;;) { testScanIntGood (i); if (i == INT_MIN) break; i--; } for (i = -20 ; i <= 20 ; i++) testScanIntGood (i); /* * Check overflow values */ for (i = 1 ; i <= 20 ; i++) { testScanIntOverflow ((double)INT_MAX + i); testScanIntOverflow ((double)INT_MIN - i); testScanIntOverflow ((2.0 * (double)INT_MAX) + i); testScanIntOverflow ((2.0 * (double)INT_MIN) - i); testScanIntOverflow ((10.0 * (double)INT_MAX) + i); testScanIntOverflow ((10.0 * (double)INT_MIN) - i); } /* * Check that non-digits terminate the scan */ string = @"1234FOO"; scanner = [NSScanner scannerWithString:string]; if (![scanner scanInt:&value]) printf ("scanInt of `%s' failed.\n", [string cString]); scanLocation = [scanner scanLocation]; if (scanLocation != 4) printf ("scanInt of `%s' moves scan location to %u.\n", [string cString], scanLocation); [scanner release]; /* * Check that non-digits don't move the scan location */ string = @"junk"; scanner = [NSScanner scannerWithString:string]; if ([scanner scanInt:&value]) printf ("scanInt of `%s' succeeded with value %d.\n", [string cString], value); scanLocation = [scanner scanLocation]; if (scanLocation != 0) printf ("scanInt of `%s' moves scan location to %u.\n", [string cString], scanLocation); [scanner release]; /* * Check that non-digits don't consume characters to be skipped */ string = @" junk"; scanner = [NSScanner scannerWithString:string]; if ([scanner scanInt:&value]) printf ("scanInt of `%s' succeeded with value %d.\n", [string cString], value); scanLocation = [scanner scanLocation]; if (scanLocation != 0) printf ("scanInt of `%s' moves scan location to %u.\n", [string cString], scanLocation); [scanner release]; } /* ************************************************************************ * scanLongLong: * ************************************************************************ */ #if defined (LONG_LONG_MAX) /* * Quick hacks to convert a long long types. */ static char * unsignedlonglongToString (unsigned long long n) { static char cbuf[400]; /* Should be big enough! */ char *cp = &cbuf[400]; *--cp = '\0'; do { *--cp = (n % 10) + '0'; n /= 10; } while (n); return cp; } static char * longlongToString (long long i) { unsigned long long n; char *cp; if (i < 0) n = -i; else n = i; cp = unsignedlonglongToString (n); if (i < 0) *--cp = '-'; return cp; } /* * Test a valid scanLongLong operation */ void testScanLongLongGood (long long i) { NSString *string; NSScanner *scanner; long long value; string = [NSString stringWithFormat:@"%s", longlongToString (i)]; scanner = [NSScanner scannerWithString:string]; if (![scanner scanLongLong:&value]) printf ("scanLongLong of `%s' failed.\n", [string cString]); else if (value != i) printf ("scanLongLong of `%s' returned value %s.\n", [string cString], longlongToString (value)); testFullScan ("scanLongLong", string, scanner); [string release]; [scanner release]; } /* * Verify that scanLongLong handles overflow */ void testScanLongLongOverflow (const char *sign, unsigned long long check, long long expect) { NSString *string; NSScanner *scanner; long long value; string = [NSString stringWithFormat:@"%s%s", sign, unsignedlonglongToString (check)]; scanner = [NSScanner scannerWithString:string]; if (![scanner scanLongLong:&value]) printf ("scanLongLong of `%s' failed.\n", [string cString]); else if (value != expect) printf ("scanLongLong of `%s' didn't overflow, returned %s.\n", [string cString], longlongToString (value)); testFullScan ("scanLongLong", string, scanner); [string release]; [scanner release]; } /* * Test scanLongLong operation */ void testScanLongLong (void) { NSString *string; NSScanner *scanner; long long i; long long value; unsigned int scanLocation; /* * Check values within range */ i = LONG_LONG_MAX-20; for (;;) { testScanLongLongGood (i); if (i == LONG_LONG_MAX) break; i++; } i = LONG_LONG_MIN+20; for (;;) { testScanLongLongGood (i); if (i == LONG_LONG_MIN) break; i--; } for (i = -20 ; i <= 20 ; i++) testScanLongLongGood (i); /* * Check overflow values */ for (i = 1 ; i <= 20 ; i++) { testScanLongLongOverflow ("", LONG_LONG_MAX + i, LONG_LONG_MAX); testScanLongLongOverflow ("", ULONG_LONG_MAX - i + 1, LONG_LONG_MAX); if (i > 1) testScanLongLongOverflow ("-", LONG_LONG_MAX + i, LONG_LONG_MIN); } /* * Check that non-digits terminate the scan */ string = @"1234FOO"; scanner = [NSScanner scannerWithString:string]; if (![scanner scanLongLong:&value]) printf ("scanLongLong of `%s' failed.\n", [string cString]); scanLocation = [scanner scanLocation]; if (scanLocation != 4) printf ("scanLongLong of `%s' moves scan location to %u.\n", [string cString], scanLocation); /* * Check that non-digits don't move the scan location */ string = @"junk"; scanner = [NSScanner scannerWithString:string]; if ([scanner scanLongLong:&value]) printf ("scanLongLong of `%s' succeeded with value %s\n", [string cString], longlongToString (value)); scanLocation = [scanner scanLocation]; if (scanLocation != 0) printf ("scanLongLong of `%s' moves scan location to %u.\n", [string cString], scanLocation); } #endif /* defined (LONG_LONG_MAX) */ /* ************************************************************************ * scanDouble: * ************************************************************************ */ /* * Compare two doubles for `almost' equality */ static double areDoublesEqual (double d1, double d2) { if (d1 == d2) return 0; if (d1 == 0) return (fabs (d2) /DBL_EPSILON); if (d2 == 0) return (fabs (d1) /DBL_EPSILON); d1 = fabs(d1); d2 = fabs(d2); if (d1 > d2) return fabs (1.0 - (d1 / d2)) / DBL_EPSILON; else return fabs (1.0 - (d2 / d1)) / DBL_EPSILON; } /* * Test a scanDouble operation */ void testScanDoubleGood (NSString *string, double expect) { NSScanner *scanner; double value, error; scanner = [NSScanner scannerWithString:string]; if (![scanner scanDouble:&value]) printf ("scanDouble of `%s' failed.\n", [string cString]); else if ((error = areDoublesEqual (value, expect)) > DoubleCompareEqual) printf ("scanDouble of `%s' returned value %.*e (%g LSB different).\n", [string cString], DBL_DIG + 2, value, error); testFullScan ("scanDouble", string, scanner); [scanner release]; } static void testScanDoubleOneDigit (NSString *format, int digit, double expect) { NSString *string = [NSString stringWithFormat:format, digit]; testScanDoubleGood (string, expect); [string release]; } static void testScanDoubleShort (NSString *string, double expect, unsigned int length) { NSScanner *scanner; double value, error; unsigned int scanLocation; scanner = [NSScanner scannerWithString:string]; if (![scanner scanDouble:&value]) printf ("scanDouble of `%s' failed.\n", [string cString]); else if ((error = areDoublesEqual (value, expect)) > DoubleCompareEqual) printf ("scanDouble of `%s' returned value %.*e (%g LSB different).\n", [string cString], DBL_DIG + 2, value, error); scanLocation = [scanner scanLocation]; if (scanLocation != length) printf ("scanDouble of `%s' moves scan location to %u.\n", [string cString], scanLocation); [scanner release]; } void testScanDoubleBad (NSString *string) { NSScanner *scanner = [NSScanner scannerWithString:string]; double value; unsigned int scanLocation; if ([scanner scanDouble:&value]) printf ("scanDouble of `%s' succeeded with value %g\n", [string cString], value); scanLocation = [scanner scanLocation]; if (scanLocation != 0) printf ("scanDouble of `%s' moves scan location to %u.\n", [string cString], scanLocation); [scanner release]; } /* * Test scanDouble operations */ void testScanDouble (void) { int i; /* * Check all digits before and after decimal point */ for (i = 0 ; i < 10 ; i++) { testScanDoubleOneDigit (@"%d", i, i); testScanDoubleOneDigit (@"%d.", i, i); testScanDoubleOneDigit (@"%d.0", i, i); testScanDoubleOneDigit (@"0%d.0", i, i); testScanDoubleOneDigit (@".%d", i, i / 10.0); testScanDoubleOneDigit (@"0.%d", i, i / 10.0); testScanDoubleOneDigit (@"-%d", i, -i); testScanDoubleOneDigit (@"-%d.", i, -i); testScanDoubleOneDigit (@"-%d.0", i, -i); testScanDoubleOneDigit (@"-0%d.0", i, -i); testScanDoubleOneDigit (@"-.%d", i, -i / 10.0); testScanDoubleOneDigit (@"-0.%d", i, -i / 10.0); } /* * Check exponents */ testScanDoubleGood (@"1e0", 1); testScanDoubleGood (@"1e1", 10); testScanDoubleGood (@"1e+1", 10); testScanDoubleGood (@"1e10", 1e10); testScanDoubleGood (@"1e+10", 1e10); testScanDoubleGood (@"1e-0", 1); testScanDoubleGood (@"1e-1", 1e-1); testScanDoubleGood (@"1e-1", 1e-1); testScanDoubleGood (@"1e-10", 1e-10); testScanDoubleGood (@"1e-10", 1e-10); /* * Check a few other values */ testScanDoubleGood (@"123.456", 123.456); testScanDoubleGood (@"123.4567890123456789012345678901234567890123456789", 123.4567890123456789012345678901234567890123456789); testScanDoubleGood (@"1234567890123456789012345678.9", 1234567890123456789012345678.9); testScanDoubleGood (@"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890e-99", 1.234567890123456789012345678901234567890123456789); testScanDoubleGood (@"0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000123456789e+100", 1.23456789); /* * Check some overflow values (for IEEE double-precision) */ testScanDoubleGood (@"12345678901234567890123456789012345678901234567890e300", HUGE_VAL); testScanDoubleGood (@"-12345678901234567890123456789012345678901234567890e300", -HUGE_VAL); testScanDoubleGood (@"1e999", HUGE_VAL); testScanDoubleGood (@"-1e999", -HUGE_VAL); /* * Check some underflow values */ testScanDoubleGood (@"0.00000000000000000000000000000123456789e-300", 0); testScanDoubleGood (@"-0.00000000000000000000000000000123456789e-300", 0); testScanDoubleGood (@"1e-999", 0); testScanDoubleGood (@"-1e-999", 0); /* * Check that non-digits terminate the scan */ testScanDoubleShort (@"1234FOO", 1234, 4); testScanDoubleShort (@"1234.FOO", 1234, 5); testScanDoubleShort (@"1234.0FOO", 1234, 6); testScanDoubleShort (@"1234..FOO", 1234, 5); testScanDoubleShort (@"1234.5.FOO", 1234.5, 6); /* * Check that non-digits don't move the scan location */ testScanDoubleBad (@".foo"); testScanDoubleBad (@"efoo"); testScanDoubleBad (@".efoo"); testScanDoubleBad (@"1234.5e.FOO"); testScanDoubleBad (@"1234.5e.FOO"); testScanDoubleBad (@"1234.5e 1"); } /* ************************************************************************ * scanString: * ************************************************************************ */ void testScanStringGood (NSString *string, NSString *search, NSString *match, BOOL caseSensitive, unsigned int goodScanLocation) { NSScanner *scanner = [NSScanner scannerWithString:string]; NSString *s; [scanner setCaseSensitive:caseSensitive]; if ([scanner scanString:search intoString:&s]) { if (([scanner scanLocation] != goodScanLocation) || ![s isEqualToString:match]) printf ("Case-%ssensitive scanString `%s' of `%s' gives `%s', scanLocation %d.\n", caseSensitive ? "" : "in", [search cString], [string cString], [s cString], [scanner scanLocation]); } else { printf ("Case-%ssensitive scanString:`%s' of `%s' failed.\n", caseSensitive ? "" : "in", [search cString], [string cString]); } } void testScanStringBad (NSString *string, NSString *search, BOOL caseSensitive) { NSScanner *scanner = [NSScanner scannerWithString:string]; NSString *s; [scanner setCaseSensitive:caseSensitive]; if ([scanner scanString:search intoString:&s]) { printf ("Case-%ssensitive scanString `%s' of `%s' gives `%s'.\n", caseSensitive ? "" : "in", [search cString], [string cString], [s cString]); } else { if ([scanner scanLocation] != 0) printf ("Case-%ssensitive scanString `%s' of `%s' moves scan location to `%d'.\n", caseSensitive ? "" : "in", [search cString], [string cString], [scanner scanLocation]); } } void testScanString (void) { testScanStringGood (@"a", @"a", @"a", NO, 1); testScanStringGood (@"a", @"a", @"a", YES, 1); testScanStringGood (@"a", @"A", @"a", NO, 1); testScanStringGood (@" abcdefg", @"aBcD", @"abcd", NO, 7); testScanStringGood (@" ABCdEFG", @"aBcD", @"ABCd", NO, 7); testScanStringBad (@"a", @"A", YES); testScanStringBad (@" a", @"A", YES); testScanStringBad (@" aA", @"A", YES); testScanStringBad (@" aAb", @"b", NO); } /* ************************************************************************ * scanUpToString: * ************************************************************************ */ void testScanUpToStringGood (NSString *string, NSString *search, NSString *match, BOOL caseSensitive) { NSScanner *scanner = [NSScanner scannerWithString:string]; NSString *s; [scanner setCaseSensitive:caseSensitive]; if ([scanner scanUpToString:search intoString:&s]) { if (![s isEqualToString:match]) printf ("Case-%ssensitive scanUpToString `%s' of `%s' gives `%s'.\n", caseSensitive ? "" : "in", [search cString], [string cString], [s cString]); } else { printf ("Case-%ssensitive scanUpToString:`%s' of `%s' failed.\n", caseSensitive ? "" : "in", [search cString], [string cString]); } } void testScanUpToString (void) { testScanUpToStringGood (@"abcdefg", @"d", @"abc", NO); testScanUpToStringGood (@"abcdefg", @"de", @"abc", NO); testScanUpToStringGood (@"abcdefg", @"DeF", @"abcdefg", YES); testScanUpToStringGood (@"abcdefgDeFg", @"DeF", @"abc", NO); testScanUpToStringGood (@"abcdefgDeFg", @"DeF", @"abcdefg", YES); } /* ************************************************************************ * scanCharactersFromSet: * ************************************************************************ */ void testScanCharactersFromSetGood (NSString *string, NSCharacterSet *set, NSString *match, unsigned int goodScanLocation) { NSScanner *scanner = [NSScanner scannerWithString:string]; NSString *s; if ([scanner scanCharactersFromSet:set intoString:&s]) { if (([scanner scanLocation] != goodScanLocation) || ![s isEqualToString:match]) printf ("scanCharactersFromSet of `%s' gives `%s', scanLocation %d.\n", [string cString], [s cString], [scanner scanLocation]); } else { printf ("scanCharactersFromSet of `%s' failed.\n", [string cString]); } } void testScanCharactersFromSetBad (NSString *string, NSCharacterSet *set) { NSScanner *scanner = [NSScanner scannerWithString:string]; NSString *s; if ([scanner scanCharactersFromSet:set intoString:&s]) { printf ("scanCharactersFromSet of `%s' gives `%s'.\n", [string cString], [s cString]); } else { if ([scanner scanLocation] != 0) printf ("scanCharactersFromSet of `%s' moves scan location to `%d'.\n", [string cString], [scanner scanLocation]); } } void testScanCharactersFromSet (void) { NSCharacterSet *set = [NSCharacterSet uppercaseLetterCharacterSet]; testScanCharactersFromSetGood (@"A", set, @"A", 1); testScanCharactersFromSetGood (@"ABCde", set, @"ABC", 3); testScanCharactersFromSetGood (@"ABC", set, @"ABC", 3); testScanCharactersFromSetGood (@" AB12", set, @"AB", 4); testScanCharactersFromSetBad (@"a", set); testScanCharactersFromSetBad (@" abc", set); } /* ************************************************************************ * scanUpToCharactersFromSet: * ************************************************************************ */ void testScanUpToCharactersFromSetGood (NSString *string, NSCharacterSet *set, NSString *match, unsigned int goodScanLocation) { NSScanner *scanner = [NSScanner scannerWithString:string]; NSString *s; if ([scanner scanUpToCharactersFromSet:set intoString:&s]) { if (([scanner scanLocation] != goodScanLocation) || ![s isEqualToString:match]) printf ("scanUpToCharactersFromSet of `%s' gives `%s', scanLocation %d.\n", [string cString], [s cString], [scanner scanLocation]); } else { printf ("scanUpToCharactersFromSet of `%s' failed.\n", [string cString]); } } void testScanUpToCharactersFromSetBad (NSString *string, NSCharacterSet *set) { NSScanner *scanner = [NSScanner scannerWithString:string]; NSString *s; if ([scanner scanUpToCharactersFromSet:set intoString:&s]) { printf ("scanUpToCharactersFromSet of `%s' gives `%s'.\n", [string cString], [s cString]); } else { if ([scanner scanLocation] != 0) printf ("scanUpToCharactersFromSet of `%s' moves scan location to `%d'.\n", [string cString], [scanner scanLocation]); } } void testScanUpToCharactersFromSet (void) { NSCharacterSet *set = [NSCharacterSet uppercaseLetterCharacterSet]; testScanUpToCharactersFromSetGood (@"aA", set, @"a", 1); testScanUpToCharactersFromSetGood (@" aABCde", set, @"a", 3); testScanUpToCharactersFromSetGood (@"abc", set, @"abc", 3); testScanUpToCharactersFromSetGood (@" abAB12", set, @"ab", 4); testScanUpToCharactersFromSetBad (@"A", set); testScanUpToCharactersFromSetBad (@" Abc", set); } /* ************************************************************************ * TEST DRIVER * ************************************************************************ */ int main (int argc, char **argv) { extern char *optarg; int c; while ((c = getopt (argc, argv, "e:")) != EOF) { switch (c) { case 'e': DoubleCompareEqual = atoi (optarg); break; } } testScanInt (); #if defined (LONG_LONG_MAX) testScanLongLong (); #endif testScanDouble (); testScanString (); testScanUpToString (); testScanCharactersFromSet (); testScanUpToCharactersFromSet (); return 0; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.