17 classVariableNames:'' |
17 classVariableNames:'' |
18 poolDictionaries:'' |
18 poolDictionaries:'' |
19 category:'System-Support' |
19 category:'System-Support' |
20 ! |
20 ! |
21 |
21 |
|
22 !ExternalLibraryFunction primitiveDefinitions! |
|
23 %{ |
|
24 # include <ffi.h> |
|
25 |
|
26 # define MAX_ARGS 128 |
|
27 |
|
28 # define STX_FFI_TYPE_VOID 0 |
|
29 # define STX_FFI_TYPE_INT 1 |
|
30 # define STX_FFI_TYPE_FLOAT 2 |
|
31 # define STX_FFI_TYPE_DOUBLE 3 |
|
32 # define STX_FFI_TYPE_LONGDOUBLE 4 |
|
33 # define STX_FFI_TYPE_UINT8 5 |
|
34 # define STX_FFI_TYPE_SINT8 6 |
|
35 # define STX_FFI_TYPE_UINT16 7 |
|
36 # define STX_FFI_TYPE_SINT16 8 |
|
37 # define STX_FFI_TYPE_UINT32 9 |
|
38 # define STX_FFI_TYPE_SINT32 10 |
|
39 # define STX_FFI_TYPE_UINT64 11 |
|
40 # define STX_FFI_TYPE_SINT64 12 |
|
41 # define STX_FFI_TYPE_STRUCT 0x10000 /* + size */ |
|
42 # define STX_FFI_TYPE_STRUCT_SIZE_MASK 0x0FFFF /* size mask */ |
|
43 # define STX_FFI_TYPE_POINTER 13 |
|
44 |
|
45 %} |
|
46 ! ! |
|
47 |
22 !ExternalLibraryFunction class methodsFor:'documentation'! |
48 !ExternalLibraryFunction class methodsFor:'documentation'! |
23 |
49 |
24 copyright |
50 copyright |
25 " |
51 " |
26 COPYRIGHT (c) 2004 by eXept Software AG |
52 COPYRIGHT (c) 2004 by eXept Software AG |
27 All Rights Reserved |
53 All Rights Reserved |
28 |
54 |
29 This software is furnished under a license and may be used |
55 This software is furnished under a license and may be used |
30 only in accordance with the terms of that license and with the |
56 only in accordance with the terms of that license and with the |
31 inclusion of the above copyright notice. This software may not |
57 inclusion of the above copyright notice. This software may not |
32 be provided or otherwise made available to, or used by, any |
58 be provided or otherwise made available to, or used by, any |
33 other person. No title to or ownership of the software is |
59 other person. No title to or ownership of the software is |
34 hereby transferred. |
60 hereby transferred. |
35 " |
61 " |
|
62 ! |
|
63 |
|
64 example |
|
65 " |
|
66 |f| |
|
67 |
|
68 f := ExternalLibraryFunction new. |
|
69 f name:'MessageBeep' |
|
70 module:'user32.dll' |
|
71 callType:#WINAPI |
|
72 returnType:#boolean |
|
73 argumentTypes:#(uint). |
|
74 |
|
75 f invokeWith:1. |
|
76 " |
36 ! ! |
77 ! ! |
37 |
78 |
38 !ExternalLibraryFunction class methodsFor:'instance creation'! |
79 !ExternalLibraryFunction class methodsFor:'instance creation'! |
39 |
80 |
40 name:functionName module:moduleName callType:callType |
81 name:functionName module:moduleName callType:callType |
41 returnType:returnType argumentTypes:argTypes |
82 returnType:returnType argumentTypes:argTypes |
42 ^ self new |
83 ^ self new |
43 name:functionName module:moduleName callType:callType |
84 name:functionName module:moduleName callType:callType |
44 returnType:returnType argumentTypes:argTypes |
85 returnType:returnType argumentTypes:argTypes |
45 ! ! |
86 ! ! |
46 |
87 |
47 !ExternalLibraryFunction class methodsFor:'constants'! |
88 !ExternalLibraryFunction class methodsFor:'constants'! |
48 |
89 |
49 callTypeAPI |
90 callTypeAPI |
70 |
111 |
71 !ExternalLibraryFunction methodsFor:'invoking'! |
112 !ExternalLibraryFunction methodsFor:'invoking'! |
72 |
113 |
73 invoke |
114 invoke |
74 self hasCode ifFalse:[ |
115 self hasCode ifFalse:[ |
75 self prepareInvoke. |
116 self prepareInvoke. |
76 ]. |
117 ]. |
77 ^ self invokeFFIWithArguments:#() |
118 ^ self invokeFFIWithArguments:#() |
78 ! |
119 ! |
79 |
120 |
80 invokeWith:arg |
121 invokeWith:arg |
81 self hasCode ifFalse:[ |
122 self hasCode ifFalse:[ |
82 self prepareInvoke. |
123 self prepareInvoke. |
83 ]. |
124 ]. |
84 ^ self invokeFFIWithArguments:(Array with:arg) |
125 ^ self invokeFFIWithArguments:(Array with:arg) |
85 ! |
126 ! |
86 |
127 |
87 invokeWith:arg1 with:arg2 |
128 invokeWith:arg1 with:arg2 |
88 self hasCode ifFalse:[ |
129 self hasCode ifFalse:[ |
89 self prepareInvoke. |
130 self prepareInvoke. |
90 ]. |
131 ]. |
91 ^ self invokeFFIWithArguments:(Array with:arg1 with:arg2) |
132 ^ self invokeFFIWithArguments:(Array with:arg1 with:arg2) |
92 ! |
133 ! |
93 |
134 |
94 invokeWith:arg1 with:arg2 with:arg3 |
135 invokeWith:arg1 with:arg2 with:arg3 |
95 self hasCode ifFalse:[ |
136 self hasCode ifFalse:[ |
96 self prepareInvoke. |
137 self prepareInvoke. |
97 ]. |
138 ]. |
98 ^ self invokeFFIWithArguments:(Array with:arg1 with:arg2 with:arg3) |
139 ^ self invokeFFIWithArguments:(Array with:arg1 with:arg2 with:arg3) |
99 ! |
140 ! |
100 |
141 |
101 invokeWith:arg1 with:arg2 with:arg3 with:arg4 |
142 invokeWith:arg1 with:arg2 with:arg3 with:arg4 |
102 self hasCode ifFalse:[ |
143 self hasCode ifFalse:[ |
103 self prepareInvoke. |
144 self prepareInvoke. |
104 ]. |
145 ]. |
105 ^ self invokeFFIWithArguments:(Array with:arg1 with:arg2 with:arg3 with:arg4) |
146 ^ self invokeFFIWithArguments:(Array with:arg1 with:arg2 with:arg3 with:arg4) |
106 ! |
147 ! |
107 |
148 |
108 invokeWithArguments:argArray |
149 invokeWithArguments:argArray |
109 self hasCode ifFalse:[ |
150 self hasCode ifFalse:[ |
110 self prepareInvoke. |
151 self prepareInvoke. |
111 ]. |
152 ]. |
112 ^ self invokeFFIWithArguments:argArray |
153 ^ self invokeFFIWithArguments:argArray |
113 ! ! |
154 ! ! |
114 |
155 |
115 !ExternalLibraryFunction methodsFor:'printing'! |
156 !ExternalLibraryFunction methodsFor:'printing'! |
125 ! ! |
166 ! ! |
126 |
167 |
127 !ExternalLibraryFunction methodsFor:'private'! |
168 !ExternalLibraryFunction methodsFor:'private'! |
128 |
169 |
129 invokeFFIWithArguments:arguments |
170 invokeFFIWithArguments:arguments |
130 |ffiArgTypes failureCode| |
171 |argTypeSymbols returnTypeSymbol failureCode| |
131 |
172 |
132 argumentTypes notNil ifTrue:[ |
173 argumentTypes notNil ifTrue:[ |
133 ffiArgTypes := argumentTypes collect:[:argType | self ffiArgTypeForType:argType]. |
174 argTypeSymbols := argumentTypes collect:[:argType | self ffiTypeSymbolForType:argType]. |
134 ]. |
175 ]. |
135 %{ |
176 returnTypeSymbol := self ffiTypeSymbolForType:returnType. |
136 #if defined(i386) |
177 |
137 # ifndef STX_FFI_TYPE_VOID |
178 %{ |
138 # define STX_FFI_TYPE_VOID 0 |
179 ffi_type *argTypes[MAX_ARGS]; |
139 # define STX_FFI_TYPE_INT 1 |
180 union { |
140 # define STX_FFI_TYPE_FLOAT 2 |
181 int iVal; |
141 # define STX_FFI_TYPE_DOUBLE 3 |
182 } argValues[MAX_ARGS]; |
142 # define STX_FFI_TYPE_LONGDOUBLE 4 |
183 void *argValuePointers[MAX_ARGS]; |
143 # define STX_FFI_TYPE_UINT8 5 |
|
144 # define STX_FFI_TYPE_SINT8 6 |
|
145 # define STX_FFI_TYPE_UINT16 7 |
|
146 # define STX_FFI_TYPE_SINT16 8 |
|
147 # define STX_FFI_TYPE_UINT32 9 |
|
148 # define STX_FFI_TYPE_SINT32 10 |
|
149 # define STX_FFI_TYPE_UINT64 11 |
|
150 # define STX_FFI_TYPE_SINT64 12 |
|
151 # define STX_FFI_TYPE_STRUCT 13 |
|
152 # define STX_FFI_TYPE_POINTER 14 |
|
153 |
|
154 # define MAX_NUMARGS 128 |
|
155 typedef void * ffi_type; |
|
156 # endif |
|
157 |
|
158 void *argValues[MAX_NUMARGS]; |
|
159 ffi_type *argtypes[MAX_NUMARGS]; |
|
160 int numArgs; |
184 int numArgs; |
161 int i; |
185 int i; |
|
186 static int null = 0; |
162 |
187 |
163 if (arguments == nil) { |
188 if (arguments == nil) { |
164 numArgs = 0; |
189 numArgs = 0; |
165 if (ffiArgTypes != nil) { |
190 if (argTypeSymbols != nil) { |
166 if (! __isArray(ffiArgTypes)) goto error; |
191 if (! __isArray(argTypeSymbols)) goto error; |
167 if (__arraySize(ffiArgTypes) != numArgs) goto error; |
192 if (__arraySize(argTypeSymbols) != numArgs) goto error; |
168 } |
193 } |
169 } else { |
194 } else { |
170 if (! __isArray(arguments)) goto error; |
195 if (! __isArray(arguments)) goto error; |
171 numArgs = __arraySize(arguments); |
196 numArgs = __arraySize(arguments); |
172 if (! __isArray(ffiArgTypes)) goto error; |
197 if (! __isArray(argTypeSymbols)) goto error; |
173 if (__arraySize(ffiArgTypes) != numArgs) goto error; |
198 if (__arraySize(argTypeSymbols) != numArgs) goto error; |
174 } |
199 } |
175 if (numArgs > MAX_NUMARGS) { |
200 if (numArgs > MAX_ARGS) { |
176 failureCode = @symbol(TooManyArguments); |
201 failureCode = @symbol(TooManyArguments); |
177 goto error; |
202 goto error; |
178 } |
203 } |
|
204 |
179 for (i=0; i<numArgs; i++) { |
205 for (i=0; i<numArgs; i++) { |
180 switch (__intVal( __ArrayInstPtr(ffiArgTypes)->a_element[i]) ) { |
206 ffi_type *argType; |
181 case STX_FFI_TYPE_VOID: |
207 void *argValuePtr; |
182 case STX_FFI_TYPE_INT: |
208 OBJ typeSymbol; |
183 case STX_FFI_TYPE_FLOAT: |
209 |
184 case STX_FFI_TYPE_DOUBLE: |
210 typeSymbol = __ArrayInstPtr(argTypeSymbols)->a_element[i]; |
185 case STX_FFI_TYPE_LONGDOUBLE: |
211 if (typeSymbol == @symbol(int)) { |
186 case STX_FFI_TYPE_UINT8: |
212 } else if (typeSymbol == @symbol(void)) { |
187 case STX_FFI_TYPE_SINT8: |
213 #if 0 |
188 case STX_FFI_TYPE_UINT16: |
214 argType = &ffi_type_void; |
189 case STX_FFI_TYPE_SINT16: |
215 #endif |
190 case STX_FFI_TYPE_UINT32: |
216 argValuePtr = &null; |
191 case STX_FFI_TYPE_SINT32: |
217 } else { |
192 case STX_FFI_TYPE_UINT64: |
218 failureCode = @symbol(UnknownArgumentType); |
193 case STX_FFI_TYPE_SINT64: |
219 goto error; |
194 case STX_FFI_TYPE_STRUCT: |
|
195 case STX_FFI_TYPE_POINTER: |
|
196 default: |
|
197 failureCode = @symbol(UnknownArgumentType); |
|
198 goto error; |
|
199 } |
220 } |
|
221 |
|
222 argTypes[i] = argType; |
|
223 argValuePointers[i] = argValuePtr; |
200 } |
224 } |
201 |
225 |
202 #else |
226 # if 0 |
|
227 /* Initialize the cif */ |
|
228 CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, |
|
229 &ffi_type_sint64, args) == FFI_OK); |
|
230 |
203 argtypes = (ffi_type **)C_alloca(sizeof(ffi_type *) * (n + 3)); |
231 argtypes = (ffi_type **)C_alloca(sizeof(ffi_type *) * (n + 3)); |
204 argvalues = (void **)C_alloca(sizeof(void *) * (n + 3)); |
232 argvalues = (void **)C_alloca(sizeof(void *) * (n + 3)); |
205 argtypes[ 0 ] = &ffi_type_pointer; |
233 argtypes[ 0 ] = &ffi_type_pointer; |
206 argtypes[ 1 ] = &ffi_type_pointer; |
234 argtypes[ 1 ] = &ffi_type_pointer; |
207 argtypes[ 2 ] = &ffi_type_pointer; |
235 argtypes[ 2 ] = &ffi_type_pointer; |
229 I.e. retrieve the module handle and the code pointer." |
258 I.e. retrieve the module handle and the code pointer." |
230 |
259 |
231 |handle code| |
260 |handle code| |
232 |
261 |
233 moduleName isNil ifTrue:[ |
262 moduleName isNil ifTrue:[ |
234 self error:'Missing moduleName'. |
263 self error:'Missing moduleName'. |
235 ]. |
264 ]. |
236 |
265 |
237 handle := ObjectFileLoader loadDynamicObject:moduleName. |
266 handle := ObjectFileLoader loadDynamicObject:moduleName. |
238 handle isNil ifTrue:[ |
267 handle isNil ifTrue:[ |
239 self error:'Cannot load module: ', moduleName. |
268 self error:'Cannot load module: ', moduleName. |
240 ]. |
269 ]. |
241 moduleHandle := handle. |
270 moduleHandle := handle. |
242 code := moduleHandle getFunctionAddress:name into:self. |
271 code := moduleHandle getFunctionAddress:name into:self. |
243 code isNil ifTrue:[ |
272 code isNil ifTrue:[ |
244 self error:'Missing function: ', name, ' in module: ', moduleName. |
273 self error:'Missing function: ', name, ' in module: ', moduleName. |
245 ]. |
274 ]. |
246 ! |
275 ! |
247 |
276 |
248 prepareInvoke |
277 prepareInvoke |
249 self hasCode ifFalse:[ |
278 self hasCode ifFalse:[ |
250 moduleHandle isNil ifTrue:[ |
279 moduleHandle isNil ifTrue:[ |
251 self linkToModule. |
280 self linkToModule. |
252 self setupFFI. |
281 self setupFFI. |
253 ]. |
282 ]. |
254 ]. |
283 ]. |
255 ! |
284 ! |
256 |
285 |
257 setupFFI |
286 setupFFI |
258 "setup foreign function interface" |
287 "setup foreign function interface" |
259 |
288 |
260 "/ %{ |
289 "/ %{ |
261 "/ #if defined(WIN32) && defined(i386) |
290 "/ #if defined(WIN32) && defined(i386) |
262 "/ /* Have special code for this case - no need to use of ffi code. */ |
291 "/ /* Have special code for this case - no need to use of ffi code. */ |
263 "/ #else |
292 "/ #else |
264 "/ if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_uint, args)) != FFI_OK) |
293 "/ if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_uint, args)) |
265 "/ #endif |
|
266 "/ %} |
|
267 ! ! |
294 ! ! |
268 |
295 |
269 !ExternalLibraryFunction methodsFor:'private-accessing'! |
296 !ExternalLibraryFunction methodsFor:'private-accessing'! |
270 |
297 |
271 name:functionName module:aModuleName callType:aCallType returnType:aReturnType argumentTypes:argTypes |
298 STX_FFI_TYPE_DOUBLE |
|
299 %{ |
|
300 RETURN(__MKSMALLINT(STX_FFI_TYPE_DOUBLE)); |
|
301 %}. |
|
302 |
|
303 " |
|
304 self new STX_FFI_TYPE_DOUBLE |
|
305 " |
|
306 ! |
|
307 |
|
308 STX_FFI_TYPE_FLOAT |
|
309 %{ |
|
310 RETURN(__MKSMALLINT(STX_FFI_TYPE_FLOAT)); |
|
311 %}. |
|
312 |
|
313 " |
|
314 self new STX_FFI_TYPE_FLOAT |
|
315 " |
|
316 ! |
|
317 |
|
318 STX_FFI_TYPE_LONGDOUBLE |
|
319 %{ |
|
320 RETURN(__MKSMALLINT(STX_FFI_TYPE_LONGDOUBLE)); |
|
321 %}. |
|
322 |
|
323 " |
|
324 self new STX_FFI_TYPE_LONGDOUBLE |
|
325 " |
|
326 ! |
|
327 |
|
328 STX_FFI_TYPE_POINTER |
|
329 %{ |
|
330 RETURN(__MKSMALLINT(STX_FFI_TYPE_POINTER)); |
|
331 %}. |
|
332 |
|
333 " |
|
334 self new STX_FFI_TYPE_POINTER |
|
335 " |
|
336 ! |
|
337 |
|
338 STX_FFI_TYPE_SINT |
|
339 %{ |
|
340 #if sizeof(int) == 4 |
|
341 RETURN(__MKSMALLINT(STX_FFI_TYPE_SINT32)); |
|
342 #endif |
|
343 #if sizeof(int) == 8 |
|
344 RETURN(__MKSMALLINT(STX_FFI_TYPE_SINT64)); |
|
345 #endif |
|
346 %}. |
|
347 self primitiveFailed |
|
348 |
|
349 " |
|
350 self new STX_FFI_TYPE_SINT |
|
351 " |
|
352 ! |
|
353 |
|
354 STX_FFI_TYPE_SINT16 |
|
355 %{ |
|
356 RETURN(__MKSMALLINT(STX_FFI_TYPE_SINT16)); |
|
357 %}. |
|
358 |
|
359 " |
|
360 self new STX_FFI_TYPE_SINT16 |
|
361 " |
|
362 ! |
|
363 |
|
364 STX_FFI_TYPE_SINT32 |
|
365 %{ |
|
366 RETURN(__MKSMALLINT(STX_FFI_TYPE_SINT32)); |
|
367 %}. |
|
368 |
|
369 " |
|
370 self new STX_FFI_TYPE_SINT32 |
|
371 " |
|
372 ! |
|
373 |
|
374 STX_FFI_TYPE_SINT64 |
|
375 %{ |
|
376 RETURN(__MKSMALLINT(STX_FFI_TYPE_SINT64)); |
|
377 %}. |
|
378 |
|
379 " |
|
380 self new STX_FFI_TYPE_SINT64 |
|
381 " |
|
382 ! |
|
383 |
|
384 STX_FFI_TYPE_SINT8 |
|
385 %{ |
|
386 RETURN(__MKSMALLINT(STX_FFI_TYPE_SINT8)); |
|
387 %}. |
|
388 |
|
389 " |
|
390 self new STX_FFI_TYPE_SINT8 |
|
391 " |
|
392 ! |
|
393 |
|
394 STX_FFI_TYPE_STRUCT |
|
395 %{ |
|
396 RETURN(__MKSMALLINT(STX_FFI_TYPE_STRUCT)); |
|
397 %}. |
|
398 |
|
399 " |
|
400 self new STX_FFI_TYPE_STRUCT |
|
401 " |
|
402 ! |
|
403 |
|
404 STX_FFI_TYPE_STRUCT:size |
|
405 ^ self STX_FFI_TYPE_STRUCT + size |
|
406 |
|
407 " |
|
408 self new STX_FFI_TYPE_STRUCT:0 |
|
409 self new STX_FFI_TYPE_STRUCT:16 |
|
410 " |
|
411 ! |
|
412 |
|
413 STX_FFI_TYPE_UINT |
|
414 %{ |
|
415 #if sizeof(int) == 4 |
|
416 RETURN(__MKSMALLINT(STX_FFI_TYPE_UINT32)); |
|
417 #endif |
|
418 #if sizeof(int) == 8 |
|
419 RETURN(__MKSMALLINT(STX_FFI_TYPE_UINT64)); |
|
420 #endif |
|
421 %}. |
|
422 self primitiveFailed |
|
423 |
|
424 " |
|
425 self new STX_FFI_TYPE_UINT |
|
426 " |
|
427 ! |
|
428 |
|
429 STX_FFI_TYPE_UINT16 |
|
430 %{ |
|
431 RETURN(__MKSMALLINT(STX_FFI_TYPE_UINT16)); |
|
432 %}. |
|
433 |
|
434 " |
|
435 self new STX_FFI_TYPE_UINT16 |
|
436 " |
|
437 ! |
|
438 |
|
439 STX_FFI_TYPE_UINT64 |
|
440 %{ |
|
441 RETURN(__MKSMALLINT(STX_FFI_TYPE_UINT64)); |
|
442 %}. |
|
443 |
|
444 " |
|
445 self new STX_FFI_TYPE_UINT64 |
|
446 " |
|
447 ! |
|
448 |
|
449 STX_FFI_TYPE_UINT8 |
|
450 %{ |
|
451 RETURN(__MKSMALLINT(STX_FFI_TYPE_UINT8)); |
|
452 %}. |
|
453 |
|
454 " |
|
455 self new STX_FFI_TYPE_UINT8 |
|
456 " |
|
457 ! |
|
458 |
|
459 STX_FFI_TYPE_VOID |
|
460 %{ |
|
461 RETURN(__MKSMALLINT(STX_FFI_TYPE_VOID)); |
|
462 %} |
|
463 |
|
464 " |
|
465 self new STX_FFI_TYPE_VOID |
|
466 " |
|
467 ! |
|
468 |
|
469 ffiTypeForType:aType |
|
470 "/ kludge |
|
471 |
|
472 aType isSymbol ifTrue:[ |
|
473 "/ for those who do not have the CType package... |
|
474 aType == #int ifTrue:[ ^ self STX_FFI_TYPE_INT ]. |
|
475 aType == #uint ifTrue:[ ^ self STX_FFI_TYPE_UINT ]. |
|
476 aType == #short ifTrue:[ ^ self STX_FFI_TYPE_SHORT ]. |
|
477 aType == #ushort ifTrue:[ ^ self STX_FFI_TYPE_USHORT ]. |
|
478 aType == #long ifTrue:[ ^ self STX_FFI_TYPE_LONG ]. |
|
479 aType == #ulong ifTrue:[ ^ self STX_FFI_TYPE_ULONG ]. |
|
480 aType == #float ifTrue:[ ^ self STX_FFI_TYPE_FLOAT ]. |
|
481 aType == #double ifTrue:[ ^ self STX_FFI_TYPE_DOUBLE ]. |
|
482 aType == #void ifTrue:[ ^ self STX_FFI_TYPE_VOID ]. |
|
483 self error:'unknown type'. |
|
484 ]. |
|
485 self error:'unknown type'. |
|
486 ! |
|
487 |
|
488 ffiTypeSymbolForType:aType |
|
489 "/ kludge for those who do not have the CType package... |
|
490 aType isSymbol ifTrue:[ ^ aType ]. |
|
491 CType isNil ifTrue:[ |
|
492 self error:'unknown type'. |
|
493 ]. |
|
494 ^ aType typeSymbol |
|
495 ! |
|
496 |
|
497 name:functionName module:aModuleName callType:aCallType returnType:aReturnType argumentTypes:argTypes |
272 name := functionName. |
498 name := functionName. |
273 moduleName := aModuleName. |
499 moduleName := aModuleName. |
274 callType := aCallType. |
500 callType := aCallType. |
275 returnType := aReturnType. |
501 returnType := aReturnType. |
276 argumentTypes := argTypes. |
502 argumentTypes := argTypes. |
277 ! ! |
503 ! ! |
278 |
504 |
279 !ExternalLibraryFunction class methodsFor:'documentation'! |
505 !ExternalLibraryFunction class methodsFor:'documentation'! |
280 |
506 |
281 version |
507 version |
282 ^ '$Header: /cvs/stx/stx/libbasic/ExternalLibraryFunction.st,v 1.5 2006-04-24 08:49:16 cg Exp $' |
508 ^ '$Header: /cvs/stx/stx/libbasic/ExternalLibraryFunction.st,v 1.6 2006-04-25 10:33:27 cg Exp $' |
283 ! ! |
509 ! ! |