1 |
/* |
2 |
ASCEND modelling environment |
3 |
Copyright (C) 1990, 1993, 1994 Thomas Guthrie Epperly, Kirk Andre Abbott |
4 |
Copyright (C) 2006 Carnegie Mellon University |
5 |
|
6 |
This program is free software; you can redistribute it and/or modify |
7 |
it under the terms of the GNU General Public License as published by |
8 |
the Free Software Foundation; either version 2, or (at your option) |
9 |
any later version. |
10 |
|
11 |
This program is distributed in the hope that it will be useful, |
12 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
GNU General Public License for more details. |
15 |
|
16 |
You should have received a copy of the GNU General Public License |
17 |
along with this program; if not, write to the Free Software |
18 |
Foundation, Inc., 59 Temple Place - Suite 330, |
19 |
Boston, MA 02111-1307, USA. |
20 |
*//* |
21 |
by Kirk Andre Abbott |
22 |
Created: July 4, 1994. |
23 |
Last in CVS: $Revision: 1.8 $ $Date: 1998/02/05 22:23:26 $ $Author: ballan $ |
24 |
*/ |
25 |
|
26 |
#include <utilities/ascConfig.h> |
27 |
#include <utilities/ascMalloc.h> |
28 |
#include <utilities/ascPanic.h> |
29 |
#include <general/hashpjw.h> |
30 |
#include <general/list.h> |
31 |
#include <general/table.h> |
32 |
#include <general/dstring.h> |
33 |
#include "compiler.h" |
34 |
#include "symtab.h" |
35 |
#include "instance_enum.h" |
36 |
#include "instance_io.h" |
37 |
#include "extfunc.h" |
38 |
#include "extcall.h" |
39 |
#include "atomvalue.h" |
40 |
|
41 |
/*------------------------------------------------------------------------------ |
42 |
forward decls and typedefs etc |
43 |
*/ |
44 |
|
45 |
#define EXTFUNCHASHSIZE 31 |
46 |
|
47 |
static struct Table *ExternalFuncLibrary = NULL; |
48 |
|
49 |
/*----------------------------------------------------------------------------- |
50 |
BLACK BOX STUFF |
51 |
*/ |
52 |
|
53 |
int CreateUserFunctionBlackBox(CONST char *name, |
54 |
ExtBBoxInitFunc *init, |
55 |
ExtBBoxFunc *value, |
56 |
ExtBBoxFunc *deriv, |
57 |
ExtBBoxFunc *deriv2, |
58 |
ExtBBoxInitFunc *final, |
59 |
CONST unsigned long n_inputs, |
60 |
CONST unsigned long n_outputs, |
61 |
CONST char *help) |
62 |
{ |
63 |
struct ExternalFunc *efunc; |
64 |
int isNew = 0; |
65 |
if (name == NULL) { |
66 |
return 1; |
67 |
} |
68 |
efunc = LookupExtFunc(name); |
69 |
if (efunc != NULL) { |
70 |
CONSOLE_DEBUG("Found efunc at %p",efunc); |
71 |
/* name was pre-loaded -- just update the info */ |
72 |
isNew = 0; |
73 |
}else{ |
74 |
isNew = 1; |
75 |
efunc = ASC_NEW(struct ExternalFunc); |
76 |
asc_assert(efunc!=NULL); |
77 |
efunc->help = NULL; |
78 |
efunc->name = ascstrdup(SCP(AddSymbol(name))); |
79 |
CONSOLE_DEBUG("Created new efunc at %p",efunc); |
80 |
/* add or find name in symbol table */ |
81 |
/* the main symtab owns the string */ |
82 |
} |
83 |
|
84 |
efunc->etype = efunc_BlackBox; |
85 |
efunc->n_inputs = n_inputs; |
86 |
efunc->n_outputs = n_outputs; |
87 |
efunc->u.black.initial = init; |
88 |
efunc->u.black.value = value; |
89 |
efunc->u.black.deriv = deriv; |
90 |
efunc->u.black.deriv2 = deriv2; |
91 |
efunc->u.black.final = final; |
92 |
if (help) { |
93 |
if (efunc->help) ascfree((char *)efunc->help); |
94 |
efunc->help = ascstrdup(help); |
95 |
} else { |
96 |
efunc->help = NULL; |
97 |
} |
98 |
|
99 |
if (isNew) { |
100 |
CONSOLE_DEBUG("NEW BLACKBOX EFUNC %p ('%s', %lu inputs, %lu outputs, type=%d)" |
101 |
,efunc, name, n_inputs, n_outputs, (int)efunc->etype |
102 |
); |
103 |
(void)AddExternalFunc(efunc,1); |
104 |
} |
105 |
return 0; |
106 |
} |
107 |
|
108 |
|
109 |
ExtBBoxInitFunc * GetInitFunc(struct ExternalFunc *efunc) |
110 |
{ |
111 |
asc_assert(efunc!=NULL); |
112 |
/* return (ExtBBoxInitFunc*)efunc->u.black.init; */ |
113 |
return efunc->u.black.initial; |
114 |
} |
115 |
|
116 |
ExtBBoxInitFunc * GetFinalFunc(struct ExternalFunc *efunc) |
117 |
{ |
118 |
asc_assert(efunc!=NULL); |
119 |
return efunc->u.black.final; |
120 |
} |
121 |
|
122 |
ExtBBoxFunc *GetValueFunc(struct ExternalFunc *efunc) |
123 |
{ |
124 |
asc_assert(efunc!=NULL); |
125 |
AssertMemory(efunc->etype); |
126 |
|
127 |
CONSOLE_DEBUG("GETVALUEFUNC efunc = %p, type = %d",efunc,(int)efunc->etype); |
128 |
asc_assert(efunc->etype == efunc_BlackBox); |
129 |
/* return (ExtBBoxFunc *)efunc->value; */ |
130 |
return efunc->u.black.value; |
131 |
} |
132 |
|
133 |
|
134 |
ExtBBoxFunc *GetDerivFunc(struct ExternalFunc *efunc) |
135 |
{ |
136 |
asc_assert(efunc!=NULL); |
137 |
asc_assert(efunc->etype == efunc_BlackBox); |
138 |
return efunc->u.black.deriv; |
139 |
} |
140 |
|
141 |
ExtBBoxFunc *GetDeriv2Func(struct ExternalFunc *efunc) |
142 |
{ |
143 |
asc_assert(efunc!=NULL); |
144 |
asc_assert(efunc->etype == efunc_BlackBox); |
145 |
return efunc->u.black.deriv2; |
146 |
} |
147 |
|
148 |
/*------------------------------------------------------------------------------ |
149 |
GLASS BOX STUFF |
150 |
*/ |
151 |
|
152 |
int CreateUserFunctionGlassBox(CONST char *name, |
153 |
ExtEvalFunc *init, |
154 |
ExtEvalFunc **value, |
155 |
ExtEvalFunc **deriv, |
156 |
ExtEvalFunc **deriv2, |
157 |
ExtEvalFunc *final, |
158 |
CONST unsigned long n_inputs, |
159 |
CONST unsigned long n_outputs, |
160 |
CONST char *help) |
161 |
{ |
162 |
struct ExternalFunc *efunc; |
163 |
int isNew = 0; |
164 |
if (name == NULL) { |
165 |
return 1; |
166 |
} |
167 |
efunc = LookupExtFunc(name); |
168 |
if (efunc != NULL) { /* name was pre-loaded -- just update the info */ |
169 |
isNew = 0; |
170 |
} else { |
171 |
isNew = 1; |
172 |
efunc = ASC_NEW(struct ExternalFunc); |
173 |
asc_assert(efunc!=NULL); |
174 |
efunc->help = NULL; |
175 |
efunc->name = ascstrdup(SCP(AddSymbol(name))); |
176 |
/* add or find name in symbol table */ |
177 |
/* the main symtab owns the string */ |
178 |
} |
179 |
|
180 |
efunc->etype = efunc_GlassBox; |
181 |
efunc->n_inputs = n_inputs; |
182 |
efunc->n_outputs = n_outputs; |
183 |
efunc->u.glass.initial = init; |
184 |
efunc->u.glass.value = value; |
185 |
efunc->u.glass.deriv = deriv; |
186 |
efunc->u.glass.deriv2 = deriv2; |
187 |
efunc->u.glass.final = final; |
188 |
if (help) { |
189 |
if (efunc->help) ascfree((char *)efunc->help); |
190 |
efunc->help = ascstrdup(help); |
191 |
} else { |
192 |
efunc->help = NULL; |
193 |
} |
194 |
|
195 |
if (isNew) { |
196 |
(void)AddExternalFunc(efunc,1); |
197 |
} |
198 |
return 0; |
199 |
} |
200 |
|
201 |
|
202 |
/* |
203 |
* GlassBox relations in particular register not just |
204 |
* a single function but rather a pointer to a jump table |
205 |
* of functions. There will be a jump table ptr for each |
206 |
* of value, deriv, deriv2. |
207 |
*/ |
208 |
|
209 |
/* |
210 |
* The following means: |
211 |
* GetValue is a function that returning pointer to array[] of |
212 |
* pointer to functions, which take args and return an int. |
213 |
* |
214 |
* int (*(*GetValueJumpTable(struct ExternalFunc *efunc))[])(args) |
215 |
*/ |
216 |
|
217 |
ExtEvalFunc **GetValueJumpTable(struct ExternalFunc *efunc) |
218 |
{ |
219 |
asc_assert(efunc!=NULL); |
220 |
asc_assert(efunc->etype == efunc_GlassBox); |
221 |
return efunc->u.glass.value; |
222 |
} |
223 |
|
224 |
ExtEvalFunc **GetDerivJumpTable(struct ExternalFunc *efunc) |
225 |
{ |
226 |
asc_assert(efunc!=NULL); |
227 |
asc_assert(efunc->etype == efunc_GlassBox); |
228 |
return efunc->u.glass.deriv; |
229 |
} |
230 |
|
231 |
ExtEvalFunc **GetDeriv2JumpTable(struct ExternalFunc *efunc) |
232 |
{ |
233 |
asc_assert(efunc!=NULL); |
234 |
asc_assert(efunc->etype == efunc_GlassBox); |
235 |
return efunc->u.glass.deriv2; |
236 |
} |
237 |
|
238 |
/*------------------------------------------------------------------------------ |
239 |
EXTERNAL METHOD STUFF |
240 |
*/ |
241 |
|
242 |
int CreateUserFunctionMethod(CONST char *name, |
243 |
/* ExtMethodInit *init, */ |
244 |
ExtMethodRun *run, |
245 |
/* ExtMethodInitEvalFunc *final, */ |
246 |
CONST long n_args, |
247 |
/* CONST unsigned long n_outputs, */ |
248 |
CONST char *help) |
249 |
{ |
250 |
struct ExternalFunc *efunc; |
251 |
int isNew = 1; |
252 |
if (name == NULL) { |
253 |
return 1; |
254 |
} |
255 |
efunc = LookupExtFunc(name); |
256 |
if (efunc != NULL) { |
257 |
isNew = 0; |
258 |
/* name was pre-loaded -- just update the info. This may cause user |
259 |
insanity if it wasn't a reload of the same thing. */ |
260 |
} else { |
261 |
isNew = 1; |
262 |
efunc = ASC_NEW(struct ExternalFunc); |
263 |
asc_assert(efunc!=NULL); |
264 |
efunc->help = NULL; |
265 |
efunc->name = ascstrdup(SCP(AddSymbol(name))); |
266 |
/* add or find name in symbol table, and copy because */ |
267 |
/* the main symtab owns the string */ |
268 |
} |
269 |
efunc->etype = efunc_Method; |
270 |
efunc->n_inputs = n_args; |
271 |
efunc->n_outputs = 0; |
272 |
efunc->u.method.run = run; |
273 |
#if 0 |
274 |
efunc->u.method.initial = init; |
275 |
efunc->u.method.final = final; |
276 |
#endif |
277 |
if (help) { |
278 |
if (efunc->help) { ascfree((char *)efunc->help); } |
279 |
efunc->help = ascstrdup(help); |
280 |
} else { |
281 |
efunc->help = NULL; |
282 |
} |
283 |
|
284 |
if (isNew ) { |
285 |
(void)AddExternalFunc(efunc,1); |
286 |
} |
287 |
return 0; |
288 |
} |
289 |
|
290 |
|
291 |
|
292 |
ExtMethodRun *GetExtMethodRun(struct ExternalFunc *efunc) |
293 |
{ |
294 |
asc_assert(efunc!=NULL); |
295 |
asc_assert(efunc->etype == efunc_Method); |
296 |
return efunc->u.method.run; |
297 |
} |
298 |
|
299 |
/*------------------------------------------------------------------------------ |
300 |
REGISTRATION AND LOOKUP FUNCTIONS |
301 |
*/ |
302 |
|
303 |
void DestroyExternalFunc(struct ExternalFunc *efunc){ |
304 |
struct ExternalFunc *tmp; |
305 |
if(efunc){ |
306 |
CONSOLE_DEBUG("DESTROYING EFUNC at %p",efunc); |
307 |
tmp = efunc; |
308 |
if (tmp->name ) ascfree((char *)(tmp->name)); /* we own the string */ |
309 |
if (tmp->help) ascfree((char *)(tmp->help)); /* we own the string */ |
310 |
tmp->name = NULL; |
311 |
tmp->help = NULL; |
312 |
/* might want to set null pointers here depending on etype. */ |
313 |
tmp->etype = efunc_ERR; |
314 |
ascfree((char *)tmp); |
315 |
} |
316 |
} |
317 |
|
318 |
CONST char *ExternalFuncName(CONST struct ExternalFunc *efunc) |
319 |
{ |
320 |
asc_assert(efunc!=NULL); |
321 |
return efunc->name; |
322 |
} |
323 |
|
324 |
unsigned long NumberInputArgs(CONST struct ExternalFunc *efunc) |
325 |
{ |
326 |
asc_assert(efunc!=NULL); |
327 |
return efunc->n_inputs; |
328 |
} |
329 |
|
330 |
unsigned long NumberOutputArgs(CONST struct ExternalFunc *efunc) |
331 |
{ |
332 |
asc_assert(efunc!=NULL); |
333 |
return efunc->n_outputs; |
334 |
} |
335 |
|
336 |
/*------------------------------------------------------------------------------ |
337 |
EXTERNALFUNCLIBRARY TABLE-MANAGEMENT ROUTINES |
338 |
*/ |
339 |
|
340 |
void InitExternalFuncLibrary(void) |
341 |
{ |
342 |
struct Table *result; |
343 |
result = CreateTable(EXTFUNCHASHSIZE); /* this isn't destroyed at end. fix.*/ |
344 |
ExternalFuncLibrary = result; |
345 |
} |
346 |
|
347 |
|
348 |
int AddExternalFunc(struct ExternalFunc *efunc, int force){ |
349 |
struct ExternalFunc *found, *tmp; |
350 |
char *name; |
351 |
|
352 |
CONSOLE_DEBUG("efunc = %p",efunc); |
353 |
asc_assert(efunc!=NULL); |
354 |
|
355 |
name = (char *)efunc->name; |
356 |
found = (struct ExternalFunc *)LookupTableData(ExternalFuncLibrary,name); |
357 |
if(found){ |
358 |
/* function with this name already exists in the ExternalFuncLibrary */ |
359 |
if(!force){ |
360 |
CONSOLE_DEBUG("EFUNC found OK, not adding"); |
361 |
return 0; |
362 |
} |
363 |
|
364 |
/* force!=0, so we're requested to update the entry in the table */ |
365 |
CONSOLE_DEBUG("EFUNC found OK, update forced"); |
366 |
tmp = (struct ExternalFunc *)RemoveTableData(ExternalFuncLibrary,name); |
367 |
DestroyExternalFunc(tmp); |
368 |
AddTableData(ExternalFuncLibrary,(void *)efunc,name); |
369 |
return 1; |
370 |
}else{ |
371 |
/* need to add function to library */ |
372 |
CONSOLE_DEBUG("EFUNC not found, adding pointer %p for efunc to table under name '%s'.",efunc,name); |
373 |
AddTableData(ExternalFuncLibrary,(void *)efunc,name); |
374 |
return 1; |
375 |
} |
376 |
} |
377 |
|
378 |
|
379 |
struct ExternalFunc *LookupExtFunc(CONST char *funcname) |
380 |
{ |
381 |
struct ExternalFunc *found; |
382 |
if (!funcname) { |
383 |
return NULL; |
384 |
} |
385 |
found = (struct ExternalFunc *)LookupTableData(ExternalFuncLibrary,funcname); |
386 |
if (found) { |
387 |
CONSOLE_DEBUG("Found '%s' in ExternalFuncLibrary at %p",funcname,found); |
388 |
return found; |
389 |
} else { |
390 |
return NULL; /* name not found */ |
391 |
} |
392 |
} |
393 |
|
394 |
struct ExternalFunc *RemoveExternalFunc(char *funcname) |
395 |
{ |
396 |
struct ExternalFunc *found; |
397 |
if (!funcname) |
398 |
return NULL; |
399 |
found = (struct ExternalFunc *) |
400 |
RemoveTableData(ExternalFuncLibrary,funcname); |
401 |
return found; |
402 |
} |
403 |
|
404 |
|
405 |
static |
406 |
void ExternalFuncDestroyFunc(void *efunc) |
407 |
{ |
408 |
struct ExternalFunc *local; |
409 |
local = (struct ExternalFunc *)efunc; |
410 |
if (local) |
411 |
DestroyExternalFunc(local); |
412 |
} |
413 |
|
414 |
void DestroyExtFuncLibrary(void) |
415 |
{ |
416 |
TableApplyAll(ExternalFuncLibrary, |
417 |
(TableIteratorOne)ExternalFuncDestroyFunc); |
418 |
DestroyTable(ExternalFuncLibrary,0); |
419 |
ExternalFuncLibrary = NULL; |
420 |
} |
421 |
|
422 |
static |
423 |
void PrintExtFuncLibraryFunc(void *efunc, void *fp) |
424 |
{ |
425 |
struct ExternalFunc *local_efunc = (struct ExternalFunc *)efunc; |
426 |
|
427 |
if (local_efunc!=NULL) { |
428 |
FPRINTF(fp,"%s\n",ExternalFuncName(local_efunc)); |
429 |
if (local_efunc->help) { |
430 |
FPRINTF(fp,"%s\n",local_efunc->help); |
431 |
} else { |
432 |
FPRINTF(fp,"No help information available for this function\n"); |
433 |
} |
434 |
} |
435 |
} |
436 |
|
437 |
void PrintExtFuncLibrary(FILE *fp) |
438 |
{ |
439 |
if (!fp) { |
440 |
FPRINTF(ASCERR,"Invalid file handle in PrintExtFuncLibrary\n"); |
441 |
return; |
442 |
} |
443 |
TableApplyAllTwo(ExternalFuncLibrary, PrintExtFuncLibraryFunc, |
444 |
(void *)fp); |
445 |
} |
446 |
|
447 |
static |
448 |
void WriteExtFuncString(struct ExternalFunc *efunc, Asc_DString *dsPtr) |
449 |
{ |
450 |
if (efunc!=NULL) { |
451 |
Asc_DStringAppend(dsPtr,"{{",2); |
452 |
Asc_DStringAppend(dsPtr,ExternalFuncName(efunc),-1); |
453 |
Asc_DStringAppend(dsPtr,"} {",3); |
454 |
if (efunc->help!=NULL) { |
455 |
Asc_DStringAppend(dsPtr,efunc->help,-1); |
456 |
} else { |
457 |
Asc_DStringAppend(dsPtr,"No help available.",18); |
458 |
} |
459 |
Asc_DStringAppend(dsPtr,"}} ",3); |
460 |
} |
461 |
} |
462 |
|
463 |
char *WriteExtFuncLibraryString(void) |
464 |
{ |
465 |
char *result; |
466 |
Asc_DString ds, *dsPtr; |
467 |
dsPtr = &ds; |
468 |
Asc_DStringInit(dsPtr); |
469 |
TableApplyAllTwo(ExternalFuncLibrary,(TableIteratorTwo)WriteExtFuncString, |
470 |
(void *) dsPtr); |
471 |
result = Asc_DStringResult(dsPtr); |
472 |
return result; |
473 |
} |
474 |
|
475 |
void |
476 |
TraverseExtFuncLibrary(void (*func)(void *,void *), void *secondparam){ |
477 |
TableApplyAllTwo(ExternalFuncLibrary, func, secondparam); |
478 |
} |