]> err.no Git - sope/blob - Recycler/NGJavaScript/NGJavaScriptObjCClassInfo.m
use %p for pointer formats
[sope] / Recycler / NGJavaScript / NGJavaScriptObjCClassInfo.m
1 /*
2   Copyright (C) 2000-2003 SKYRIX Software AG
3
4   This file is part of OGo
5
6   OGo is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with OGo; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21 // $Id$
22
23 #include "NGJavaScriptObjCClassInfo.h"
24 #include "NGJavaScriptObjectHandler.h"
25 #include <NGExtensions/NGObjCRuntime.h>
26 #include "globals.h"
27 #include "common.h"
28
29 #if 0
30 #  warning needs to be rewritten for tinyIds
31 #endif
32
33 @interface NGJavaScriptObjectHandler(Misc)
34 + (void *)jsStaticFuncDispatcher;
35 @end
36
37 #ifndef JSPROP_NOSLOT
38 // new in 1.5 rc3
39 #  define PROP_READONLY_FLAGS  (JSPROP_READONLY | JSPROP_SHARED)
40 #  define PROP_READWRITE_FLAGS (JSPROP_SHARED)
41 #else
42 // special version of 1.5 rc
43 #  define PROP_READONLY_FLAGS  (JSPROP_READONLY | JSPROP_NOSLOT)
44 #  define PROP_READWRITE_FLAGS (JSPROP_NOSLOT)
45 #endif
46 //#define PROP_READONLY_FLAGS  (JSPROP_READONLY | JSPROP_PERMANENT)
47
48 @implementation NGJavaScriptObjCClassInfo
49
50 - (id)initWithClass:(Class)_clazz
51   setter:(JSPropertyOp)_setter
52   getter:(JSPropertyOp)_getter
53   caller:(JSNative)_caller
54 {
55   NSEnumerator   *e;
56   NSString       *mname;
57   NSMutableArray *funcs;
58   NSMutableArray *props;
59   NSMutableArray *roProps;
60   
61   self->clazz  = _clazz;
62   self->setter = _setter;
63   self->getter = _getter;
64   self->caller = _caller;
65   
66   funcs = props = roProps = nil;
67   
68   self->idToKey = NSCreateMapTable(NSIntMapKeyCallBacks,
69                                    NSOwnedPointerMapValueCallBacks,
70                                    64);
71   
72   e = [_clazz hierachyMethodNameEnumerator];
73   while ((mname = [e nextObject])) {
74     if ([mname hasPrefix:@"_jsfunc_"]) {
75       NSString *f;
76       
77       if (funcs == nil)
78         funcs = [NSMutableArray arrayWithCapacity:64];
79
80       f = [mname substringFromIndex:8];
81       f = [f substringToIndex:([f length] - 1)];
82       
83       [funcs addObject:f];
84     }
85     else if ([mname hasPrefix:@"_jsprop_"] && ![mname hasSuffix:@":"]) {
86       char     *buf;
87       unsigned len;
88       NSString *propName;
89       SEL      setSel;
90       
91       len = [mname length];
92       buf = malloc(len + 3);
93       [mname getCString:buf];
94       
95       propName = [NSString stringWithCString:&(buf[8])];
96
97       /* get set-selector */
98       buf[len] = ':';
99       buf[len + 1] = '\0';
100 #if NeXT_RUNTIME || APPLE_RUNTIME
101       setSel = sel_getUid(buf);
102 #else
103       setSel = sel_get_uid(buf);
104 #endif
105
106       if ((setSel != NULL) && [_clazz instancesRespondToSelector:setSel]) {
107         if (props == nil)
108           props = [NSMutableArray arrayWithCapacity:64];
109         [props addObject:propName];
110       }
111       else {
112         if (roProps == nil)
113           roProps = [NSMutableArray arrayWithCapacity:64];
114         [roProps addObject:propName];
115       }
116     }
117   }
118   
119   self->jsFuncNames = [funcs copy];
120   self->jsPropNames = [props copy];
121   self->jsReadOnlyPropNames = [roProps copy];
122   
123   return self;
124 }
125
126 - (void)dealloc {
127   //NSLog(@"DEALLOC ClassInfo ..");
128
129 #if 0 // BUGGY, need to leak
130   if (self->funcSpecs) {
131     unsigned i;
132     
133     while (self->funcSpecs[i].name)
134       free((void *)self->funcSpecs[i].name);
135     
136     free(self->funcSpecs);
137   }
138   if (self->idToKey) {
139     NSFreeMapTable(self->idToKey);
140     self->idToKey = NULL;
141   }
142 #endif
143   [self->jsFuncNames         release];
144   [self->jsReadOnlyPropNames release];
145   [self->jsPropNames         release];
146   [super dealloc];
147 }
148
149 - (NSArray *)jsFuncNames {
150   return self->jsFuncNames;
151 }
152 - (NSArray *)jsPropNames {
153   return self->jsPropNames;
154 }
155 - (NSArray *)jsReadOnlyPropNames {
156   return self->jsReadOnlyPropNames;
157 }
158
159 - (JSFunctionSpec *)functionSpecs {
160   unsigned i, count;
161   
162   if (self->funcSpecs)
163     return self->funcSpecs;
164   
165   if ((count = [self->jsFuncNames count]) == 0)
166     return NULL;
167   
168   self->funcSpecs = calloc(count + 1, sizeof(JSFunctionSpec));
169   for (i = 0; i < count; i++) {
170     NSString *oname;
171     unsigned clen;
172     
173     oname = [self->jsFuncNames objectAtIndex:i];
174     clen  = [oname cStringLength];
175     
176     self->funcSpecs[i].name = malloc(clen + 4);
177     [oname getCString:(char *)self->funcSpecs[i].name];
178     
179     //NSLog(@"  def JS func '%s'\n", self->funcSpecs[i].name);
180     
181     self->tinyId++;
182     // TODO: explain the comment below
183     //***BUG: copy 'name'!
184     NSMapInsert(self->idToKey, (void*)(int)self->tinyId,
185                 self->funcSpecs[i].name);
186     
187     self->funcSpecs[i].call  = self->caller;
188     self->funcSpecs[i].nargs = 0;
189     self->funcSpecs[i].flags = 0;
190     self->funcSpecs[i].extra = 0;
191   }
192   return self->funcSpecs;
193 }
194
195 - (BOOL)isStaticProperty:(NSString *)_prop {
196   if ([self->jsFuncNames containsObject:_prop])
197     return YES;
198   if ([self->jsReadOnlyPropNames containsObject:_prop])
199     return YES;
200   if ([self->jsPropNames containsObject:_prop])
201     return YES;
202   return NO;
203 }
204
205 /* resolving IDs */
206
207 - (SEL)getSelectorForPropertyId:(void *)_idval inJSContext:(void *)_cx {
208   jsval      _id = *(jsval *)_idval;
209   const char *propName = NULL;
210   SEL        sel       = NULL;
211   
212   if (JSVAL_IS_STRING(_id)) {
213     if ((propName = JS_GetStringBytes(JS_ValueToString(_cx, _id))) == NULL)
214       NSLog(@"%s: got no string for string id val ..", __PRETTY_FUNCTION__);
215   }
216   else if (JSVAL_IS_INT(_id)) {
217     int ttid;
218     
219     ttid = JSVAL_TO_INT(_id);
220     if ((propName = NSMapGet(self->idToKey, (void*)(int)ttid)) == NULL)
221       NSLog(@"%s: got no INT id val %i ..", __PRETTY_FUNCTION__, ttid);
222   }
223   else {
224 #if DEBUG
225     NSLog(@"%s: GOT invalid id value ..", __PRETTY_FUNCTION__);
226     abort();
227 #else
228     NSLog(@"%s: GOT invalid id value ..", __PRETTY_FUNCTION__);
229     return NULL;
230 #endif
231   }
232   
233   if (propName) {
234     char *msgname;
235     
236     msgname = malloc(strlen(propName) + 12);
237     strcpy(msgname, "_jsprop_");
238     strcat(msgname, propName);
239 #if NeXT_RUNTIME
240     sel = sel_getUid(msgname);
241 #else
242     sel = sel_get_any_uid(msgname);
243 #endif
244     if (sel == NULL)
245       NSLog(@"%s: got no selector for msg '%s'", __PRETTY_FUNCTION__, msgname);
246     free(msgname);
247   }
248   return sel;
249 }
250 - (SEL)setSelectorForPropertyId:(void *)_idval inJSContext:(void *)_cx {
251   jsval      _id = *(jsval *)_idval;
252   const char *propName = NULL;
253   SEL        sel       = NULL;
254   
255   if (JSVAL_IS_STRING(_id)) {
256     if ((propName = JS_GetStringBytes(JS_ValueToString(_cx, _id))) == NULL)
257       NSLog(@"%s: got no string for string id val ..", __PRETTY_FUNCTION__);
258   }
259   else if (JSVAL_IS_INT(_id)) {
260     int ttid;
261     
262     ttid     = JSVAL_TO_INT(_id);
263     if ((propName = NSMapGet(self->idToKey, (void*)(int)ttid)) == NULL)
264       NSLog(@"%s: got no INT id val %i ..", __PRETTY_FUNCTION__, ttid);
265   }
266   else {
267 #if DEBUG
268     NSLog(@"%s: GOT invalid id value ..", __PRETTY_FUNCTION__);
269     abort();
270 #else
271     NSLog(@"%s: GOT invalid id value ..", __PRETTY_FUNCTION__);
272     return NULL;
273 #endif
274   }
275
276   if (propName) {
277     char *msgname;
278     
279     msgname = malloc(strlen(propName) + 12);
280     strcpy(msgname, "_jsprop_");
281     strcat(msgname, propName);
282     strcat(msgname, ":");
283
284 #if NeXT_RUNTIME
285     sel = sel_getUid(msgname);
286 #else
287     sel = sel_get_any_uid(msgname);
288 #endif
289     if (sel == NULL)
290       NSLog(@"%s: got no selector for msg '%s'", __PRETTY_FUNCTION__, msgname);
291     free(msgname);
292   }
293   
294   return sel;
295 }
296
297 /* apply on JSObject */
298
299 - (unsigned char)tinyIdForKey:(NSString *)_key {
300   char *ckey;
301   
302   self->tinyId++;
303   ckey = malloc([_key cStringLength] + 1);
304   [_key getCString:ckey];
305   NSMapInsert(self->idToKey, (void*)(int)self->tinyId, ckey);
306   
307   return self->tinyId;
308 }
309
310 - (JSBool)defineProperty:(NSString *)mname readOnly:(BOOL)_ro
311   onObject:(void *)_jso inJSContext:(void *)_cx
312 {
313   JSBool ret;
314   
315   if (NGJavaScriptBridge_LOG_PROP_DEFINITION) {
316     NSLog(@"%s: definition of %@ property '%@' on j0x%p",
317           __PRETTY_FUNCTION__, _ro ? @"ro/noslot" : @"rw/noslot", 
318           mname, _jso);
319   }
320
321 #if WITH_TINY_ID
322   ret = JS_DefinePropertyWithTinyId(_cx, _jso,
323                                     [mname cString],
324                                     [self tinyIdForKey:mname],
325                                     JSVAL_NULL,
326                                     self->getter, ro ? NULL : self->setter,
327                                     _ro ? PROP_READONLY_FLAGS : PROP_READWRITE_FLAGS);
328 #else
329   ret = JS_DefineProperty(_cx, _jso,
330                           [mname cString],
331                           JSVAL_NULL,
332                           self->getter, _ro ? NULL : self->setter,
333                           _ro ? PROP_READONLY_FLAGS : PROP_READWRITE_FLAGS);
334 #endif
335   return ret;
336 }
337
338 - (BOOL)applyOnJSObject:(void *)_jso inJSContext:(void *)_cx {
339   NSEnumerator *mnames;
340   NSString     *mname;
341   JSFunctionSpec *fspecs;
342   
343   if ((fspecs = [self functionSpecs])) {  
344     if (!JS_DefineFunctions(_cx, _jso, fspecs)) {
345       NSLog(@"ERROR(%s): couldn't define static JS functions (0x%p) on "
346             @"JSObject 0x%p in JSContext 0x%p ..", 
347             __PRETTY_FUNCTION__, fspecs, _jso, _cx);
348       return NO;
349     }
350   }
351   
352   mnames = [[self jsPropNames] objectEnumerator];
353   while ((mname = [mnames nextObject])) {
354     JSBool ret;
355     
356     ret = [self defineProperty:mname readOnly:NO 
357                 onObject:_jso inJSContext:_cx];
358     if (!ret) {
359       NSLog(@"ERROR(%s): couldn't define property '%@' on "
360             @"JSObject 0x%p in JSContext 0x%p", 
361             __PRETTY_FUNCTION__, mname, _jso, _cx);
362       continue;
363     }
364   }
365   
366   mnames = [[self jsReadOnlyPropNames] objectEnumerator];
367   while ((mname = [mnames nextObject])) {
368     JSBool ret;
369     
370     ret = [self defineProperty:mname readOnly:YES
371                 onObject:_jso inJSContext:_cx];
372     if (!ret)
373       continue;
374   }
375
376   return YES;
377 }
378
379 @end /* NGJavaScriptObjCClassInfo */