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(&params[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(&params[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(&params[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