1 /***********************************************************************/
2 /* Open Visualization Data Explorer */
3 /* (C) Copyright IBM Corp. 1989,1999 */
4 /* ALL RIGHTS RESERVED */
5 /* This code licensed under the */
6 /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */
7 /***********************************************************************/
8
9 #include <dxconfig.h>
10 #include "../base/defines.h"
11
12
13
14 #include "NodeDefinition.h"
15 #include "Node.h"
16 #include "ParameterDefinition.h"
17 #include "Parameter.h"
18 #include "Dictionary.h"
19 #include "DictionaryIterator.h"
20 #include "Network.h"
21 #include "SIAllocatorDictionary.h"
22 #include "CDBAllocatorDictionary.h"
23 #include "ErrorDialogManager.h"
24
25 //
26 // This is the dictionary that contains all Node (and derived) class
27 // definitions. Looking up a node by name returns a pointer to a
28 // NodeDefinition;
29 //
30 Dictionary *theNodeDefinitionDictionary = new Dictionary;
31
32
NodeDefinition()33 NodeDefinition::NodeDefinition()
34 {
35 this-> nodeInstanceNumbers = 0;
36 this->description = NUL(char*);
37 this->input_repeats = this->output_repeats = 0;
38 this->writeableCacheability = TRUE;
39 this->defaultCacheability = ModuleFullyCached;
40 this->mdf_flags = 0;
41 this->loadFile = NULL;
42 this->outboardHost = NULL;
43 this->outboardCommand = NULL;
44 this->userTool = TRUE;
45 this->uiLoadedOnly = FALSE;
46 }
~NodeDefinition()47 NodeDefinition::~NodeDefinition()
48 {
49 //
50 // Delete the input/output definitions
51 //
52 ParameterDefinition *pd;
53 ListIterator iterator(this->inputDefs);
54 while ( (pd = (ParameterDefinition*)iterator.getNext()) )
55 delete pd;
56 iterator.setList(this->outputDefs);
57 while ( (pd = (ParameterDefinition*)iterator.getNext()) )
58 delete pd;
59
60
61 if (this->outboardHost)
62 delete[] this->outboardHost;
63 if (this->outboardCommand)
64 delete[] this->outboardCommand;
65 if (this->loadFile)
66 delete[] this->loadFile;
67 if (this->description)
68 delete[] this->description;
69
70 //
71 // If this node definition was installed in the Node definition
72 // dictionary, then remove it.
73 // Note that the constructor does NOT install this NodeDefinition in
74 // theNodeDefinitionDictionary. It is assumed that this happens elsewhere,
75 // probably for no good reason.
76 //
77 NodeDefinition *nd = (NodeDefinition*)
78 theNodeDefinitionDictionary->findDefinition(this->getNameSymbol());
79 if (nd == this)
80 theNodeDefinitionDictionary->removeDefinition(this->getNameSymbol());
81
82
83 }
newNode(Network * net,int inst)84 Node *NodeDefinition::newNode(Network *net, int inst)
85 {
86 Node *m = new Node(this, net, inst);
87 return m;
88 }
89
AllocateDefinition()90 NodeDefinition *NodeDefinition::AllocateDefinition()
91 {
92 return new NodeDefinition;
93 }
94
95 ///////////////////////////////////////////////////////////////////////////////
96 // Get the Nth Input or Output ParameterDefinition.
97 // n is indexed from 1. If n is greater than the number of input/output
98 // defintions then it is a repeatable parameter, in which case we
99 // must account for this to find the correct definition.
100 //
getInputDefinition(int n)101 ParameterDefinition *NodeDefinition::getInputDefinition(int n)
102 {
103
104 ASSERT(n > 0);
105 int cnt = this->getInputCount();
106
107 if (n > cnt) {
108 int repeats = this->input_repeats;
109 ASSERT(repeats > 0);
110 if (repeats == 1) {
111 n = cnt;
112 } else {
113 int num = (((n-1) - cnt) % repeats) + 1;
114 n = cnt - repeats + num ;
115 ASSERT(n > cnt - repeats);
116 ASSERT(n <= cnt);
117 }
118 }
119 return (ParameterDefinition*)this->inputDefs.getElement(n);
120 }
121 //
122 // Get the n'th output parameter definition.
123 // n is indexed from 1.
124 //
getOutputDefinition(int n)125 ParameterDefinition *NodeDefinition::getOutputDefinition(int n)
126 {
127
128 ASSERT(n > 0);
129 int cnt = this->getOutputCount();
130
131 if (n > cnt) {
132 int repeats = this->output_repeats;
133 ASSERT(repeats > 0);
134 if (repeats == 1) {
135 n = cnt;
136 } else {
137 int num = (((n-1) - cnt) % repeats) + 1;
138 n = cnt - repeats + num ;
139 ASSERT(n > cnt - repeats);
140 ASSERT(n <= cnt);
141 }
142 }
143 return (ParameterDefinition*)this->outputDefs.getElement(n);
144 }
145
createNewNode(Network * net,int inst)146 Node *NodeDefinition::createNewNode(Network *net, int inst)
147 {
148 if (!this->isAllowedInMacro() && net->isMacro())
149 {
150 ErrorMessage("The %s node is not allowed in a macro.",
151 this->getNameString());
152 return NULL;
153 }
154
155 Node *n = this->newNode(net, inst);
156
157 if (n) {
158 //
159 // If initialization of the node fails delete the node and return NULL.
160 // If initialize() fails, it is assumed that it issued an appropriate
161 // error message, so we don't give one here.
162 //
163 if (!n->initialize()) {
164 delete n;
165 return NULL;
166 }
167 }
168
169 return n;
170 }
171
172
isDerivedFromMacro()173 boolean NodeDefinition::isDerivedFromMacro()
174 {
175 return FALSE;
176 }
177 //
178 // Called once per new class (actually called on every new instance, but
179 // we assume we only have one instance of each node defintion in the
180 // whole system) after parsing an MDF record for this node.
181 //
completeDefinition()182 void NodeDefinition::completeDefinition()
183 {
184
185 if (theSIAllocatorDictionary) {
186 SIAllocator sia = this->getSIAllocator();
187 if (sia)
188 theSIAllocatorDictionary->addAllocator(this->getNameString(), sia);
189 }
190
191 if (theCDBAllocatorDictionary) {
192 CDBAllocator cdba = this->getCDBAllocator();
193 if (cdba)
194 theCDBAllocatorDictionary->addAllocator(this->getNameString(), cdba);
195 }
196
197 this->finishDefinition();
198
199 }
200
getSIAllocator()201 SIAllocator NodeDefinition::getSIAllocator()
202 {
203 // Causes the default definition in the SIAllocatorDictionary to be used.
204 return NULL;
205 }
getCDBAllocator()206 CDBAllocator NodeDefinition::getCDBAllocator()
207 {
208 // Causes the default definition in the CDBAllocatorDictionary to be used.
209 return NULL;
210 }
211 //
212 // Get a new parameter for the node that corresponds to this node definition.
213 //
newParameter(ParameterDefinition * pd,Node * n,int index)214 Parameter *NodeDefinition::newParameter(ParameterDefinition *pd,
215 Node *n, int index)
216 {
217 return new Parameter(pd);
218 }
219 //
220 // Returns the name executive module that is called to do the work
221 // for this type of node.
222 // Be default, that name is always just the name of the Node.
223 //
getExecModuleNameString()224 const char *NodeDefinition::getExecModuleNameString()
225 {
226 return this->getNameString();
227 }
228
229 //
230 // Reset all the NodeDefinitions in the given dictionary to
231 // have the next instance number generated by 1.
232 //
ResetInstanceNumbers(Dictionary * dict)233 void NodeDefinition::ResetInstanceNumbers(Dictionary *dict)
234 {
235 DictionaryIterator di(*dict);
236 NodeDefinition *nd;
237
238 while ( (nd = (NodeDefinition*) di.getNextDefinition()) )
239 nd->setNextInstance(1);
240 }
241
242 //
243 // Get the MDF record for this Node definition.
244 // The returned string must be delete by the caller.
245 //
getMDFString()246 char *NodeDefinition::getMDFString()
247 {
248 char *header = this->getMDFHeaderString();
249 char *inputs = this->getMDFParametersString(TRUE);
250 char *outputs = this->getMDFParametersString(FALSE);
251
252 ASSERT(header);
253
254 char *mdf = new char [STRLEN(header) +
255 STRLEN(inputs) + STRLEN(outputs) + 2];
256 sprintf(mdf, "%s%s%s",
257 header,
258 (inputs ? inputs : ""),
259 (outputs ? outputs : ""));
260
261 delete[] header;
262 if (inputs) delete[] inputs;
263 if (outputs) delete[] outputs;
264 return mdf;
265 }
266 //
267 // Get the MDF header (stuff before the INPUT/OUTPUT statements) for this
268 // NodeDefinition.
269 // The returned string must be delete by the caller.
270 //
getMDFHeaderString()271 char *NodeDefinition::getMDFHeaderString()
272 {
273 char category[256];
274 char description[256];
275 char io_board[256];
276 char flags[256];
277
278 if (this->getCategoryString()) {
279 sprintf(category,"CATEGORY %s\n", this->getCategoryString());
280 } else {
281 category[0] = '\0';
282 }
283 if (this->getDescription()) {
284 sprintf(description,"DESCRIPTION %s\n", this->getDescription());
285 } else {
286 description[0] = '\0';
287 }
288 if (this->isOutboard()) {
289 const char *host = this->getDefaultOutboardHost();
290 sprintf(io_board,"OUTBOARD \"%s\" ; %s\n",
291 this->getOutboardCommand(),
292 host ? host : "");
293 } else if (this->isDynamicallyLoaded()) {
294 sprintf(io_board,"LOADABLE %s\n", this->getDynamicLoadFile());
295 } else {
296 io_board[0] = '\0';
297 }
298 if (this->mdf_flags) {
299 sprintf(flags,"FLAGS%s%s%s%s%s%s%s%s%s\n",
300 (this->isMDFFlagERR_CONT() ? " ERR_CONT" : ""),
301 (this->isMDFFlagSWITCH() ? " SWITCH" : ""),
302 (this->isMDFFlagPIN() ? " PIN" : ""),
303 (this->isMDFFlagLOOP() ? " LOOP" : ""),
304 (this->isMDFFlagSIDE_EFFECT() ? " SIDE_EFFECT" : ""),
305 (this->isMDFFlagPERSISTENT() ? " PERSISTENT" : ""),
306 (this->isMDFFlagASYNCHRONOUS() ? " ASYNC" : ""),
307 (this->isMDFFlagREACH() ? " REACH" : ""),
308 (this->isMDFFlagREROUTABLE() ? " REROUTABLE" : ""));
309 } else {
310 flags[0] = '\0';
311 }
312
313 char *header = new char[128 +
314 STRLEN(category) +
315 STRLEN(description) +
316 STRLEN(io_board) +
317 STRLEN(flags)];
318
319 sprintf(header,"MODULE %s\n"
320 "%s"
321 "%s"
322 "%s"
323 "%s",
324 this->getNameString(),
325 category,
326 description,
327 io_board,
328 flags);
329
330 return header;
331 }
332
333 //
334 // Get the list of INPUT/OUTPUT lines in the MDF and the REPEAT if any
335 // The returned string must be delete by the caller.
336 //
getMDFParametersString(boolean inputs)337 char *NodeDefinition::getMDFParametersString(boolean inputs)
338 {
339 #define CHUNK 256
340 char *params = NULL;
341 int currend = 0, maxlen = 0;
342 ListIterator li;
343 ParameterDefinition *pd;
344
345 if (inputs)
346 li.setList(this->inputDefs);
347 else
348 li.setList(this->outputDefs);
349
350 while ( (pd = (ParameterDefinition*)li.getNext()) ) {
351 char *line = pd->getMDFString();
352 int linelen = STRLEN(line) + 1;
353 if (linelen + currend > maxlen) {
354 maxlen = ( CHUNK > linelen ? CHUNK : linelen) + currend;
355 params = (char*)REALLOC(params, maxlen * sizeof(char));
356 if (currend == 0) // The first time
357 *params = '\0';
358 }
359 strcat(¶ms[currend], line);
360 currend += linelen - 1;
361 delete[] line;
362 }
363
364 if (inputs && this->isInputRepeatable()) {
365 if (maxlen - currend < 32)
366 params = (char*)REALLOC(params, (32 + currend) * sizeof(char));
367 sprintf(¶ms[currend],"REPEAT %d\n",this->getInputRepeatCount());
368 } else if (!inputs && this->isOutputRepeatable()) {
369 if (maxlen - currend < 32)
370 params = (char*)REALLOC(params, (32 + currend) * sizeof(char));
371 sprintf(¶ms[currend],"REPEAT %d\n",this->getOutputRepeatCount());
372 }
373
374 return params;
375 }
376 #define MDF_SWITCH 0x01
377 #define MDF_ERR_CONT 0x02
378 #define MDF_PIN 0x04
379 #define MDF_SIDE_EFFECT 0x08
380 #define MDF_PERSISTENT 0x10
381 #define MDF_ASYNCHRONOUS 0x20
382 #define MDF_REROUTABLE 0x40
383 #define MDF_REACH 0x80
384 #define MDF_LOOP 0x100
385
setMDFFlag(boolean val,long flag)386 void NodeDefinition::setMDFFlag(boolean val, long flag)
387 {
388 if (val)
389 this->mdf_flags |= flag;
390 else
391 this->mdf_flags &= ~flag;
392 }
setMDFFlagERR_CONT(boolean val)393 void NodeDefinition::setMDFFlagERR_CONT(boolean val)
394 {
395 this->setMDFFlag(val, MDF_ERR_CONT);
396 }
isMDFFlagERR_CONT()397 boolean NodeDefinition::isMDFFlagERR_CONT()
398 {
399 return (this->mdf_flags & MDF_ERR_CONT) ? TRUE : FALSE ;
400 }
setMDFFlagSWITCH(boolean val)401 void NodeDefinition::setMDFFlagSWITCH(boolean val )
402 {
403 this->setMDFFlag(val, MDF_SWITCH);
404 }
isMDFFlagSWITCH()405 boolean NodeDefinition::isMDFFlagSWITCH()
406 {
407 return (this->mdf_flags & MDF_SWITCH) ? TRUE : FALSE ;
408 }
setMDFFlagPIN(boolean val)409 void NodeDefinition::setMDFFlagPIN(boolean val )
410 {
411 this->setMDFFlag(val, MDF_PIN);
412 }
isMDFFlagPIN()413 boolean NodeDefinition::isMDFFlagPIN()
414 {
415 return (this->mdf_flags & MDF_PIN) ? TRUE : FALSE ;
416 }
setMDFFlagLOOP(boolean val)417 void NodeDefinition::setMDFFlagLOOP(boolean val )
418 {
419 this->setMDFFlag(val, MDF_LOOP);
420 }
isMDFFlagLOOP()421 boolean NodeDefinition::isMDFFlagLOOP()
422 {
423 return (this->mdf_flags & MDF_LOOP) ? TRUE : FALSE ;
424 }
setMDFFlagSIDE_EFFECT(boolean val)425 void NodeDefinition::setMDFFlagSIDE_EFFECT(boolean val )
426 {
427 this->setMDFFlag(val, MDF_SIDE_EFFECT);
428 }
isMDFFlagSIDE_EFFECT()429 boolean NodeDefinition::isMDFFlagSIDE_EFFECT()
430 {
431 return (this->mdf_flags & MDF_SIDE_EFFECT) ? TRUE : FALSE ;
432 }
setMDFFlagPERSISTENT(boolean val)433 void NodeDefinition::setMDFFlagPERSISTENT(boolean val )
434 {
435 this->setMDFFlag(val, MDF_PERSISTENT);
436 }
isMDFFlagPERSISTENT()437 boolean NodeDefinition::isMDFFlagPERSISTENT()
438 {
439 return (this->mdf_flags & MDF_PERSISTENT) ? TRUE : FALSE ;
440 }
setMDFFlagASYNCHRONOUS(boolean val)441 void NodeDefinition::setMDFFlagASYNCHRONOUS(boolean val )
442 {
443 this->setMDFFlag(val, MDF_ASYNCHRONOUS);
444 }
isMDFFlagASYNCHRONOUS()445 boolean NodeDefinition::isMDFFlagASYNCHRONOUS()
446 {
447 return (this->mdf_flags & MDF_ASYNCHRONOUS) ? TRUE : FALSE ;
448 }
setMDFFlagREROUTABLE(boolean val)449 void NodeDefinition::setMDFFlagREROUTABLE(boolean val )
450 {
451 this->setMDFFlag(val, MDF_REROUTABLE);
452 }
isMDFFlagREROUTABLE()453 boolean NodeDefinition::isMDFFlagREROUTABLE()
454 {
455 return (this->mdf_flags & MDF_REROUTABLE) ? TRUE : FALSE ;
456 }
setMDFFlagREACH(boolean val)457 void NodeDefinition::setMDFFlagREACH(boolean val )
458 {
459 this->setMDFFlag(val, MDF_REACH);
460 }
isMDFFlagREACH()461 boolean NodeDefinition::isMDFFlagREACH()
462 {
463 return (this->mdf_flags & MDF_REACH) ? TRUE : FALSE ;
464 }
setDefaultOutboardHost(const char * host)465 void NodeDefinition::setDefaultOutboardHost(const char *host)
466 {
467 if (this->outboardHost)
468 delete[] this->outboardHost;
469 this->outboardHost = DuplicateString(host);
470 }
isOutboard()471 boolean NodeDefinition::isOutboard()
472 {
473 return (this->outboardCommand != NULL);
474 }
setOutboardCommand(const char * command)475 void NodeDefinition::setOutboardCommand(const char *command)
476 {
477 if (this->outboardCommand)
478 delete[] this->outboardCommand;
479
480 if (this->loadFile) {
481 delete[] this->loadFile;
482 this->loadFile = NULL;
483 }
484
485 this->outboardCommand = DuplicateString(command);
486 }
isDynamicallyLoaded()487 boolean NodeDefinition::isDynamicallyLoaded()
488 {
489 return (this->loadFile != NULL);
490 }
getDynamicLoadFile()491 const char *NodeDefinition::getDynamicLoadFile()
492 {
493 return this->loadFile;
494 }
setDynamicLoadFile(const char * file)495 void NodeDefinition::setDynamicLoadFile(const char *file)
496 {
497 if (this->loadFile)
498 delete[] this->loadFile;
499
500 //
501 // I tool can be either outboard or inboard (static) or inboard
502 // (dynamic), but not both.
503 //
504 if (this->outboardCommand) {
505 delete[] this->outboardCommand;
506 this->outboardCommand = NULL;
507 }
508
509 this->loadFile = DuplicateString(file);
510 }
setDescription(const char * d)511 void NodeDefinition::setDescription(const char *d)
512 {
513 if (this->description)
514 delete[] this->description;
515
516 this->description = DuplicateString(d);
517 }
518
519 //
520 // Add a selectable value for the n'th input.
521 //
addInputValueOption(int n,const char * value)522 boolean NodeDefinition::addInputValueOption(int n, const char *value)
523 {
524
525 ParameterDefinition *pd = this->getInputDefinition(n);
526 if (pd)
527 return pd->addValueOption(value);
528 return FALSE;
529 }
setUILoadedOnly()530 void NodeDefinition::setUILoadedOnly()
531 {
532 this->uiLoadedOnly = TRUE;
533 }
isUILoadedOnly()534 boolean NodeDefinition::isUILoadedOnly()
535 {
536 return this->uiLoadedOnly;
537 }
538
539 #if 0 // This is in Node.C
540 //
541 // Get the selectable values for the n'th input.
542 //
543 const char * const *NodeDefinition::getInputValueOptions(int n)
544 {
545
546 ParameterDefinition *pd = this->getInputDefinition(n);
547 if (pd)
548 return pd->getValueOptions(options);
549 if (options)
550 *options = NULL;
551 return 0;
552 }
553 #endif
554
555
556
557