Oolite
Loading...
Searching...
No Matches
OOJSScript.m
Go to the documentation of this file.
1/*
2
3OOJSScript.m
4
5JavaScript support for Oolite
6Copyright (C) 2007-2013 David Taylor and Jens Ayton.
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program; if not, write to the Free Software
20Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21MA 02110-1301, USA.
22
23*/
24
25#ifndef OO_CACHE_JS_SCRIPTS
26#define OO_CACHE_JS_SCRIPTS 1
27#endif
28
29
30#import "OOJSScript.h"
33
34#import "OOLogging.h"
35#import "OOConstToString.h"
36#import "Entity.h"
39#import "OOConstToJSString.h"
42#import "OOPListParsing.h"
43#import "OODebugStandards.h"
44
45#if OO_CACHE_JS_SCRIPTS
46#include <jsxdrapi.h>
47#import "OOCacheManager.h"
48#endif
49
50
53{
56};
57
58
59static JSObject *sScriptPrototype;
61
62
63static void AddStackToArrayReversed(NSMutableArray *array, RunningStack *stack);
64
65static JSScript *LoadScriptWithName(JSContext *context, NSString *path, JSObject *object, JSObject **outScriptObject, NSString **outErrorMessage);
66
67#if OO_CACHE_JS_SCRIPTS
68static NSData *CompiledScriptData(JSContext *context, JSScript *script);
69static JSScript *ScriptWithCompiledData(JSContext *context, NSData *data);
70#endif
71
72static NSString *StrippedName(NSString *string);
73
74
75static JSBool ScriptAddProperty(JSContext *context, JSObject *this, jsid propID, jsval *value);
76
77
78static JSClass sScriptClass =
79{
80 "Script",
81 JSCLASS_HAS_PRIVATE,
82
84 JS_PropertyStub,
85 JS_PropertyStub,
86 JS_StrictPropertyStub,
87 JS_EnumerateStub,
88 JS_ResolveStub,
89 JS_ConvertStub,
91};
92
93
94static JSFunctionSpec sScriptMethods[] =
95{
96 // JS name Function min args
97 { "toString", OOJSObjectWrapperToString, 0, },
98 { 0 }
99};
100
101
102@interface OOJSScript (OOPrivate)
103
104- (NSString *)scriptNameFromPath:(NSString *)path;
105- (NSDictionary *)defaultPropertiesFromPath:(NSString *)path;
106
107@end
108
109
110@implementation OOJSScript
111
112+ (id) scriptWithPath:(NSString *)path properties:(NSDictionary *)properties
113{
114 return [[[self alloc] initWithPath:path properties:properties] autorelease];
115}
116
117
118- (id) initWithPath:(NSString *)path properties:(NSDictionary *)properties
119{
120 JSContext *context = NULL;
121 NSString *problem = nil; // Acts as error flag.
122 JSScript *script = NULL;
123 JSObject *scriptObject = NULL;
124 jsval returnValue = JSVAL_VOID;
125 NSString *key = nil;
126 id property = nil;
127
128 self = [super init];
129 if (self == nil) problem = @"allocation failure";
130 else
131 {
132 context = OOJSAcquireContext();
133
134 if (JS_IsExceptionPending(context))
135 {
136 JS_ClearPendingException(context);
137 OOLogERR(@"script.javaScript.load.waitingException", @"Prior to loading script %@, there was a pending JavaScript exception, which has been cleared. This is an internal error, please report it.", path);
138 }
139
140 // Set up JS object
141 if (!problem)
142 {
143 _jsSelf = JS_NewObject(context, &sScriptClass, sScriptPrototype, NULL);
144 if (_jsSelf == NULL) problem = @"allocation failure";
145 }
146
147 if (!problem && !OOJSAddGCObjectRoot(context, &_jsSelf, "Script object"))
148 {
149 problem = @"could not add JavaScript root object";
150 }
151
152 if (!problem && !OOJSAddGCObjectRoot(context, &scriptObject, "Script GC holder"))
153 {
154 problem = @"could not add JavaScript root object";
155 }
156
157 if (!problem)
158 {
159 if (!JS_SetPrivate(context, _jsSelf, OOConsumeReference([self weakRetain])))
160 {
161 problem = @"could not set private backreference";
162 }
163 }
164
165 // Push self on stack of running scripts.
166 RunningStack stackElement =
167 {
169 .current = self
170 };
171 sRunningStack = &stackElement;
172
173 filePath = [path retain];
174
175 if (!problem)
176 {
177 OOLog(@"script.javaScript.willLoad", @"About to load JavaScript %@", path);
178 script = LoadScriptWithName(context, path, _jsSelf, &scriptObject, &problem);
179 }
180 OOLogIndentIf(@"script.javaScript.willLoad");
181
182 // Set default properties from manifest.plist
183 NSDictionary *defaultProperties = [self defaultPropertiesFromPath:path];
184 foreachkey (key, defaultProperties)
185 {
186 if ([key isKindOfClass:[NSString class]])
187 {
188 property = [defaultProperties objectForKey:key];
189 if ([key isEqualToString:kLocalManifestProperty])
190 {
191 // this must not be editable
192 [self defineProperty:property named:key];
193 }
194 else
195 {
196 // can be overwritten by script itself
197 [self setProperty:property named:key];
198 }
199 }
200 }
201
202 // Set properties. (read-only)
203 if (!problem && properties != nil)
204 {
205 foreachkey (key, properties)
206 {
207 if ([key isKindOfClass:[NSString class]])
208 {
209 property = [properties objectForKey:key];
210 [self defineProperty:property named:key];
211 }
212 }
213 }
214
215 /* Set initial name (in case of script error during initial run).
216 The "name" ivar is not set here, so the property can be fetched from JS
217 if we fail during setup. However, the "name" ivar is set later so that
218 the script object can't be renamed after the initial run. This could
219 probably also be achieved by fiddling with JS property attributes.
220 */
221 jsid nameID = OOJSID("name");
222 [self setProperty:[self scriptNameFromPath:path] withID:nameID inContext:context];
223
224 // Run the script (allowing it to set up the properties we need, as well as setting up those event handlers)
225 if (!problem)
226 {
228 if (!JS_ExecuteScript(context, _jsSelf, script, &returnValue))
229 {
230 problem = @"could not run script";
231 }
233
234 // We don't need the script any more - the event handlers hang around as long as the JS object exists.
235 JS_DestroyScript(context, script);
236 }
237
238 JS_RemoveObjectRoot(context, &scriptObject);
239
240 sRunningStack = stackElement.back;
241
242 if (!problem)
243 {
244 // Get display attributes from script
245 DESTROY(name);
246 name = [StrippedName([[self propertyWithID:nameID inContext:context] description]) copy];
247 if (name == nil)
248 {
249 name = [[self scriptNameFromPath:path] retain];
250 [self setProperty:name withID:nameID inContext:context];
251 }
252
253 version = [[[self propertyWithID:OOJSID("version") inContext:context] description] copy];
254 description = [[[self propertyWithID:OOJSID("description") inContext:context] description] copy];
255
256 OOLog(@"script.javaScript.load.success", @"Loaded JavaScript: %@ -- %@", [self displayName], description ? description : (NSString *)@"(no description)");
257 }
258
259 OOLogOutdentIf(@"script.javaScript.willLoad");
260
261 DESTROY(filePath); // Only used for error reporting during startup.
262 }
263
264 if (problem)
265 {
266 OOLog(@"script.javaScript.load.failed", @"***** Error loading JavaScript script %@ -- %@", path, problem);
267 JS_ReportPendingException(context);
268 DESTROY(self);
269 }
270
271 OOJSRelinquishContext(context);
272
273 if (self != nil)
274 {
275 [[NSNotificationCenter defaultCenter] addObserver:self
276 selector:@selector(javaScriptEngineWillReset:)
277 name:kOOJavaScriptEngineWillResetNotification
279 }
280
281 return self;
282}
283
284
285- (void) dealloc
286{
287 [[NSNotificationCenter defaultCenter] removeObserver:self
288 name:kOOJavaScriptEngineWillResetNotification
290
291 DESTROY(name);
292 DESTROY(description);
293 DESTROY(version);
294 DESTROY(filePath);
295
296 if (_jsSelf != NULL)
297 {
298 JSContext *context = OOJSAcquireContext();
299
300 OOJSObjectWrapperFinalize(context, _jsSelf); // Release weakref to self
301 JS_RemoveObjectRoot(context, &_jsSelf); // Unroot jsSelf
302
303 OOJSRelinquishContext(context);
304 }
305
306 [weakSelf weakRefDrop];
307
308 [super dealloc];
309}
310
311
312- (NSString *) oo_jsClassName
313{
314 return @"Script";
315}
316
317
318- (NSString *)descriptionComponents
319{
320 if (_jsSelf != NULL) return [super descriptionComponents];
321 else return @"invalid script";
322}
323
324
325- (void) javaScriptEngineWillReset:(NSNotification *)notification
326{
327 // All scripts become invalid when the JS engine resets.
328 if (_jsSelf != NULL)
329 {
330 _jsSelf = NULL;
331 JSContext *context = OOJSAcquireContext();
332 JS_RemoveObjectRoot(context, &_jsSelf);
333 OOJSRelinquishContext(context);
334 }
335}
336
337
338+ (OOJSScript *) currentlyRunningScript
339{
340 if (sRunningStack == NULL) return NULL;
341 return sRunningStack->current;
342}
343
344
345+ (NSArray *) scriptStack
346{
347 NSMutableArray *result = nil;
348
349 result = [NSMutableArray array];
351 return result;
352}
353
354
355- (id) weakRetain
356{
357 if (weakSelf == nil) weakSelf = [OOWeakReference weakRefWithObject:self];
358 return [weakSelf retain];
359}
360
361
362- (void) weakRefDied:(OOWeakReference *)weakRef
363{
364 if (weakRef == weakSelf) weakSelf = nil;
365}
366
367
368- (NSString *) name
369{
370 if (name == nil) name = [[self propertyNamed:@"name"] copy];
371 if (name == nil) return [self scriptNameFromPath:filePath]; // Special case for parse errors during load.
372 return name;
373}
374
375
376- (NSString *) scriptDescription
377{
378 return description;
379}
380
381
382- (NSString *) version
383{
384 return version;
385}
386
387
388- (void)runWithTarget:(Entity *)target
389{
390
391}
392
393
394- (BOOL) callMethod:(jsid)methodID
395 inContext:(JSContext *)context
396 withArguments:(jsval *)argv count:(intN)argc
397 result:(jsval *)outResult
398{
399 NSParameterAssert(name != NULL && (argv != NULL || argc == 0) && context != NULL && JS_IsInRequest(context));
400 if (_jsSelf == NULL) return NO;
401
402 JSObject *root = NULL;
403 BOOL OK = NO;
404 jsval method;
405 jsval ignoredResult = JSVAL_VOID;
406
407 if (outResult == NULL) outResult = &ignoredResult;
408 OOJSAddGCObjectRoot(context, &root, "OOJSScript method root");
409
410 if (EXPECT(JS_GetMethodById(context, _jsSelf, methodID, &root, &method) && !JSVAL_IS_VOID(method)))
411 {
412#ifndef NDEBUG
413 if (JS_IsExceptionPending(context))
414 {
415 OOLog(@"script.internalBug", @"Exception pending on context before calling method in %s, clearing. This is an internal error, please report it.", __PRETTY_FUNCTION__);
416 JS_ClearPendingException(context);
417 }
418
419 OOLog(@"script.javaScript.call", @"Calling [%@].%@()", [self name], OOStringFromJSID(methodID));
420 OOLogIndentIf(@"script.javaScript.call");
421#endif
422
423 // Push self on stack of running scripts.
424 RunningStack stackElement =
425 {
427 .current = self
428 };
429 sRunningStack = &stackElement;
430
431 // Call the method.
433 OK = JS_CallFunctionValue(context, _jsSelf, method, argc, argv, outResult);
435
436 if (JS_IsExceptionPending(context))
437 {
438 JS_ReportPendingException(context);
439 OK = NO;
440 }
441
442 // Pop running scripts stack
443 sRunningStack = stackElement.back;
444
445#ifndef NDEBUG
446 OOLogOutdentIf(@"script.javaScript.call");
447#endif
448 }
449
450 JS_RemoveObjectRoot(context, &root);
451
452 return OK;
453}
454
455
456- (id) propertyWithID:(jsid)propID inContext:(JSContext *)context
457{
458 NSParameterAssert(context != NULL && JS_IsInRequest(context));
459 if (_jsSelf == NULL) return nil;
460
461 jsval jsValue = JSVAL_VOID;
462 if (JS_GetPropertyById(context, _jsSelf, propID, &jsValue))
463 {
464 return OOJSNativeObjectFromJSValue(context, jsValue);
465 }
466 return nil;
467}
468
469
470- (BOOL) setProperty:(id)value withID:(jsid)propID inContext:(JSContext *)context
471{
472 NSParameterAssert(context != NULL && JS_IsInRequest(context));
473 if (_jsSelf == NULL) return NO;
474
475 jsval jsValue = OOJSValueFromNativeObject(context, value);
476 return JS_SetPropertyById(context, _jsSelf, propID, &jsValue);
477}
478
479
480- (BOOL) defineProperty:(id)value withID:(jsid)propID inContext:(JSContext *)context
481{
482 NSParameterAssert(context != NULL && JS_IsInRequest(context));
483 if (_jsSelf == NULL) return NO;
484
485 jsval jsValue = OOJSValueFromNativeObject(context, value);
486 return JS_DefinePropertyById(context, _jsSelf, propID, jsValue, NULL, NULL, OOJS_PROP_READONLY);
487}
488
489
490- (id) propertyNamed:(NSString *)propName
491{
492 if (propName == nil) return nil;
493 if (_jsSelf == NULL) return nil;
494
495 JSContext *context = OOJSAcquireContext();
496 id result = [self propertyWithID:OOJSIDFromString(propName) inContext:context];
497 OOJSRelinquishContext(context);
498
499 return result;
500}
501
502
503- (BOOL) setProperty:(id)value named:(NSString *)propName
504{
505 if (value == nil || propName == nil) return NO;
506 if (_jsSelf == NULL) return NO;
507
508 JSContext *context = OOJSAcquireContext();
509 BOOL result = [self setProperty:value withID:OOJSIDFromString(propName) inContext:context];
510 OOJSRelinquishContext(context);
511
512 return result;
513}
514
515
516- (BOOL) defineProperty:(id)value named:(NSString *)propName
517{
518 if (value == nil || propName == nil) return NO;
519 if (_jsSelf == NULL) return NO;
520
521 JSContext *context = OOJSAcquireContext();
522 BOOL result = [self defineProperty:value withID:OOJSIDFromString(propName) inContext:context];
523 OOJSRelinquishContext(context);
524
525 return result;
526}
527
528
529- (jsval)oo_jsValueInContext:(JSContext *)context
530{
531 if (_jsSelf == NULL) return JSVAL_VOID;
532 return OBJECT_TO_JSVAL(_jsSelf);
533}
534
535
536+ (void)pushScript:(OOJSScript *)script
537{
538 RunningStack *element = NULL;
539
540 element = malloc(sizeof *element);
541 if (element == NULL) exit(EXIT_FAILURE);
542
543 element->back = sRunningStack;
544 element->current = script;
545 sRunningStack = element;
546}
547
548
549+ (void)popScript:(OOJSScript *)script
550{
551 RunningStack *element = NULL;
552
553 assert(sRunningStack->current == script);
554
555 element = sRunningStack;
557 free(element);
558}
559
560@end
561
562
563@implementation OOJSScript (OOPrivate)
564
565
566
567/* Generate default name for script which doesn't set its name property when
568 first run.
569
570 The generated name is <name>.anon-script, where <name> is selected as
571 follows:
572 * If path is nil (futureproofing), use the address of the script object.
573 * If the file's name is something other than script.*, use the file name.
574 * If the containing directory is something other than Config, use the
575 containing directory's name.
576 * Otherwise, use the containing directory's parent (which will generally
577 be an OXP root directory).
578 * If either of the two previous steps results in an empty string, fall
579 back on the full path.
580*/
581- (NSString *)scriptNameFromPath:(NSString *)path
582{
583 NSString *lastComponent = nil;
584 NSString *truncatedPath = nil;
585 NSString *theName = nil;
586
587 if (path == nil) theName = [NSString stringWithFormat:@"%p", self];
588 else
589 {
590 lastComponent = [path lastPathComponent];
591 if (![lastComponent hasPrefix:@"script."]) theName = lastComponent;
592 else
593 {
594 truncatedPath = [path stringByDeletingLastPathComponent];
595 if (NSOrderedSame == [[truncatedPath lastPathComponent] caseInsensitiveCompare:@"Config"])
596 {
597 truncatedPath = [truncatedPath stringByDeletingLastPathComponent];
598 }
599 if (NSOrderedSame == [[truncatedPath pathExtension] caseInsensitiveCompare:@"oxp"])
600 {
601 truncatedPath = [truncatedPath stringByDeletingPathExtension];
602 }
603
604 lastComponent = [truncatedPath lastPathComponent];
605 theName = lastComponent;
606 }
607 }
608
609 if (0 == [theName length]) theName = path;
610
611 return StrippedName([theName stringByAppendingString:@".anon-script"]);
612}
613
614
615- (NSDictionary *) defaultPropertiesFromPath:(NSString *)path
616{
617 // remove file name, remove OXP subfolder, add manifest.plist
618 NSString *manifestPath = [[[path stringByDeletingLastPathComponent] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"manifest.plist"];
619 NSDictionary *manifest = OODictionaryFromFile(manifestPath);
620 NSMutableDictionary *properties = [NSMutableDictionary dictionaryWithCapacity:3];
621 /* __oolite.tmp.* is allocated for OXPs without manifests. Its
622 * values are meaningless and shouldn't be used here */
623 if (manifest != nil && ![[manifest oo_stringForKey:kOOManifestIdentifier] hasPrefix:@"__oolite.tmp."])
624 {
625 if ([manifest objectForKey:kOOManifestVersion] != nil)
626 {
627 [properties setObject:[manifest oo_stringForKey:kOOManifestVersion] forKey:@"version"];
628 }
629 if ([manifest objectForKey:kOOManifestIdentifier] != nil)
630 {
631 // used for system info
632 [properties setObject:[manifest oo_stringForKey:kOOManifestIdentifier] forKey:kLocalManifestProperty];
633 }
634 if ([manifest objectForKey:kOOManifestAuthor] != nil)
635 {
636 [properties setObject:[manifest oo_stringForKey:kOOManifestAuthor] forKey:@"author"];
637 }
638 if ([manifest objectForKey:kOOManifestLicense] != nil)
639 {
640 [properties setObject:[manifest oo_stringForKey:kOOManifestLicense] forKey:@"license"];
641 }
642 }
643 return properties;
644}
645
646@end
647
648
649@implementation OOScript (JavaScriptEvents)
650
651- (BOOL) callMethod:(jsid)methodID
652 inContext:(JSContext *)context
653 withArguments:(jsval *)argv count:(intN)argc
654 result:(jsval *)outResult
655{
656 return NO;
657}
658
659@end
660
661
662void InitOOJSScript(JSContext *context, JSObject *global)
663{
664 sScriptPrototype = JS_InitClass(context, global, NULL, &sScriptClass, OOJSUnconstructableConstruct, 0, NULL, sScriptMethods, NULL, NULL);
666}
667
668
669static JSBool ScriptAddProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
670{
671 // Complain about attempts to set the property tickle.
672 if (JSID_IS_STRING(propID))
673 {
674 JSString *propName = JSID_TO_STRING(propID);
675 JSBool match;
676 if (JS_StringEqualsAscii(context, propName, "tickle", &match) && match)
677 {
678 OOJSScript *thisScript = OOJSNativeObjectOfClassFromJSObject(context, this, [OOJSScript class]);
679 OOJSReportWarning(context, @"Script %@ appears to use the tickle() event handler, which is no longer supported.", [thisScript name]);
680 }
681 }
682
683 return YES;
684}
685
686
687static void AddStackToArrayReversed(NSMutableArray *array, RunningStack *stack)
688{
689 if (stack != NULL)
690 {
691 AddStackToArrayReversed(array, stack->back);
692 [array addObject:stack->current];
693 }
694}
695
696
697static JSScript *LoadScriptWithName(JSContext *context, NSString *path, JSObject *object, JSObject **outScriptObject, NSString **outErrorMessage)
698{
699#if OO_CACHE_JS_SCRIPTS
700 OOCacheManager *cache = nil;
701#endif
702 NSString *fileContents = nil;
703 NSData *data = nil;
704 JSScript *script = NULL;
705
706 NSCParameterAssert(outScriptObject != NULL && outErrorMessage != NULL);
707 *outErrorMessage = nil;
708
709#if OO_CACHE_JS_SCRIPTS
710 // Look for cached compiled script
711 cache = [OOCacheManager sharedCache];
712 data = [cache objectForKey:path inCache:@"compiled JavaScript scripts"];
713 if (data != nil)
714 {
715 script = ScriptWithCompiledData(context, data);
716 }
717#endif
718
719 if (script == NULL)
720 {
721 fileContents = [NSString stringWithContentsOfUnicodeFile:path];
722
723 if (fileContents != nil)
724 {
725#ifndef NDEBUG
726 /* FIXME: this isn't strictly the right test, since strict
727 * mode can be enabled with this string within a function
728 * definition, but it seems unlikely anyone is actually doing
729 * that here. */
730 if ([fileContents rangeOfString:@"\"use strict\";"].location == NSNotFound && [fileContents rangeOfString:@"'use strict';"].location == NSNotFound)
731 {
732 OOStandardsDeprecated([NSString stringWithFormat:@"Script %@ does not \"use strict\";",path]);
733 if (OOEnforceStandards())
734 {
735 // prepend it anyway
736 // TODO: some time after 1.82, make this required
737 fileContents = [@"\"use strict\";\n" stringByAppendingString:fileContents];
738 }
739 }
740#endif
741 data = [fileContents utf16DataWithBOM:NO];
742 }
743 if (data == nil) *outErrorMessage = @"could not load file";
744 else
745 {
746 script = JS_CompileUCScript(context, object, [data bytes], [data length] / sizeof(unichar), [path UTF8String], 1);
747 if (script != NULL) *outScriptObject = JS_NewScriptObject(context, script);
748 else *outErrorMessage = @"compilation failed";
749 }
750
751#if OO_CACHE_JS_SCRIPTS
752 if (script != NULL)
753 {
754 // Write compiled script to cache
755 data = CompiledScriptData(context, script);
756 [cache setObject:data forKey:path inCache:@"compiled JavaScript scripts"];
757 }
758#endif
759 }
760
761 return script;
762}
763
764
765#if OO_CACHE_JS_SCRIPTS
766static NSData *CompiledScriptData(JSContext *context, JSScript *script)
767{
768 JSXDRState *xdr = NULL;
769 NSData *result = nil;
770 uint32 length;
771 void *bytes = NULL;
772
773 xdr = JS_XDRNewMem(context, JSXDR_ENCODE);
774 if (xdr != NULL)
775 {
776 if (JS_XDRScript(xdr, &script))
777 {
778 bytes = JS_XDRMemGetData(xdr, &length);
779 if (bytes != NULL)
780 {
781 result = [NSData dataWithBytes:bytes length:length];
782 }
783 }
784 JS_XDRDestroy(xdr);
785 }
786
787 return result;
788}
789
790
791static JSScript *ScriptWithCompiledData(JSContext *context, NSData *data)
792{
793 JSXDRState *xdr = NULL;
794 JSScript *result = NULL;
795
796 if (data == nil) return NULL;
797
798 xdr = JS_XDRNewMem(context, JSXDR_DECODE);
799 if (xdr != NULL)
800 {
801 NSUInteger length = [data length];
802 if (EXPECT_NOT(length > UINT32_MAX)) return NULL;
803
804 JS_XDRMemSetData(xdr, (void *)[data bytes], (uint32_t)length);
805 if (!JS_XDRScript(xdr, &result)) result = NULL;
806
807 JS_XDRMemSetData(xdr, NULL, 0); // Don't let it be freed by XDRDestroy
808 JS_XDRDestroy(xdr);
809 }
810
811 return result;
812}
813#endif
814
815
816static NSString *StrippedName(NSString *string)
817{
818 static NSCharacterSet *invalidSet = nil;
819 if (invalidSet == nil) invalidSet = [[NSCharacterSet characterSetWithCharactersInString:@"_ \t\n\r\v"] retain];
820
821 return [string stringByTrimmingCharactersInSet:invalidSet];
822}
#define DESTROY(x)
Definition OOCocoa.h:75
#define foreachkey(VAR, DICT)
Definition OOCocoa.h:353
id OOConsumeReference(id OO_NS_CONSUMED value)
Definition OOCocoa.m:93
void OOStandardsDeprecated(NSString *message)
BOOL OOEnforceStandards(void)
#define EXPECT_NOT(x)
#define EXPECT(x)
#define OOJSStopTimeLimiter()
#define OOJSStartTimeLimiter()
#define kOOJSLongTimeLimit
#define OOJSStartTimeLimiterWithTimeLimit(limit)
#define OOJSID(str)
Definition OOJSPropID.h:38
void InitOOJSScript(JSContext *context, JSObject *global)
Definition OOJSScript.m:662
static NSString *const kLocalManifestProperty
Definition OOJSScript.h:29
static NSString * StrippedName(NSString *string)
Definition OOJSScript.m:816
static JSBool ScriptAddProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
Definition OOJSScript.m:669
static NSData * CompiledScriptData(JSContext *context, JSScript *script)
Definition OOJSScript.m:766
static JSObject * sScriptPrototype
Definition OOJSScript.m:59
static RunningStack * sRunningStack
Definition OOJSScript.m:60
static JSFunctionSpec sScriptMethods[]
Definition OOJSScript.m:94
static JSClass sScriptClass
Definition OOJSScript.m:78
static JSScript * LoadScriptWithName(JSContext *context, NSString *path, JSObject *object, JSObject **outScriptObject, NSString **outErrorMessage)
Definition OOJSScript.m:697
static void AddStackToArrayReversed(NSMutableArray *array, RunningStack *stack)
Definition OOJSScript.m:687
static JSScript * ScriptWithCompiledData(JSContext *context, NSData *data)
Definition OOJSScript.m:791
id OOJSNativeObjectFromJSValue(JSContext *context, jsval value)
void OOJSReportWarning(JSContext *context, NSString *format,...)
JSBool OOJSObjectWrapperToString(JSContext *context, uintN argc, jsval *vp)
#define JS_IsInRequest(context)
NSString * OOStringFromJSID(jsid propID)
void OOJSRegisterObjectConverter(JSClass *theClass, OOJSClassConverterCallback converter)
OOINLINE jsval OOJSValueFromNativeObject(JSContext *context, id object)
void OOJSObjectWrapperFinalize(JSContext *context, JSObject *this)
JSBool OOJSUnconstructableConstruct(JSContext *context, uintN argc, jsval *vp)
#define OOJS_PROP_READONLY
OOINLINE JSContext * OOJSAcquireContext(void)
#define OOJSAddGCObjectRoot(context, root, name)
OOINLINE void OOJSRelinquishContext(JSContext *context)
id OOJSBasicPrivateObjectConverter(JSContext *context, JSObject *object)
id OOJSNativeObjectOfClassFromJSObject(JSContext *context, JSObject *object, Class requiredClass)
#define OOLogERR(class, format,...)
Definition OOLogging.h:112
#define OOLogOutdentIf(class)
Definition OOLogging.h:102
#define OOLog(class, format,...)
Definition OOLogging.h:88
#define OOLogIndentIf(class)
Definition OOLogging.h:101
static NSString *const kOOManifestLicense
static NSString *const kOOManifestIdentifier
static NSString *const kOOManifestVersion
static NSString *const kOOManifestAuthor
NSDictionary * OODictionaryFromFile(NSString *path)
return nil
void setObject:forKey:inCache:(id inElement,[forKey] NSString *inKey,[inCache] NSString *inCacheKey)
id objectForKey:inCache:(NSString *inKey,[inCache] NSString *inCacheKey)
OOCacheManager * sharedCache()
OOJavaScriptEngine * sharedEngine()
id weakRefWithObject:(id< OOWeakReferenceSupport > object)
RunningStack * back
Definition OOJSScript.m:54
OOJSScript * current
Definition OOJSScript.m:55