LCOV - code coverage report
Current view: top level - Core - OOStringParsing.m (source / functions) Hit Total Coverage
Test: coverxygen.info Lines: 0 20 0.0 %
Date: 2025-05-28 07:50:54 Functions: 0 0 -

          Line data    Source code
       1           0 : /*
       2             : 
       3             : OOStringParsing.m
       4             : 
       5             : Oolite
       6             : Copyright (C) 2004-2013 Giles C Williams and contributors
       7             : 
       8             : This program is free software; you can redistribute it and/or
       9             : modify it under the terms of the GNU General Public License
      10             : as published by the Free Software Foundation; either version 2
      11             : of the License, or (at your option) any later version.
      12             : 
      13             : This program is distributed in the hope that it will be useful,
      14             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             : GNU General Public License for more details.
      17             : 
      18             : You should have received a copy of the GNU General Public License
      19             : along with this program; if not, write to the Free Software
      20             : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
      21             : MA 02110-1301, USA.
      22             : 
      23             : */
      24             : 
      25             : #import "OOStringParsing.h"
      26             : #import "OOLogging.h"
      27             : #import "NSScannerOOExtensions.h"
      28             : #import "legacy_random.h"
      29             : #import "Universe.h"
      30             : #import "PlayerEntity.h"
      31             : #import "PlayerEntityLegacyScriptEngine.h"
      32             : #import "OOFunctionAttributes.h"
      33             : #import "OOCollectionExtractors.h"
      34             : #import "ResourceManager.h"
      35             : #import "HeadUpDisplay.h"
      36             : 
      37             : #import "OOJavaScriptEngine.h"
      38             : #import "OOJSEngineTimeManagement.h"
      39             : 
      40             : 
      41           0 : static NSString * const kOOLogStringVectorConversion                    = @"strings.conversion.vector";
      42           0 : static NSString * const kOOLogStringQuaternionConversion                = @"strings.conversion.quaternion";
      43           0 : static NSString * const kOOLogStringRandomSeedConversion                = @"strings.conversion.randomSeed";
      44             : 
      45             : 
      46           0 : NSMutableArray *ScanTokensFromString(NSString *values)
      47             : {
      48             :         NSMutableArray                  *result = nil;
      49             :         NSScanner                               *scanner = nil;
      50             :         NSString                                *token = nil;
      51             :         static NSCharacterSet   *space_set = nil;
      52             :         
      53             :         // Note: Shark suggests we're getting a lot of early exits, but testing showed a pretty steady 2% early exit rate.
      54             :         if (EXPECT_NOT(values == nil))  return [NSMutableArray array];
      55             :         if (EXPECT_NOT(space_set == nil)) space_set = [[NSCharacterSet whitespaceAndNewlineCharacterSet] retain];
      56             :         
      57             :         result = [NSMutableArray array];
      58             :         scanner = [NSScanner scannerWithString:values];
      59             :         
      60             :         while (![scanner isAtEnd])
      61             :         {
      62             :                 [scanner ooliteScanCharactersFromSet:space_set intoString:NULL];
      63             :                 if ([scanner ooliteScanUpToCharactersFromSet:space_set intoString:&token])
      64             :                 {
      65             :                         [result addObject:token];
      66             :                 }
      67             :         }
      68             :         
      69             :         return result;
      70             : }
      71             : 
      72             : 
      73           0 : BOOL ScanVectorFromString(NSString *xyzString, Vector *outVector)
      74             : {
      75             :         GLfloat                                 xyz[] = {0.0, 0.0, 0.0};
      76             :         int                                             i = 0;
      77             :         NSString                                *error = nil;
      78             :         NSScanner                               *scanner = nil;
      79             :         
      80             :         assert(outVector != NULL);
      81             :         if (xyzString == nil) return NO;
      82             :         
      83             :         if (!error) scanner = [NSScanner scannerWithString:xyzString];
      84             :         while (![scanner isAtEnd] && i < 3 && !error)
      85             :         {
      86             :                 if (![scanner scanFloat:&xyz[i++]])  error = @"could not scan a float value.";
      87             :         }
      88             :         
      89             :         if (!error && i < 3)  error = @"found less than three float values.";
      90             :         
      91             :         if (!error)
      92             :         {
      93             :                 *outVector = make_vector(xyz[0], xyz[1], xyz[2]);
      94             :                 return YES;
      95             :         }
      96             :         else
      97             :         {
      98             :                  OOLogERR(kOOLogStringVectorConversion, @"cannot make vector from '%@': %@", xyzString, error);
      99             :                  return NO;
     100             :         }
     101             : }
     102             : 
     103           0 : BOOL ScanHPVectorFromString(NSString *xyzString, HPVector *outVector)
     104             : {
     105             :         Vector scanVector;
     106             :         assert(outVector != NULL);
     107             :         BOOL result = ScanVectorFromString(xyzString, &scanVector);
     108             :         if (!result)
     109             :         {
     110             :                 return NO;
     111             :         }
     112             :         *outVector = vectorToHPVector(scanVector);
     113             :         return YES;
     114             : }
     115             : 
     116           0 : BOOL ScanQuaternionFromString(NSString *wxyzString, Quaternion *outQuaternion)
     117             : {
     118             :         GLfloat                                 wxyz[] = {1.0, 0.0, 0.0, 0.0};
     119             :         int                                             i = 0;
     120             :         NSString                                *error = nil;
     121             :         NSScanner                               *scanner = nil;
     122             :         
     123             :         assert(outQuaternion != NULL);
     124             :         if (wxyzString == nil) return NO;
     125             :         
     126             :         if (!error) scanner = [NSScanner scannerWithString:wxyzString];
     127             :         while (![scanner isAtEnd] && i < 4 && !error)
     128             :         {
     129             :                 if (![scanner scanFloat:&wxyz[i++]])  error = @"could not scan a float value.";
     130             :         }
     131             :         
     132             :         if (!error && i < 4)  error = @"found less than four float values.";
     133             :         
     134             :         if (!error)
     135             :         {
     136             :                 outQuaternion->w = wxyz[0];
     137             :                 outQuaternion->x = wxyz[1];
     138             :                 outQuaternion->y = wxyz[2];
     139             :                 outQuaternion->z = wxyz[3];
     140             :                 quaternion_normalize(outQuaternion);
     141             :                 return YES;
     142             :         }
     143             :         else
     144             :         {
     145             :                 OOLogERR(kOOLogStringQuaternionConversion, @"cannot make quaternion from '%@': %@", wxyzString, error);
     146             :                 return NO;
     147             :         }
     148             : }
     149             : 
     150             : 
     151           0 : BOOL ScanVectorAndQuaternionFromString(NSString *xyzwxyzString, Vector *outVector, Quaternion *outQuaternion)
     152             : {
     153             :         GLfloat                                 xyzwxyz[] = { 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0};
     154             :         int                                             i = 0;
     155             :         NSString                                *error = nil;
     156             :         NSScanner                               *scanner = nil;
     157             :         
     158             :         assert(outVector != NULL && outQuaternion != NULL);
     159             :         if (xyzwxyzString == nil) return NO;
     160             :         
     161             :         if (!error) scanner = [NSScanner scannerWithString:xyzwxyzString];
     162             :         while (![scanner isAtEnd] && i < 7 && !error)
     163             :         {
     164             :                 if (![scanner scanFloat:&xyzwxyz[i++]])  error = @"Could not scan a float value.";
     165             :         }
     166             :         
     167             :         if (!error && i < 7)  error = @"Found less than seven float values.";
     168             :         
     169             :         if (error)
     170             :         {
     171             :                 OOLogERR(kOOLogStringQuaternionConversion, @"cannot make vector and quaternion from '%@': %@", xyzwxyzString, error);
     172             :                 return NO;
     173             :         }
     174             :         
     175             :         outVector->x = xyzwxyz[0];
     176             :         outVector->y = xyzwxyz[1];
     177             :         outVector->z = xyzwxyz[2];
     178             :         outQuaternion->w = xyzwxyz[3];
     179             :         outQuaternion->x = xyzwxyz[4];
     180             :         outQuaternion->y = xyzwxyz[5];
     181             :         outQuaternion->z = xyzwxyz[6];
     182             :         
     183             :         return YES;
     184             : }
     185             : 
     186             : 
     187           0 : Vector VectorFromString(NSString *xyzString, Vector defaultValue)
     188             : {
     189             :         Vector result;
     190             :         if (!ScanVectorFromString(xyzString, &result))  result = defaultValue;
     191             :         return result;
     192             : }
     193             : 
     194             : 
     195           0 : Quaternion QuaternionFromString(NSString *wxyzString, Quaternion defaultValue)
     196             : {
     197             :         Quaternion result;
     198             :         if (!ScanQuaternionFromString(wxyzString, &result))  result = defaultValue;
     199             :         return result;
     200             : }
     201             : 
     202             : 
     203           0 : NSString *StringFromPoint(NSPoint point)
     204             : {
     205             :         return [NSString stringWithFormat:@"%f %f", point.x, point.y];
     206             : }
     207             : 
     208             : 
     209           0 : NSPoint PointFromString(NSString *xyString)
     210             : {
     211             :         NSArray         *tokens = ScanTokensFromString(xyString);
     212             :         NSPoint         result = NSZeroPoint;
     213             :         
     214             :         NSUInteger n_tokens = [tokens count];
     215             :         if (n_tokens == 2)
     216             :         {
     217             :                 result.x = [[tokens objectAtIndex:0] doubleValue];
     218             :                 result.y = [[tokens objectAtIndex:1] doubleValue];
     219             :         }
     220             :         return result;
     221             : }
     222             : 
     223             : 
     224           0 : Random_Seed RandomSeedFromString(NSString *abcdefString)
     225             : {
     226             :         Random_Seed                             result;
     227             :         int                                             abcdef[] = { 0, 0, 0, 0, 0, 0};
     228             :         int                                             i = 0;
     229             :         NSString                                *error = nil;
     230             :         NSScanner                               *scanner = [NSScanner scannerWithString:abcdefString];
     231             :         
     232             :         while (![scanner isAtEnd] && i < 6 && !error)
     233             :         {
     234             :                 if (![scanner scanInt:&abcdef[i++]])  error = @"could not scan a int value.";
     235             :         }
     236             :         
     237             :         if (!error && i < 6)  error = @"found less than six int values.";
     238             :         
     239             :         if (!error)
     240             :         {
     241             :                 result.a = abcdef[0];
     242             :                 result.b = abcdef[1];
     243             :                 result.c = abcdef[2];
     244             :                 result.d = abcdef[3];
     245             :                 result.e = abcdef[4];
     246             :                 result.f = abcdef[5];
     247             :         }
     248             :         else
     249             :         {
     250             :                 OOLogERR(kOOLogStringRandomSeedConversion, @"cannot make Random_Seed from '%@': %@", abcdefString, error);
     251             :                 result = kNilRandomSeed;
     252             :         }
     253             :         
     254             :         return result;
     255             : }
     256             : 
     257             : 
     258           0 : NSString *StringFromRandomSeed(Random_Seed seed)
     259             : {
     260             :         return [NSString stringWithFormat: @"%d %d %d %d %d %d", seed.a, seed.b, seed.c, seed.d, seed.e, seed.f];
     261             : }
     262             : 
     263             : 
     264           0 : NSString *OOPadStringToEms(NSString * string, float padEms)
     265             : {
     266             :         NSString                *result = string;
     267             :         float numEms = padEms - OOStringWidthInEm(result);
     268             :         if (numEms>0)
     269             :         {
     270             :                 numEms /= OOStringWidthInEm(@" "); // start with wide space
     271             :                 result=[[@"" stringByPaddingToLength:(NSUInteger)numEms withString: @" " startingAtIndex:0] stringByAppendingString: result];
     272             :         }
     273             :         // most of the way there, so switch to narrow space
     274             :         numEms = padEms - OOStringWidthInEm(result);
     275             :         if (numEms>0)
     276             :         {
     277             :                 numEms /= OOStringWidthInEm(@"\037"); // 037 is narrow space
     278             :                 result=[[@"" stringByPaddingToLength:(NSUInteger)numEms withString: @"\037" startingAtIndex:0] stringByAppendingString: result];
     279             :         }
     280             :         return result;
     281             : }
     282             : 
     283             : 
     284           0 : NSString *OOStringFromDeciCredits(OOCreditsQuantity tenthsOfCredits, BOOL includeDecimal, BOOL includeSymbol)
     285             : {
     286             :         JSContext                       *context = OOJSAcquireContext();
     287             :         JSObject                        *global = [[OOJavaScriptEngine sharedEngine] globalObject];
     288             :         JSObject                        *fakeRoot;
     289             :         jsval                           method;
     290             :         jsval                           rval;
     291             :         NSString                        *result = nil;
     292             :         jsval                           exception;
     293             :         BOOL                            hadException;
     294             :         
     295             :         /*      Because the |cr etc. formatting operators call this, and the
     296             :                 implementation may use string expansion, we need to ensure recursion
     297             :                 can't happen.
     298             :         */
     299             :         static BOOL reentrancyLock;
     300             :         if (reentrancyLock)  return [NSString stringWithFormat:@"%0.1f", tenthsOfCredits * 0.1];
     301             :         
     302             :         reentrancyLock = YES;
     303             :         
     304             :         hadException = JS_GetPendingException(context, &exception);
     305             :         JS_ClearPendingException(context);
     306             :         
     307             :         if (JS_GetMethodById(context, global, OOJSID("formatCredits"), &fakeRoot, &method))
     308             :         {
     309             :                 jsval args[3];
     310             :                 if (JS_NewNumberValue(context, tenthsOfCredits * 0.1, &args[0]))
     311             :                 {
     312             :                         args[1] = OOJSValueFromBOOL(includeDecimal);
     313             :                         args[2] = OOJSValueFromBOOL(includeSymbol);
     314             :                         
     315             :                         OOJSStartTimeLimiter();
     316             :                         JS_CallFunctionValue(context, global, method, 3, args, &rval);
     317             :                         OOJSStopTimeLimiter();
     318             :                         
     319             :                         result = OOStringFromJSValue(context, rval);
     320             :                 }
     321             :         }
     322             :         
     323             :         if (hadException)  JS_SetPendingException(context, exception);
     324             :         
     325             :         OOJSRelinquishContext(context);
     326             :         
     327             :         if (EXPECT_NOT(result == nil))  result = [NSString stringWithFormat:@"%li", (long)(tenthsOfCredits) / 10];
     328             :         
     329             :         reentrancyLock = NO;
     330             :         
     331             :         return result;
     332             : }
     333             : 
     334             : 
     335             : @implementation NSString (OOUtilities)
     336             : 
     337             : - (BOOL)pathHasExtension:(NSString *)extension
     338             : {
     339             :         return [[self pathExtension] caseInsensitiveCompare:extension] == NSOrderedSame;
     340             : }
     341             : 
     342             : 
     343             : - (BOOL)pathHasExtensionInArray:(NSArray *)extensions
     344             : {
     345             :         NSEnumerator    *extEnum = nil;
     346             :         NSString                *extension = nil;
     347             :         
     348             :         for (extEnum = [extensions objectEnumerator]; (extension = [extEnum nextObject]); )
     349             :         {
     350             :                 if ([[self pathExtension] caseInsensitiveCompare:extension] == NSOrderedSame) return YES;
     351             :         }
     352             :         
     353             :         return NO;
     354             : }
     355             : 
     356             : @end
     357             : 
     358             : 
     359           0 : NSArray *ComponentsFromVersionString(NSString *string)
     360             : {
     361             :         NSArray                         *stringComponents = nil;
     362             :         NSMutableArray          *result = nil;
     363             :         NSUInteger                      i, count;
     364             :         int                                     value;
     365             :         id                                      component;
     366             :         
     367             :         stringComponents = [string componentsSeparatedByString:@" "];
     368             :         stringComponents = [[stringComponents objectAtIndex:0] componentsSeparatedByString:@"-"];
     369             :         stringComponents = [[stringComponents objectAtIndex:0] componentsSeparatedByString:@"."];
     370             :         count = [stringComponents count];
     371             :         result = [NSMutableArray arrayWithCapacity:count];
     372             :         
     373             :         for (i = 0; i != count; ++i)
     374             :         {
     375             :                 component = [stringComponents objectAtIndex:i];
     376             :                 if ([component respondsToSelector:@selector(intValue)])  value = MAX([component intValue], 0);
     377             :                 else  value = 0;
     378             :                 
     379             :                 [result addObject:[NSNumber numberWithUnsignedInt:value]];
     380             :         }
     381             :         
     382             :         return result;
     383             : }
     384             : 
     385             : 
     386           0 : NSComparisonResult CompareVersions(NSArray *version1, NSArray *version2)
     387             : {
     388             :         NSEnumerator            *leftEnum = nil,
     389             :                                                 *rightEnum = nil;
     390             :         NSNumber                        *leftComponent = nil,
     391             :                                                 *rightComponent = nil;
     392             :         unsigned                        leftValue,
     393             :                                                 rightValue;
     394             :         
     395             :         leftEnum = [version1 objectEnumerator];
     396             :         rightEnum = [version2 objectEnumerator];
     397             :         
     398             :         for (;;)
     399             :         {
     400             :                 leftComponent = [leftEnum nextObject];
     401             :                 rightComponent = [rightEnum nextObject];
     402             :                 
     403             :                 if (leftComponent == nil && rightComponent == nil)  break;      // End of both versions
     404             :                 
     405             :                 // We'll get 0 if the component is nil, which is what we want.
     406             :                 leftValue = [leftComponent unsignedIntValue];
     407             :                 rightValue = [rightComponent unsignedIntValue];
     408             :                 
     409             :                 if (leftValue < rightValue) return NSOrderedAscending;
     410             :                 if (leftValue > rightValue) return NSOrderedDescending;
     411             :         }
     412             :         
     413             :         // If there was a difference, we'd have returned already.
     414             :         return NSOrderedSame;
     415             : }
     416             : 
     417             : 
     418           0 : NSString *ClockToString(double clock, BOOL adjusting)
     419             : {
     420             :         int                             days, hrs, mins, secs;
     421             :         NSString                *format = nil;
     422             :         
     423             :         days = floor(clock / 86400.0);
     424             :         secs = floor(clock - days * 86400.0);
     425             :         hrs = floor(secs / 3600.0);
     426             :         secs %= 3600;
     427             :         mins = floor(secs / 60.0);
     428             :         secs %= 60;
     429             :         
     430             :         if (adjusting)  format = DESC(@"clock-format-adjusting");
     431             :         else  format = DESC(@"clock-format");
     432             :         
     433             :         return [NSString stringWithFormat:format, days, hrs, mins, secs];
     434             : }
     435             : 
     436             : 
     437             : #if DEBUG_GRAPHVIZ
     438             : 
     439             : NSString *EscapedGraphVizString(NSString *string)
     440             : {
     441             :         NSString * const srcStrings[] =
     442             :         {
     443             :                 //Note: backslash must be first.
     444             :                 @"\\", @"\"", @"\'", @"\r", @"\n", @"\t", nil
     445             :         };
     446             :         NSString * const subStrings[] =
     447             :         {
     448             :                 //Note: must be same order.
     449             :                 @"\\\\", @"\\\"", @"\\\'", @"\\r", @"\\n", @"\\t", nil
     450             :         };
     451             :         
     452             :         NSString * const *              src = srcStrings;
     453             :         NSString * const *              sub = subStrings;
     454             :         NSMutableString                 *mutable = nil;
     455             :         NSString                                *result = nil;
     456             :         
     457             :         mutable = [string mutableCopy];
     458             :         while (*src != nil)
     459             :         {
     460             :                 [mutable replaceOccurrencesOfString:*src++
     461             :                                                                  withString:*sub++
     462             :                                                                         options:0
     463             :                                                                           range:(NSRange){ 0, [mutable length] }];
     464             :         }
     465             :         
     466             :         if ([mutable length] == [string length])
     467             :         {
     468             :                 result = string;
     469             :         }
     470             :         else
     471             :         {
     472             :                 result = [[mutable copy] autorelease];
     473             :         }
     474             :         [mutable release];
     475             :         return result;
     476             : }
     477             : 
     478             : 
     479             : static BOOL NameIsTaken(NSString *name, NSSet *uniqueSet);
     480             : 
     481             : NSString *GraphVizTokenString(NSString *string, NSMutableSet *uniqueSet)
     482             : {
     483             :         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
     484             :         
     485             :         BOOL lastWasUnderscore = NO;
     486             :         NSUInteger i, length = [string length], ri = 0;
     487             :         unichar result[length];
     488             :         NSString *token = nil;
     489             :         
     490             :         if (length > 0)
     491             :         {
     492             :                 // Special case for first char - can't be digit.
     493             :                 unichar c = [string characterAtIndex:0];
     494             :                 if (!isalpha(c))
     495             :                 {
     496             :                         c = '_';
     497             :                         lastWasUnderscore = YES;
     498             :                 }
     499             :                 result[ri++] = c;
     500             :                 
     501             :                 for (i = 1; i < length; i++)
     502             :                 {
     503             :                         c = [string characterAtIndex:i];
     504             :                         if (!isalnum(c))
     505             :                         {
     506             :                                 if (lastWasUnderscore)  continue;
     507             :                                 c = '_';
     508             :                                 lastWasUnderscore = YES;
     509             :                         }
     510             :                         else
     511             :                         {
     512             :                                 lastWasUnderscore = NO;
     513             :                         }
     514             :                         
     515             :                         result[ri++] = c;
     516             :                 }
     517             :                 
     518             :                 token = [NSString stringWithCharacters:result length:ri];
     519             :         }
     520             :         else
     521             :         {
     522             :                 token = @"_";
     523             :         }
     524             :         
     525             :         if (NameIsTaken(token, uniqueSet))
     526             :         {
     527             :                 if (!lastWasUnderscore)  token = [token stringByAppendingString:@"_"];
     528             :                 NSString *uniqueToken = nil;
     529             :                 unsigned uniqueID = 2;
     530             :                 
     531             :                 for (;;)
     532             :                 {
     533             :                         uniqueToken = [NSString stringWithFormat:@"%@%u", token, uniqueID];
     534             :                         if (!NameIsTaken(uniqueToken, uniqueSet))  break;
     535             :                 }
     536             :                 token = uniqueToken;
     537             :         }
     538             :         [uniqueSet addObject:token];
     539             :         
     540             :         [token retain];
     541             :         [pool release];
     542             :         return [token autorelease];
     543             : }
     544             : 
     545             : 
     546             : static BOOL NameIsTaken(NSString *name, NSSet *uniqueSet)
     547             : {
     548             :         if ([uniqueSet containsObject:name])  return YES;
     549             :         
     550             :         static NSSet *keywords = nil;
     551             :         if (keywords == nil)  keywords = [[NSSet alloc] initWithObjects:@"node", @"edge", @"graph", @"digraph", @"subgraph", @"strict", nil];
     552             :         
     553             :         return [keywords containsObject:[name lowercaseString]];
     554             : }
     555             : 
     556             : #endif //DEBUG_GRAPHVIZ

Generated by: LCOV version 1.14