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 
15 //
16 // 3/24/95 dawood - Static macros are macros that do not execute unless
17 // their inputs change.  Previously, the UI used global variables to
18 // set hardcoded (i.e. tab down, unconnected) inputs to modules in macros.
19 // Now we place the parameter values write in the argument list to the
20 // modules.  Among other things this means that we must send a new
21 // definition of the macro (before an execution) each time the user
22 // changes a hardcoded input value.
23 //
24 #define STATIC_MACROS
25 
26 #include "DXStrings.h"
27 #include "lex.h"
28 #include "Node.h"
29 #include "NodeDefinition.h"
30 #include "Network.h"
31 #include "DXPacketIF.h"
32 #include "Parameter.h"
33 #include "StandIn.h"
34 #include "ConfigurationDialog.h"
35 #include "ErrorDialogManager.h"
36 #include "WarningDialogManager.h"
37 #include "Ark.h"
38 #include "ListIterator.h"
39 #include "DXApplication.h"
40 #include "ProcessGroupManager.h"
41 #include "EditorWindow.h"
42 #if WORKSPACE_PAGES
43 #include "Dictionary.h"
44 #include "DictionaryIterator.h"
45 #endif
46 
47 #if defined(windows) && defined(HAVE_WINSOCK_H)
48 #include <winsock.h>
49 #elif defined(HAVE_CYGWIN_SOCKET_H)
50 #include <cygwin/socket.h>
51 #elif defined(HAVE_SYS_SOCKET_H)
52 #include <sys/socket.h>
53 #endif
54 
55 
56 //
57 // Define the maxium number of repeatable inputs and outputs.
58 //
59 #define MAX_INPUT_SETS	21
60 #define MAX_OUTPUT_SETS 21
61 
62 static char *__indent = "    ";
63 
setDefinition(NodeDefinition * nd)64 void Node::setDefinition(NodeDefinition *nd)
65 {
66 
67     this->definition = nd;
68     if (this->instanceNumber < 1)
69 	this->instanceNumber = nd->newInstanceNumber();
70 }
71 
Node(NodeDefinition * nd,Network * net,int inst)72 Node::Node(NodeDefinition *nd, Network *net, int inst)
73 {
74 
75     this->network = net;
76     this->instanceNumber = inst;
77     this->setDefinition(nd);		// This may also set the instance #
78     this->vpe_xpos = this->vpe_ypos = 0;
79     this->labelSymbol = 0;
80     this->standin = NULL;
81     this->cdb = NULL;
82     this->moduleMessageId = NULL;
83     this->nodeCacheability = nd->getDefaultCacheability();
84     this->buildParameterLists();
85     this->marked = FALSE;
86 #if WORKSPACE_PAGES
87 #else
88     this->groupNameSymbol = 0;
89 #endif
90     this->layout_information = NULL;
91 }
92 
93 
94 //////////////////////////////////////////////////////////////////////////////
95 //
96 // Delete all elements that are considered part of the Node.  This includes
97 // input and output parameters, and a Node's standin if it has one.
98 //
~Node()99 Node::~Node()
100 {
101     Parameter *p;
102     ListIterator iterator;
103 
104     //
105     // If this node has a messaging protocol and it gets deleted during
106     // execution, be sure that the handler gets removed from the packet
107     // handler so that the handler doesn't get called on a freed node.
108     //
109     if (this->moduleMessageId) {
110 	if (this->getNetwork() == theDXApplication->network) {
111 	    //
112 	    // don't remove the handler in the case of destroying
113 	    // a temporary network - i.e. drag-n-drop
114 	    //
115 	    DXPacketIF *pif = theDXApplication->getPacketIF();
116 	    if  (pif)
117 		pif->setHandler(DXPacketIF::INFORMATION,
118 			NULL, (void*)this, this->moduleMessageId);
119 	}
120 	delete this->moduleMessageId;
121     }
122 
123     //
124     // Delete the Configuration Dialog for this node
125     //
126     if (this->cdb)  {
127 	delete this->cdb;
128         this->cdb = NULL;	// Should speed up arc deletion.
129     }
130 
131     //
132     // Delete the standin for this node
133     //
134     StandIn *saved_standin = this->standin;
135     this->standin = NULL;	// Should speed up arc deletion.
136 
137 
138 
139     //
140     // Delete all the parameters in the Input parameter List
141     //
142     FOR_EACH_NODE_INPUT(this,p,iterator)
143         delete p;
144 
145     //
146     // Delete all the parameters in the Output parameter List
147     //
148     FOR_EACH_NODE_OUTPUT(this,p,iterator)
149         delete p;
150 
151     //
152     // Now that the parameters and arcs have been deleted we can delete
153     // the StandIn.
154     // NOTE: this depends upon the fact that deletion of the StandIn does not
155     //	require reading the state of the Node (i.e. its parameters), otherwise
156     //  deletion will need to be placed above Parameter deletion.
157     //
158     if (saved_standin)
159 	delete saved_standin;
160 
161     if (this->network)
162 	this->network->setDirty();
163 
164     //
165     // If this is a persistent outboard module, be sure to tell the executive
166     // that it has been deleted.
167     //
168     NodeDefinition *nd = this->definition;
169     if (nd->isOutboard() && nd->isMDFFlagPERSISTENT()) {
170 	DXPacketIF *pif = theDXApplication->getPacketIF();
171 	if (pif) {
172 	    char buf[512];
173 #if WORKSPACE_PAGES
174 	    const char *gname =
175 		this->getGroupName(theSymbolManager->getSymbol(PROCESS_GROUP));
176 #else
177 	    const char *gname = this->getGroupName();
178 #endif
179 	    if (gname)
180 		sprintf(buf,
181 			"Executive(\"outboard delete\",\"%s\",%d,\"%s\");\n",
182 			this->getNameString(),
183 			this->getInstanceNumber(),
184 			gname);
185 	    else
186 		sprintf(buf,
187 			"Executive(\"outboard delete\",\"%s\",%d);\n",
188 			this->getNameString(),
189 			this->getInstanceNumber());
190 	    pif->send(DXPacketIF::FOREGROUND, buf);
191 	    // FIXME: is the following necessary
192 	    // pif->sendImmediate("sync");
193 	}
194     }
195 
196     if (this->layout_information) delete this->layout_information;
197 }
198 //
199 // Determine if this node is a node of the given class
200 //
isA(const char * classname)201 boolean Node::isA(const char *classname)
202 {
203     Symbol s = theSymbolManager->registerSymbol(classname);
204     return this->isA(s);
205 }
206 //
207 // Determine if this node is of the given class.
208 //
isA(Symbol classname)209 boolean Node::isA(Symbol classname)
210 {
211     Symbol s = theSymbolManager->registerSymbol(ClassNode);
212     return (s == classname);
213 }
214 
215 //////////////////////////////////////////////////////////////////////////////
216 //
217 // Set the x,y positions on the VPE (visual program editor).
218 // If a standin exists for this node, then ask the StandIn to do it
219 // otherwise just set the values
220 //
setVpePosition(int x,int y)221 void Node::setVpePosition(int x, int y)
222 {
223     this->vpe_xpos = x;
224     this->vpe_ypos = y;
225 
226     if (this->standin)
227 	this->standin->setXYPosition(x,y);
228 
229 }
230 //////////////////////////////////////////////////////////////////////////////
231 //
232 // Get the x,y positions on the VPE (visual program editor).
233 // If a standin exists for this node, then ask the StandIn for the position
234 // otherwise use the values that were read from the .net file.
235 //
getVpePosition(int * x,int * y)236 void Node::getVpePosition(int *x, int *y)
237 {
238     if (this->standin) {
239 	this->standin->getXYPosition(x,y);
240 	// Do this in case the standin goes away, but the node does not?!
241 	this->vpe_xpos = *x;
242 	this->vpe_ypos = *y;
243     } else {
244 	*x = this->vpe_xpos;
245 	*y = this->vpe_ypos;
246     }
247 }
248 
249 //////////////////////////////////////////////////////////////////////////////
250 //
251 // Output the names of list of input parameters for this node.
252 // If on input have a value print its name as $module_$instance_$in_$input.
253 // If the input is taking it's value from another node's output, then print
254 // ${outputmodule}_${outputmodule_instance}_out_${outputmodule_output}.
255 //
256 // Note that the trailing newline ('\n') is not printed.
257 //
258 //  Like this...
259 //
260 //    Import_1_in_1,
261 //    Import_1_in_2,
262 //    Import_1_in_3,
263 //    Import_1_in_4,
264 //    Import_1_in_5,
265 //    Import_1_in_6
266 //
inputParameterNamesString(const char * varprefix,const char * indent)267 char *Node::inputParameterNamesString(const char *varprefix, const char *indent)
268 {
269     const char *name ;
270     char  *retstr;
271     int	  i, num_params;
272 
273     name = this->getNameString();
274     ASSERT(name);
275 
276     num_params = inputParameters.getSize();
277     if (num_params == 0)
278 	return NULL;
279 
280     //
281     // Get some buffers.
282     //
283     if (!indent)
284 	indent = "";
285 #if !defined(STATIC_MACROS)
286     int paramlen =
287 		(STRLEN(indent) + STRLEN(varprefix) + STRLEN(name) + 16) + 300;
288     char *buf = new char[ paramlen ];
289     retstr = new char[num_params * paramlen ];
290 #else
291     char buf[1024];
292     retstr = new char[num_params * 1024];
293 #endif
294 
295     //
296     // Print them
297     //
298     i = 1;
299     *retstr = '\0';
300     char *pstr = retstr;
301     for (i=1 ; i<=num_params ; i++, pstr+=STRLEN(pstr))  {
302 	Parameter *p;
303 	if ((p = this->getInputParameter(i))->isConnected())
304 	{
305 	    int  param;
306 	    Ark  *a = p->getArk(1);
307 	    ASSERT(a);
308 	    Node *onode = a->getSourceNode(param);
309 	    ASSERT(onode);
310 	    sprintf(buf, "%s%s%s_%d_out_%d", indent,varprefix,
311 			onode->getNameString(),
312 			onode->getInstanceNumber(), param);
313 	}
314 	else
315 	{
316 #if defined(STATIC_MACROS)
317 	    //
318 	    // If this is a macro then print the input value now, otherwise
319 	    // reference a global variable and print that value later.
320 	    //
321 	    if (this->network->isMacro())
322 		sprintf(buf,"%s%s",indent,this->getInputValueString(i));
323 	    else
324 #endif
325 	    sprintf(buf,"%s%s%s_%d_in_%d", indent, varprefix,
326 			name, this->instanceNumber, i);
327 	}
328 	if (i != num_params)
329 	    strcat(buf,",\n");
330         strcat(pstr,buf);
331     }
332 
333 #if !defined(STATIC_MACROS)
334     delete buf;
335 #endif
336     return retstr;
337 }
338 //
339 // Get the name of the input as specified in the network
340 // (i.e. main_Display_1_in_3)
341 // If buf is not provided the returned string must be deleted
342 // by the caller.
343 //
getNetworkIONameString(int index,boolean input,char * buffer)344 char *Node::getNetworkIONameString( int index, boolean input, char *buffer)
345 {
346     char *buf;
347     const char *prefix = this->network->getPrefix();
348 
349 #if defined(STATIC_MACROS)
350     //
351     // Macros do not use input parameter names because we always send
352     // the value of the input in the tools argument list.
353     //
354     // FIXME: now that I've removed the assert, are static macros endangered?
355     //ASSERT(!this->network->isMacro());
356 #endif
357     if (buffer)
358 	buf = buffer;
359     else
360         buf = new char[128];
361 
362     sprintf(buf,"%s%s_%d_%s_%d",
363 		prefix,
364 		this->getNameString(),
365 		this->getInstanceNumber(),
366 		(input ? "in" : "out"),
367 		index);
368      return buf;
369 }
370 
371 //////////////////////////////////////////////////////////////////////////////
372 //
373 // Output the names of the list of output parameters for this node.
374 // Note that the trailing newline ('\n') is not printed.
375 // It prints out the cache attribute for each output if it differs from
376 // that of the node.
377 //
378 //  Like this...
379 //
380 //    AutoColor_2_out_1[cache: 0],
381 //    AutoColor_2_out_2
382 //
383 //
outputParameterNamesString(const char * varprefix)384 char *Node::outputParameterNamesString(const char *varprefix)
385 {
386     if (this->getOutputCount() == 0)
387 	return NULL;
388 
389     const char *name ;
390     char  *buf, *retstr, *newprefix;
391     int	  i, paramlen, num_params;
392 
393     name = this->getNameString();
394     ASSERT(name);
395 
396     /*io = "out";*/
397     num_params = outputParameters.getSize();
398 
399     //
400     // Get some buffers.
401     //
402     paramlen = (STRLEN(varprefix) + STRLEN(name) + 16) + 300 + 10;
403     buf = new char[ paramlen ];
404     newprefix = new char[paramlen + STRLEN(varprefix)];
405     retstr = new char[num_params * paramlen ];
406     sprintf(newprefix,"%s%s_%d_out_",varprefix,name,this->instanceNumber);
407 
408     //
409     // Print the node name
410     //
411     i = 1;
412     *retstr = '\0';
413     char *pstr = retstr;
414     for (i=1 ; i<=num_params ; i++, pstr+=STRLEN(pstr))  {
415 	Parameter *p = this->getOutputParameter(i);
416 	ASSERT(p);
417 	if (this->getNodeCacheability() == p->getCacheability())
418 	    sprintf(buf,"%s%d%s", newprefix, i, (i==num_params ? "" : ",\n"));
419 	else
420 	    sprintf(buf,"%s%d[cache: %d]%s",
421 		    newprefix, i, p->getCacheability(),
422 		    (i==num_params ? "" : ",\n"));
423 	strcat(pstr,buf);
424     }
425 
426     delete buf;
427     delete newprefix;
428     return retstr;
429 }
430 
431 
432 //////////////////////////////////////////////////////////////////////////////
433 //
434 // Save any other files that relevant to this mode
435 // The name passed in is file name used to save the network (without the
436 // .net extension).
437 // By default, nodes do not have auxiliary files.
438 //
auxPrintNodeFile()439 boolean     Node::auxPrintNodeFile()
440 {
441     return TRUE;
442 }
443 
444 //////////////////////////////////////////////////////////////////////////////
445 //
446 // Print the '|'d section below for this node into what will be a .net file.
447 //
448 // FIXME: Do we need to be able to print to a string, can we just get
449 //		by with a FILE?
450 //
451 /*
452  *  //
453  *  // node Import[1]: x = 48, y = 14, inputs = 6, label = Import
454 ||  // input[1]: type = 64, value = "network8.dx"
455  *  //
456 */
printIOComment(FILE * f,boolean input,int i,const char * indent,boolean valueOnly)457 boolean Node::printIOComment(FILE *f, boolean input, int i,
458 				const char *indent, boolean valueOnly)
459 {
460     int status = 1;
461     if (!indent)
462 	indent = "";
463 
464     if (input)
465     {
466 	Parameter *p = this->getInputParameter(i);
467 	// Only print it if it is not receiving input from another output
468 	// (i.e. it does not have an arc)
469 //
470 // This ifdef is so that we save parameter values even if they have a
471 // connected arc.  This is useful for parameters whose arc-fed values
472 // are echoed back to the UI. This includes the data-driven interactors
473 // and some of Image's parameters. 	dawood 8/22/95
474 //
475 #if 00
476 	if (!p->isConnected() && p->hasValue()) {
477 	    if (valueOnly) {
478 		status = fprintf(f,
479 		    "%s// input[%d]: defaulting = %d, value = %s\n",
480 		    indent,
481 		    i,
482 		    p->isDefaulting() ? 1 : 0,
483 		    p->getSetValueString());
484 	    } else {
485 		status = fprintf(f,
486 		    "%s// input[%d]: defaulting = %d, visible = %d,"
487 			" type = %d, value = %s\n",
488 		    indent,
489 		    i,
490 		    (p->isDefaulting() ? 1 : 0),
491 		    (p->isVisible()? 1 : 0),
492 		    p->getValueType(),
493 		    p->getSetValueString());
494 	    }
495 	} else if (!valueOnly && p->isViewable() &&
496 	         (p->isVisibleByDefault() != p->isVisible()))
497 #else
498 	if (p->hasValue()) {
499 	    if (valueOnly) {
500 		status = fprintf(f,
501 		    "%s// input[%d]: defaulting = %d, value = %s\n",
502 		    indent,
503 		    i,
504 		    (p->isDefaulting() || p->isConnected() ? 1 : 0),
505 		    p->getSetValueString());
506 	    } else {
507 		// When a parameter is connected, print the value as
508 		// defaulting, so that when we read it back in, we do a
509 		// setInputSetValue() instead of a setInputValue()
510 		status = fprintf(f,
511 		    "%s// input[%d]: defaulting = %d, visible = %d,"
512 			" type = %d, value = %s\n",
513 		    indent,
514 		    i,
515 		    (p->isDefaulting() || p->isConnected() ? 1 : 0),
516 		    (p->isVisible()? 1 : 0),
517 		    (int) p->getValueType(),
518 		    p->getSetValueString());
519 	    }
520 	} else if (!valueOnly && p->isViewable() &&
521 	         (p->isVisibleByDefault() != p->isVisible()))
522 #endif
523 	    status = fprintf(f,
524 		"%s// input[%d]: visible = %d\n",
525 		indent,
526 		i, (p->isVisible() ? 1 : 0));
527     }
528     else
529     {
530 	Parameter *p = this->getOutputParameter(i);
531 	// Only print it if it is sending a value to an input
532 	// (i.e. it has an arc)
533 	if (p->hasValue()) {
534 	    if (valueOnly) {
535 		status = fprintf(f,
536 		    "%s// output[%d]: defaulting = %d, value = %s\n",
537 		    indent,
538 		    i,
539 		    p->isDefaulting() ? 1 : 0,
540 		    p->getSetValueString());
541 	    } else {
542 		status = fprintf(f,
543 		    "%s// output[%d]: visible = %d, type = %d, value = %s\n",
544 		    indent,
545 		    i,
546 		    (p->isVisible()? 1 : 0),
547 		    (int) p->getValueType(),
548 		    p->getSetValueString());
549 	    }
550 	} else if (!valueOnly && p->isViewable() &&
551 		 (p->isVisibleByDefault() != p->isVisible()))
552 	    status = fprintf(f,
553 		"%s// output[%d]: visible = %d\n",
554 		indent,
555 		i,
556 		(p->isVisible() ? 1 : 0));
557     }
558 
559     return status > 0;
560 }
561 
562 //////////////////////////////////////////////////////////////////////////////
563 //
564 // Print the '|'d section below for this node into what will be a .net file.
565 //
566 // FIXME: for now we don't do the comments (PrintType).
567 // FIXME: Do we need to be able to print to a string, can we just get
568 //		by with a FILE?
569 //
570 /*
571 ||  //
572 ||  // node Import[1]: x = 48, y = 14, inputs = 6, label = Import
573 ||  // input[1]: type = 64, value = "network8.dx"
574 ||  //
575 */
netPrintCommentHeader(FILE * f)576 boolean Node::netPrintCommentHeader(FILE *f)
577 {
578     int i, status, x, y, num;
579     const char *name;
580 
581     name = this->getNameString();
582     ASSERT(name);
583 
584     status = fprintf(f,"%s// \n",__indent);
585     if (status < 0)
586 	return FALSE;
587 
588     //
589     // Print the node name comment
590     //
591     this->getVpePosition(&x, &y);
592     if (this->getOutputCount() != this->getDefinition()->getOutputCount())
593 	status = fprintf(f,"%s// node %s[%d]: x = %d, y = %d, inputs = %d, "
594 			   "outputs = %d, label = %s\n",
595 		    __indent,
596 		    this->getNameString(),
597 		    this->getInstanceNumber(), x, y,
598 		    this->getInputCount(),
599 		    this->getOutputCount(),
600 		    this->getLabelString());
601     else
602 	status = fprintf(f,"%s// node %s[%d]: x = %d, y = %d, inputs = %d, "
603 			   "label = %s\n",
604 		    __indent,
605 		    this->getNameString(),
606 		    this->getInstanceNumber(), x, y,
607 		    this->getInputCount(),
608 		    this->getLabelString());
609     if (status < 0)
610 	return FALSE;
611 
612     //
613     // Print the inputs that have values
614     //
615     num = this->getInputCount();
616     for (i=1 ; i<=num ; i++) {
617 	if (!this->printIOComment(f, TRUE, i,__indent))
618 	    return FALSE;
619     }
620 
621     //
622     // Print the outputs that have values
623     //
624     num = this->getOutputCount();
625     for (i=1 ; i<=num ; i++) {
626 	if (!this->printIOComment(f, FALSE, i, __indent))
627 	    return FALSE;
628     }
629 
630 #if WORKSPACE_PAGES
631     if (!this->printGroupComment(f))
632 #else
633     if(NOT this->netPrintPgrpComment(f))
634 #endif
635 	return FALSE;
636 
637     if (!this->netPrintAuxComment(f))
638 	return FALSE;
639 
640     status = fprintf(f,"%s//\n",__indent);
641     if (status < 0)
642 	return FALSE;
643 
644     return TRUE;
645 
646 }
647 
648 #if WORKSPACE_PAGES
649 #else
netPrintPgrpComment(FILE * f)650 boolean Node::netPrintPgrpComment(FILE *f)
651 {
652     const char *gname = this->getGroupName();
653     if(NOT gname)
654 	return TRUE;
655 
656     if(fprintf(f,"%s// process group: %s\n",__indent, gname) < 0)
657 	return FALSE;
658 
659     return TRUE;
660 }
661 #endif
662 
663 //////////////////////////////////////////////////////////////////////////////
664 // Print the '|'d section below for this node.  If PrintType is set
665 // then also print the '||'d section. In the example below 'prefix'
666 // contains the 2 leading spaces.
667 //
668 //
669 /*
670 ||  //
671 ||  // node Import[1]: x = 48, y = 14, inputs = 6, label = Import
672 ||  // input[1]: type = 64, value = "network8.dx"
673 ||  //
674  |  Import_1_out_1 =
675  |       Import(
676  |          Import_1_in_1,
677  |          Import_1_in_2,
678  |          Import_1_in_3,
679  |          Import_1_in_4,
680  |          Import_1_in_5,
681  |          Import_1_in_6
682  |      ) [instance: 1, cache: 1, pgroup: "pg1"];
683 */
netNodeString(const char * prefix)684 char *Node::netNodeString(const char *prefix)
685 {
686     int buflen;
687     const char *name;
688     char *outputs, *inputs, *module, *attributes, *s;
689 
690     //
691     // Get the name of the module that is used to do the work for this node.
692     //
693     name = this->getExecModuleNameString();
694     ASSERT(name);
695 
696     //
697     // Print the outputs for this node
698     //
699     outputs = this->outputParameterNamesString(prefix);
700 
701 
702     //
703     // Print the Name of this node as 'Name(\n'
704     //
705     module = new char[STRLEN(__indent) + STRLEN(name) + 16];
706     sprintf(module,"%s%s(",__indent,name);
707 
708     //
709     // Print node inputs
710     //
711     inputs = this->inputParameterNamesString(prefix,__indent);
712 
713 #if WORKSPACE_PAGES
714     const char *gname = this->getGroupName(theSymbolManager->getSymbol(PROCESS_GROUP));
715 #else
716     const char *gname = this->getGroupName();
717 #endif
718     if(NOT gname)
719     {
720     	char *fmt = "%s) [instance: %d, cache: %d];";
721     	attributes = new char[STRLEN(__indent) + STRLEN(fmt) + 32];
722     	sprintf(attributes, fmt, __indent,
723 			    this->instanceNumber,
724 			    this->getNodeCacheability());
725 
726     }
727     else
728     {
729     	char *fmt = "%s) [instance: %d, cache: %d, group: \"%s\"];";
730     	attributes = new char[STRLEN(__indent) + STRLEN(fmt) +
731 			      STRLEN(gname) + 32];
732     	sprintf(attributes, fmt, __indent,
733 			    this->instanceNumber,
734 			    this->getNodeCacheability(),
735 			    gname);
736     }
737 
738     buflen = STRLEN(module) + STRLEN(outputs) +
739 		STRLEN(inputs) + STRLEN(attributes);
740     s = new char[buflen+40];
741     if (this->getOutputCount() == 0)
742     {
743 	sprintf(s,"%s\n%s\n%s\n",
744 		    module,(inputs ? inputs : "") ,attributes);
745     }
746     else
747     {
748 	sprintf(s,"%s = \n%s\n%s\n%s\n",
749 		    (outputs ? outputs : ""),
750 		    module,
751 		    (inputs ? inputs : ""),
752 		    attributes);
753     }
754 
755     if (outputs) delete outputs;
756     delete module;
757     if (inputs)  delete inputs;
758     delete attributes;
759 
760     return s;
761 }
762 //
763 // Do any work that must be done before sending the macro/network
764 // to the server.
765 // Be default, Nodes do not have any work that needs to be done for sending.
766 //
prepareToSendNode()767 void Node::prepareToSendNode()
768 {
769 }
prepareToSendValue(int index,Parameter * p)770 void Node::prepareToSendValue(int index, Parameter *p)
771 {
772 }
773 
netPrintNode(FILE * f,PrintType dest,const char * prefix,PacketIFCallback callback,void * clientdata)774 boolean Node::netPrintNode(FILE *f, PrintType dest, const char *prefix,
775 		PacketIFCallback callback, void *clientdata)
776 {
777     char *s;
778     DXPacketIF *pif = theDXApplication->getPacketIF();
779     boolean r = TRUE;
780 
781     if (dest == PrintFile || dest == PrintCut || dest == PrintCPBuffer) {
782         if (!this->netPrintCommentHeader(f))
783 	    return FALSE;
784     } else if (pif) {	// We have a connection to the executive/server
785   	//
786   	// If this node has a message protocol with the executive, then
787   	// update any state associated with the protocol.
788   	//
789 	if (this->hasModuleMessageProtocol())
790 	    this->updateModuleMessageProtocol(pif);
791   	//
792   	// Do any work that must be done before executing the macro/network
793   	// that this node belongs to.
794   	//
795 	this->prepareToSendNode();
796     }
797 
798     s = this->netNodeString(prefix);
799 
800 
801     if (dest == PrintFile || dest == PrintCut || dest == PrintCPBuffer) {
802 	if (fputs(s, f) < 0)
803 	    r = FALSE;
804 	if (callback != NUL(PacketIFCallback))
805 	    callback(clientdata,s);
806     } else {
807 	ASSERT (dest == PrintExec);
808 	pif->sendBytes(s);
809     }
810 
811     delete s;
812 
813     return r;
814 
815 }
816 
817 //
818 // Returns a string that is used to register this->ExecModuleMessageHandler()
819 // when this->hasModuleMessageProtocol() return TRUE.
820 // This version, returns an id that is unique to  this instance of this node.
821 //
getModuleMessageIdString()822 const char *Node::getModuleMessageIdString()
823 {
824 
825    if (!this->moduleMessageId) {
826        const char *name = this->getNameString();
827        int n = STRLEN(name) + 16;
828        this->moduleMessageId = new char[n];
829 
830        sprintf(this->moduleMessageId,"%s_%d",name, this->getInstanceNumber());
831    }
832 
833    return (const char*)this->moduleMessageId;
834 }
835 
836 //
837 // Update the state of message handling for a module/UI message.
838 // This is called only when we send a Node's module call to the executive
839 // and the node has a module messaging protocol as defined by
840 // this->hasModuleMessageProtocol().
841 //
updateModuleMessageProtocol(DXPacketIF * pif)842 void Node::updateModuleMessageProtocol(DXPacketIF *pif)
843 {
844     const char *id = this->getModuleMessageIdString();
845 
846 	if (this->expectingModuleMessage()) {
847 		//
848 		// Install a callback to handle messages from the module
849 		//
850 		pif->setHandler(DXPacketIF::INFORMATION,
851 			Node::ExecModuleMessageHandler,
852 			(void*)this, id);
853 	} else  {
854 		//
855 		// Remove the handler in case it was previously installed.
856 		//
857 		pif->setHandler(DXPacketIF::INFORMATION,
858 			NULL,   (void*)this, id);
859 	}
860 }
861 //
862 // Return TRUE/FALSE, indicating whether or not we support a message protocol
863 // between the executive module that runs for this node and the  UI.
864 // Be default Nodes do not have message protocols.
865 //
hasModuleMessageProtocol()866 boolean Node::hasModuleMessageProtocol()
867 {
868     return FALSE;
869 }
870 //
871 // Return TRUE/FALSE, indicating whether or not we expect to receive
872 // a message from the UI when our module executes in the executive.
873 // Be default Nodes do not expect messages.
874 //
expectingModuleMessage()875 boolean Node::expectingModuleMessage()
876 {
877     return FALSE;
878 }
879 //
880 // This dispatches messages to this->execModuleMessageHandler().
881 // Messages are not noticed unless this handler is installed
882 // (in this->netPrintNode()).
883 //
ExecModuleMessageHandler(void * clientData,int id,void * line)884 void Node::ExecModuleMessageHandler(void *clientData, int id, void *line)
885 {
886    Node *node = (Node*)clientData;
887    node->execModuleMessageHandler(id,(const char*)line);
888 }
889 //
890 // Called when a message is received from the executive after
891 // this->ExecInfoMessageHandler() is registered to receive messages
892 // for this node.  The format of the message coming back is defined
893 // by the derived class.
894 //
execModuleMessageHandler(int id,const char * line)895 void Node::execModuleMessageHandler(int id, const char *line)
896 {
897     fprintf(stderr,"Node: Saw unexpected module message, id %d...\n",id);
898     fprintf(stderr,"%s\n",line);
899 }
900 
901 
902 #if 0
903 //////////////////////////////////////////////////////////////////////////////
904 //
905 // Get name of a parameter and its value
906 // The format of the string is 'Parameter name = value;'.
907 // index is 1 based.
908 // It returns the string representing the assignment.
909 // The returned string must be deleted by the caller.
910 //
911 int Node::getParameterNameEqualsValue(Parameter *p,
912 					const char *prefix, int index)
913 {
914     const char *pval;
915     char *p, *retstr, pname[512];
916 
917     pname[0] = '\0';
918     this->strcatParameterNameLvalue(pname, p, prefix, index);
919     strcat(s, " = ");
920     if (p->isInput())
921 	pval = this->getInputValueString(index);
922     else
923 	pval = this->getOutputValueString(index);
924 
925     retstr = new char[STRLEN(pname) + STRLEN(pval) + 2];
926 
927     p = retstr;
928     strcpy(retstr,pname);
929     p += STRLEN(retstr);
930     strcat(p,v);
931     p += STRLEN(p);
932     strcat(p,";");
933 
934     return retstr;
935 }
936 #endif
937 
938 //////////////////////////////////////////////////////////////////////////////
939 //
940 // Concatenate the name of a parameter but not its value to the given string.
941 // index is 1 based.  it returns the ammount of stuff added to s
942 //
strcatParameterNameLvalue(char * s,Parameter * p,const char * prefix,int index)943 int Node::strcatParameterNameLvalue(char *s, Parameter *p,
944 	const char *prefix, int index)
945 {
946 
947     const char *ioname;
948 
949     if (p->isInput())
950 	ioname = "in";
951     else
952 	ioname = "out";
953 
954     ASSERT(s);
955     s += STRLEN(s);
956     return SPRINTF(s,"%s%s_%d_%s_%d",
957 		prefix, this->getNameString(),this->getInstanceNumber(),
958 		ioname, index);
959 }
strcatParameterValueString(char * s,Parameter * p,int index)960 int Node::strcatParameterValueString(char *s, Parameter *p, int index)
961 {
962     const char *v = p->getValueString();
963 
964     if (s)
965 	strcat(s, v);
966     return STRLEN(v);
967 }
968 ///////////////////////////////////////////////////////////////////////////////
969 //
970 // Print the value of the index'th parameter if it contains a value
971 // (i.e. it's arc list is empty).  Returns NULL if no string is to be printed.
972 // index is 1 based.
973 // The returned string must be deleted by the caller.
974 //
ioValueString(List * io,int index,const char * prefix)975 char *Node::ioValueString(List *io, int index, const char *prefix)
976 {
977     char *retstr = NUL(char*);
978     Parameter *p;
979 
980     ASSERT(index >= 1);
981 
982     p = (Parameter*)io->getElement(index);
983     ASSERT(p);
984 
985     if (p->isNeededValue()) {
986 	const char *pval;
987 	int pname_size;
988 	char *c, pname[512];
989 
990 	pname[0] = '\0';
991 	pname_size = this->strcatParameterNameLvalue(pname, p, prefix, index);
992 	strcat(pname, " = ");
993 	pname_size += 3;
994 	if (p->isInput())
995 	    pval = this->getInputValueString(index);
996 	else
997 	    pval = this->getOutputValueString(index);
998 
999 	retstr = new char[pname_size + STRLEN(pval) + 2];
1000 
1001 	c = retstr;
1002 	strcpy(retstr,pname);
1003 	c += STRLEN(retstr);
1004 	strcat(c,pval);
1005 	c += STRLEN(c);
1006 	strcat(c,";");
1007 
1008     }
1009     return retstr;
1010 }
1011 
1012 ///////////////////////////////////////////////////////////////////////////////
1013 //
1014 // Print the value of the input and output parameters  if they contain a value
1015 // (i.e. it's arc list is empty).
1016 // index is 1 based.
1017 // Returns NULL if no values need to be printed, otherwise a string containing
1018 // parameter value pairs.
1019 //
valuesString(const char * prefix)1020 char *Node::valuesString(const char *prefix)
1021 {
1022 
1023     char  *s=NUL(char*), *buf;
1024     int   size, cnt, i;
1025     boolean first = TRUE;;
1026 
1027 #if defined(STATIC_MACROS)
1028     //
1029     // Macros do not use global variables as inputs so we do not
1030     // need to send the input value assignments.
1031     //
1032     if (!this->network->isMacro())  {
1033 #endif
1034     //
1035     // Print the input values
1036     //
1037     cnt = this->getInputCount();
1038     for (i=1 ; i<=cnt ; i++) {
1039 	if ( (buf = this->inputValueString(i,prefix)) )
1040 	{
1041 	    if (s)
1042 		first = FALSE;
1043 	    size = STRLEN(buf) + STRLEN(s) + 2;
1044 	    s = (char*)REALLOC(s,size);
1045 	    if (first)
1046 		s = strcpy(s, buf);
1047 	    else
1048 		s = strcat(s,buf);
1049 	    strcat(s,"\n");
1050 	    delete buf;
1051 	}
1052     }
1053 #if defined(STATIC_MACROS)
1054     }
1055 #endif
1056 
1057     //
1058     // Print the output values
1059     //
1060     cnt = this->getOutputCount();
1061     for (i=1 ; i<=cnt ; i++) {
1062 	if ( (buf = this->outputValueString(i,prefix)) )
1063 	{
1064 	    if (s)
1065 		first = FALSE;
1066 	    size = STRLEN(buf) + STRLEN(s) + 2;
1067 	    s = (char*)REALLOC(s,size);
1068 	    if (first)
1069 		s = strcpy(s, buf);
1070 	    else
1071 		s = strcat(s,buf);
1072 	    strcat(s,"\n");
1073 	    delete buf;
1074 	}
1075     }
1076 
1077     return s;
1078 
1079 }
1080 
printValues(FILE * f,const char * prefix,PrintType dest)1081 boolean Node::printValues(FILE *f, const char *prefix, PrintType dest)
1082 {
1083     char *s;
1084     boolean r = TRUE;
1085 
1086     s = this->valuesString(prefix);
1087     if (s) {
1088 	if (dest == PrintFile || dest == PrintCut || dest == PrintCPBuffer) {
1089 	    if (fputs(s, f) < 0)
1090 		r = FALSE;
1091 	} else {
1092 	    ASSERT (dest == PrintExec);
1093 	    DXPacketIF* pif = theDXApplication->getPacketIF();
1094 	    pif->sendBytes(s);
1095 	}
1096 
1097 	delete s;
1098     }
1099     return r;
1100 }
1101 
1102 ///////////////////////////////////////////////////////////////////////////////
1103 //
1104 // Send all values that are in one expression.
sendValues(boolean ignoreDirty)1105 boolean Node::sendValues(boolean ignoreDirty)
1106 {
1107     DXPacketIF *pif  = theDXApplication->getPacketIF();
1108 
1109     if (!pif)
1110 	return TRUE;
1111 
1112     const char *prefix = this->network->getPrefix();
1113     int i, cnt;
1114     char *names=NULL;
1115     char *values=NULL;
1116     int nameLen = 0;
1117     int valueLen = 0;
1118 
1119     //
1120     // Print the dirty inputs
1121     //
1122     cnt = this->getInputCount();
1123     ListIterator li(this->inputParameters);
1124     Parameter *p;
1125 #if defined(STATIC_MACROS)
1126     //
1127     // Macros do not use global variables as inputs so we do not
1128     // need to send the input value assignments.
1129     //
1130     if (!this->network->isMacro())  {
1131 #endif
1132 		for (i=1 ; i<=cnt && NULL != (p = (Parameter *)li.getNext()); i++)
1133 		{
1134 			if (p->isNeededValue(ignoreDirty))
1135 			{
1136 				//
1137 				// Do any work that is necessary before sending the value .
1138 				//
1139 				this->prepareToSendValue(i, p);
1140 				if (nameLen == 0)
1141 				{
1142 					names = (char *)MALLOC(100);
1143 					*names = '\0';
1144 					nameLen = this->strcatParameterNameLvalue(names, p, prefix, i);
1145 
1146 					int l = this->strcatParameterValueString(NULL, p, i);
1147 					values = (char *)MALLOC(l+10);
1148 					*values = '\0';
1149 					valueLen = this->strcatParameterValueString(values, p, i);
1150 				}
1151 				else
1152 				{
1153 					names = (char *)REALLOC((void*)names, nameLen + 100 + 2);
1154 					strcat(names, ", ");
1155 					nameLen += 2 + this->strcatParameterNameLvalue(names, p, prefix, i);
1156 
1157 					int l = this->strcatParameterValueString(NULL, p, i);
1158 					values = (char *)REALLOC((void*)values, valueLen + l+10);
1159 					strcat(values, ", ");
1160 					valueLen += 2 + this->strcatParameterValueString(values, p, i);
1161 				}
1162 				p->clearDirty();
1163 			}
1164 		}
1165 #if defined(STATIC_MACROS)
1166     }
1167 #endif
1168 
1169     //
1170     // Print the outputs that have values
1171     //
1172     cnt = this->getOutputCount();
1173     li.setList(this->outputParameters);
1174     for (i=1 ; i<=cnt && NULL != (p = (Parameter *)li.getNext()); i++)
1175     {
1176 	if (p->isNeededValue(ignoreDirty))
1177 	{
1178 	    //
1179 	    // Do any work that is necessary before sending the value .
1180 	    //
1181 	    this->prepareToSendValue(i, p);
1182 
1183 	    if (nameLen == 0)
1184 	    {
1185 		names = (char *)MALLOC(100);
1186 		*names = '\0';
1187 		nameLen = this->strcatParameterNameLvalue(names, p, prefix, i);
1188 
1189 		int l = this->strcatParameterValueString(NULL, p, i);
1190 		values = (char *)MALLOC(l+10);
1191 		*values = '\0';
1192 		valueLen = this->strcatParameterValueString(values, p, i);
1193 	    }
1194 	    else
1195 	    {
1196 		names = (char *)REALLOC((void*)names, nameLen + 100 + 2);
1197 		strcat(names, ", ");
1198 		nameLen += 2 + this->strcatParameterNameLvalue(names, p, prefix, i);
1199 
1200 		int l = this->strcatParameterValueString(NULL, p, i);
1201 		values = (char *)REALLOC((void*)values, valueLen + l+10);
1202 		strcat(values, ", ");
1203 		valueLen += 2 + this->strcatParameterValueString(values, p, i);
1204 	    }
1205 	    p->clearDirty();
1206 	}
1207     }
1208 
1209     if (nameLen > 0)
1210     {
1211 	char *s = new char[nameLen + 3 + valueLen + 2];
1212 	strcpy(s, names);
1213 	strcat(s, " = ");
1214 	strcat(s, values);
1215 	strcat(s, ";");
1216 	pif->send(DXPacketIF::FOREGROUND, s);
1217 	delete s;
1218 	FREE((void*)names);
1219 	FREE((void*)values);
1220     }
1221 
1222     return TRUE;
1223 }
1224 
1225 
1226 //////////////////////////////////////////////////////////////////////////////
1227 //
1228 // Parse the .net file comment section for this node.
1229 //
1230 // Set the instance number, the x,y position, and its inputs.
1231 //
netParseComment(const char * comment,const char * filename,int lineno)1232 boolean Node::netParseComment(const char* comment,
1233 		const char* filename, int lineno)
1234 {
1235     ASSERT(comment);
1236 
1237     /*
1238      * Ignore comments that we do not recognize
1239      */
1240     return this->netParseNodeComment(comment, filename, lineno) ||
1241 		this->parseIOComment(TRUE, comment, filename, lineno) ||
1242 		this->parseIOComment(FALSE, comment, filename, lineno) ||
1243 #if WORKSPACE_PAGES
1244 		this->parseGroupComment(comment, filename, lineno) ||
1245 #else
1246 		this->netParsePgrpComment(comment, filename, lineno) ||
1247 #endif
1248 		this->netParseAuxComment(comment,filename,lineno);
1249 }
1250 
1251 //
1252 // Empty virtual method to parse comments (if any) that come after the
1253 // 'node', 'input', 'ouput' and 'process group' comments in the .net file.
1254 //
netParseAuxComment(const char * comment,const char * filename,int lineno)1255 boolean Node::netParseAuxComment(const char* comment,
1256                 const char* filename, int lineno)
1257 {
1258     return FALSE;
1259 }
1260 //
1261 // Empty virtual method to be overridden by subclasses that prints out
1262 // node specific comments after the standard comments in the .net file.
1263 //
netPrintAuxComment(FILE * f)1264 boolean Node::netPrintAuxComment(FILE *f)
1265 {
1266     return TRUE;
1267 }
1268 
1269 #if WORKSPACE_PAGES
1270 #else
netParsePgrpComment(const char * comment,const char * filename,int lineno)1271 boolean Node::netParsePgrpComment(const char* comment,
1272                 		  const char* filename, int lineno)
1273 {
1274     char *name;
1275 
1276     if (!EqualSubstring(" process group:",comment,15))
1277 	return FALSE;
1278 
1279     name = strchr(comment, ':');
1280     name++;
1281     SkipWhiteSpace(name);
1282 
1283     if(NOT name)    return FALSE;
1284 
1285     this->addToGroup(name);
1286     return TRUE;
1287 }
1288 #endif
1289 
1290 
1291 //
1292 // Parse an 'input[i]' or 'output[i]' .net file comment.
1293 //
parseIOComment(boolean input,const char * comment,const char * filename,int lineno,boolean valueOnly)1294 boolean Node::parseIOComment(boolean input, const char* comment,
1295 							 const char* filename, int lineno, boolean valueOnly)
1296 {
1297 	int      defaulting = 0, allowed_params, items_parsed, ionum, r, type_tmp;
1298 	int  visible = TRUE;
1299 	Type     type = DXType::UndefinedType;
1300 	char     *value, *ioname;
1301 	boolean	parse_error = FALSE;
1302 
1303 	ASSERT(comment);
1304 
1305 	if (input) {
1306 		if (!EqualSubstring(" input[",comment,7))
1307 			return FALSE;
1308 
1309 		if (valueOnly) {
1310 			if (sscanf(comment, " input[%d]: defaulting = %d",
1311 				&ionum, &defaulting) != 2)
1312 				parse_error = TRUE;
1313 			type = DXType::UndefinedType;
1314 		} else {
1315 			items_parsed = sscanf(comment,
1316 				" input[%d]: defaulting = %d, visible = %d, type = %d",
1317 				&ionum, &defaulting, &visible, &type_tmp);
1318 			type = (Type) type_tmp;
1319 
1320 			if (items_parsed != 4) {
1321 				// Invisibility added 3/30/93
1322 				items_parsed = sscanf(comment, " input[%d]: visible = %d",
1323 					&ionum, &visible);
1324 				if (items_parsed != 2) {
1325 					// Backwards compatibility added 3/25/93
1326 					items_parsed = sscanf(comment, " input[%d]: type = %d",
1327 						&ionum, &type_tmp);
1328 					type = (Type) type_tmp;
1329 
1330 					if (items_parsed != 2) {
1331 						items_parsed = sscanf(comment,
1332 							" input[%d]: defaulting = %d, type = %d",
1333 							&ionum, &defaulting, &type_tmp);
1334 						type = (Type) type_tmp;
1335 						if (items_parsed != 3)
1336 							parse_error = TRUE;
1337 					}
1338 				}
1339 				else
1340 				{
1341 					defaulting = 1;
1342 				}
1343 			}
1344 		}
1345 		ioname = "input";
1346 		allowed_params = this->getInputCount();
1347 	} else {	// An output
1348 
1349 		if (!EqualSubstring(" output[",comment,8))
1350 			return FALSE;
1351 
1352 		if (valueOnly) {
1353 			if (sscanf(comment, " output[%d]: defaulting = %d",
1354 				&ionum, &defaulting) != 2)
1355 				parse_error = TRUE;
1356 			type = DXType::UndefinedType;
1357 		} else {
1358 			// Invisibility added 3/30/93
1359 			items_parsed = sscanf(comment,
1360 				" output[%d]: visible = %d, type = %d",
1361 				&ionum, &visible, &type_tmp);
1362 			type = (Type) type_tmp;
1363 
1364 			if (items_parsed != 3) {
1365 
1366 				items_parsed = sscanf(comment, " output[%d]: type = %d",
1367 					&ionum, &type_tmp);
1368 				type = (Type) type_tmp;
1369 
1370 				if (items_parsed != 2) {
1371 					items_parsed = sscanf(comment, " output[%d]: visible = %d",
1372 						&ionum, &visible);
1373 					if (items_parsed != 2)
1374 						parse_error = TRUE;
1375 				}
1376 			}
1377 		}
1378 		ioname = "output";
1379 		allowed_params = this->getOutputCount();
1380 	}
1381 
1382 	if (parse_error)
1383 	{
1384 		ErrorMessage ("Can't parse %s comment file %s line %d",
1385 			ioname, filename, lineno);
1386 		return TRUE;
1387 	}
1388 	/*
1389 	* If the input parameter is out of bounds, then something is wrong...
1390 	*/
1391 	if (ionum > allowed_params)
1392 	{
1393 		ErrorMessage ("Bad %s number (%d) file %s line %d",
1394 			input? "input": "output", ionum, filename, lineno);
1395 		return TRUE;
1396 	}
1397 
1398 
1399 
1400 	/*
1401 	* If parsed ok and node exists, convert value.
1402 	*/
1403 	value = (char *) strstr(comment, "value =");
1404 	if (value != NUL(char*))
1405 	{
1406 		value = strchr(value,'=') + 2;
1407 
1408 		//
1409 		// When we went to the C++ ui, the bit masks for types changed.
1410 		// If we're reading a pre-UI++ network then convert the types.
1411 		// valueOnly was added in version 3.
1412 		//
1413 		if (this->getNetwork()->getNetMajorVersion() <= 1)
1414 			type = DXType::ConvertVersionType(type);
1415 
1416 
1417 		if (input) {
1418 			if (value[0] == '(' && value[STRLEN(value)-1] == ')') {
1419 				// Skip descriptive settings
1420 				defaulting = 1;
1421 				r = DXType::ObjectType;
1422 #if 11
1423 			} else if (defaulting) {
1424 #else
1425 				//
1426 				// This check for NULL shouldn't really be necessary, except
1427 				// that there is a bug somewhere in ConfigurationDialog
1428 				// that seems too risky to fix just before 3.1
1429 				// Bug is as follows,
1430 				//   1) Place Echo
1431 				//   2) Open CDB and type NULL into first param
1432 				//   3) Save net
1433 				//   4) Read in net.
1434 				//   5) Execute and nothing goes in MsgWin, which is correct
1435 				//   6) Open CDB, note non-null value in CDB and execute and get
1436 				//	  	a different result.
1437 				//
1438 			} else if (defaulting || EqualString(value,"NULL")) {
1439 #endif
1440 				r = this->setInputSetValue(ionum, value, type, FALSE);
1441 				if (r == DXType::UndefinedType &&
1442 					type != DXType::UndefinedType)
1443 					r = this->setInputSetValue(ionum, value,
1444 					DXType::UndefinedType, FALSE);
1445 			} else {
1446 				r = this->setInputValue(ionum, value, type, FALSE);
1447 				if (r == DXType::UndefinedType &&
1448 					type != DXType::UndefinedType)
1449 					r = this->setInputValue(ionum, value,
1450 					DXType::UndefinedType, FALSE);
1451 			}
1452 		} else {
1453 			r = this->setOutputValue(ionum, value, type, FALSE);
1454 			if (r == DXType::UndefinedType &&
1455 				type != DXType::UndefinedType)
1456 				r = this->setOutputValue(ionum, value, DXType::UndefinedType,
1457 				FALSE);
1458 		}
1459 
1460 		if (r == DXType::UndefinedType) {
1461 			ErrorMessage(
1462 				"Encountered an erroneous input value (file %s, line %d)",
1463 				filename, lineno);
1464 			return TRUE;
1465 		}
1466 	}
1467 
1468 	if (!valueOnly) {
1469 		if (input) {
1470 			this->setInputVisibility(ionum, (boolean)visible);
1471 		} else {	// Outputs always use the value found in the file
1472 			this->useAssignedOutputValue(ionum, FALSE);
1473 			this->setOutputVisibility(ionum, (boolean)visible);
1474 		}
1475 	}
1476 
1477 
1478 	return TRUE;
1479 
1480 }
1481 
1482 
netParseNodeComment(const char * comment,const char * filename,int lineno)1483 boolean Node::netParseNodeComment(const char* comment,
1484 								  const char* filename, int lineno)
1485 {
1486 	int        items_parsed;
1487 	NodeDefinition *nd;
1488 	int        instance;
1489 	int        x;
1490 	int        y;
1491 	int        n_inputs;
1492 	int        n_outputs;
1493 	int        i;
1494 	char       node_name[1024];
1495 	char       labelstr[1024];
1496 
1497 	/*
1498 	* Parse the comment.
1499 	*/
1500 
1501 	if (!EqualSubstring(" node ",comment,6))
1502 		return FALSE;
1503 
1504 	items_parsed =	// Version DX/6000 2.0 style comments
1505 		sscanf
1506 		(comment,
1507 		" node %[^[][%d]: x = %d, y = %d, inputs = %d, outputs = %d, label = %[^\n]",
1508 		node_name,
1509 		&instance,
1510 		&x,
1511 		&y,
1512 		&n_inputs,
1513 		&n_outputs,
1514 		labelstr);
1515 
1516 	if (items_parsed != 7) {	// Try pre Version DX/6000 2.0 style comments
1517 		items_parsed =	// Version DX/6000 1.2 style comments
1518 			sscanf
1519 			(comment,
1520 			" node %[^[][%d]: x = %d, y = %d, inputs = %d, label = %[^\n]",
1521 			node_name,
1522 			&instance,
1523 			&x,
1524 			&y,
1525 			&n_inputs,
1526 			labelstr);
1527 
1528 		if (items_parsed != 6) {// Try pre Version DX/6000 1.2 style comments
1529 			items_parsed =
1530 				sscanf(comment,
1531 				" node %[^[][%d]: x = %d, y = %d, label = %[^\n]",
1532 				node_name,
1533 				&instance,
1534 				&x,
1535 				&y,
1536 				labelstr);
1537 			if (items_parsed != 5)
1538 			{
1539 				// FIXME : should be ModelessErrorMessageDialog
1540 #ifdef NOT_YET
1541 				ErrorMessage
1542 					("#10001", "node", filename, lineno);
1543 				_error_occurred = TRUE;
1544 #else
1545 				ErrorMessage("Can not parse node comment at "
1546 					"line %d in file %s",
1547 					lineno, filename);
1548 #endif
1549 				return TRUE;
1550 			}
1551 		}
1552 	}
1553 
1554 	/*
1555 	* Get definition for this node.
1556 	*/
1557 	nd = (NodeDefinition*)
1558 		theNodeDefinitionDictionary->findDefinition(node_name);
1559 	if (!nd) {
1560 		ErrorMessage("Undefined module %s at line %d in file %s",
1561 			node_name, lineno, filename);
1562 		return FALSE;
1563 	}
1564 
1565 	//    printf ("Number of inputs found = %d, number defined = %d\n",
1566 	//		n_inputs, this->definition->getInputCount());
1567 	/*
1568 	* If old syle comment, set number of inputs to that of module definition.
1569 	*/
1570 	if (items_parsed < 7)
1571 		n_outputs = this->getOutputCount();
1572 	if (items_parsed < 6)
1573 		n_inputs =  this->getInputCount();
1574 
1575 	//
1576 	// Set the label for this module.
1577 	//
1578 	this->setLabelString(labelstr);
1579 
1580 	/*
1581 	* Set the instance number in the node.
1582 	*/
1583 	this->setInstanceNumber(instance);
1584 	this->setVpePosition(x,y);
1585 
1586 
1587 	/*
1588 	* Count the inputs, if not the default and the inputs are repeatable
1589 	* then add some inputs.
1590 	* If there are fewer inputs in the file, silently assume that
1591 	* this is an old network.
1592 	*/
1593 	if (n_inputs != this->getInputCount()) {
1594 		if (this->isInputRepeatable()) {
1595 			int delta_inputs = n_inputs - this->getInputCount();
1596 			boolean adding = delta_inputs > 0;
1597 			if (!adding)
1598 				delta_inputs = -delta_inputs;
1599 			int sets;
1600 			if (delta_inputs % this->getInputRepeatCount() != 0) {
1601 				ErrorMessage("Number of repeatable input parameters does not "
1602 					"divide number of parameters for module %s",
1603 					this->getNameString());
1604 				return TRUE;
1605 			}
1606 			sets = delta_inputs/getInputRepeatCount();
1607 			for (i=0  ; i<sets ; i++) {
1608 				if (adding) {
1609 					if (!this->addInputRepeats()) {
1610 						ErrorMessage("Can't add repeated input parameters");
1611 						return TRUE;
1612 					}
1613 				} else {
1614 					if (!this->removeInputRepeats()) {
1615 						ErrorMessage("Can't remove repeated input parameters");
1616 						return TRUE;
1617 					}
1618 				}
1619 			}
1620 		}
1621 		// else expect the network parser to recognize that the definition
1622 		// has changed and indicate so.
1623 	}
1624 
1625 	if (n_outputs != this->getOutputCount()) {
1626 		if (this->isOutputRepeatable()) {
1627 			int delta_outputs = n_outputs - this->getOutputCount();
1628 			boolean adding = delta_outputs > 0;
1629 			if (!adding)
1630 				delta_outputs = -delta_outputs;
1631 			int sets;
1632 			if (delta_outputs % this->getOutputRepeatCount() != 0) {
1633 				ErrorMessage("Number of repeatable output parameters does "
1634 					"not divide number of parameters for module %s",
1635 					this->getNameString());
1636 				return TRUE;
1637 			}
1638 			sets = delta_outputs/getOutputRepeatCount();
1639 			for (i=0  ; i<sets ; i++) {
1640 				if (adding) {
1641 					if (!this->addOutputRepeats()) {
1642 						ErrorMessage("Can't add repeated output parameters");
1643 						return TRUE;
1644 					}
1645 				} else {
1646 					if (!this->removeOutputRepeats()) {
1647 						ErrorMessage("Can't remove repeated output parameters");
1648 						return TRUE;
1649 					}
1650 				}
1651 			}
1652 		}
1653 		// else expect the network parser to recognize that the definition
1654 		// has changed and indicate so.
1655 	}
1656 
1657 
1658 	/*
1659 	* Increment the module instance count if the current
1660 	* node instance count is higher.
1661 	*/
1662 	if (instance > this->definition->getCurrentInstance())
1663 		this->definition->setNextInstance(instance+1);
1664 
1665 	return TRUE;
1666 
1667 }
1668 
1669 //
1670 // Set the stored value.
1671 // If the parameter is not defaulting, this is
1672 // the same as setValue, but if it is defaulting, then we set the
1673 // value but leave the parameter clean and defaulting and ignore 'send'.
1674 //
1675 // Internal note: We handle our own notification (i.e. calls to
1676 // ioParameterStatusChanged()) so that multiple intermediate notifications
1677 // are avoided.
1678 //
setInputSetValue(int index,const char * value,Type type,boolean send)1679 Type Node::setInputSetValue(int index, const char *value,
1680 				Type type,
1681 				boolean send)
1682 {
1683 
1684     boolean was_defaulting = this->isInputDefaulting(index);
1685 
1686     //
1687     // If the parameter is already set (i.e. tab down) then just do
1688     // a normal set and return.
1689     //
1690     if (!was_defaulting)
1691 	return this->setInputValue(index,value,type,send);
1692 
1693     //
1694     // First set the value, don't send it and don't do notification (this
1695     // is the same as a normal set except we don't do notification).
1696     //
1697     type = this->setIOValue(&this->inputParameters, index, value,
1698 						type, FALSE, FALSE);
1699 
1700     if (type != DXType::UndefinedType) {
1701 	//
1702 	// Second, set the parameter back to defaulting, but again, don't
1703 	// do notification (again, this is the same as a normal setting of
1704 	// a parameter to defaulting, but no notification).
1705 	//
1706 	this->setIODefaultingStatus(index, TRUE, TRUE, FALSE, FALSE);
1707 
1708 	//
1709 	// Third, clear the parameter's dirty bit as we are only changing
1710 	// the set value (i.e. not the value the exec knows about).
1711 	//
1712 	this->clearInputDirty(index);
1713 
1714 	//
1715 	// Now do the notification that we've jumped through hoops to
1716 	// get right!
1717 	//
1718 	this->notifyIoParameterStatusChanged(TRUE, index,
1719 				Node::ParameterSetValueChanged);
1720     }
1721 
1722     return type;
1723 
1724 }
1725 
1726 
1727 //
1728 //  Mark the given parameter as clean.
1729 //
setIODirty(List * io,int index,boolean dirty)1730 void Node::setIODirty(List *io, int index, boolean dirty)
1731 {
1732     ASSERT(index >= 1);
1733     Parameter *p = (Parameter*)io->getElement(index);
1734     ASSERT(p);
1735     if (dirty)
1736         p->setDirty();
1737     else
1738         p->clearDirty();
1739 #if defined(STATIC_MACROS)
1740     //
1741     // If an input parameter is being marked dirty and it  is in a macro
1742     // then we need to resend the macro since the parameters value is
1743     // contained within the macro definition.
1744     //
1745     if (io == &this->inputParameters && this->network->isMacro())
1746 	this->network->setDirty();
1747 #endif
1748 }
1749 
1750 ///////////////////////////////////////////////////////////////////////////////
1751 //
1752 // Set the index'th parameter value of the parameter list given by io
1753 // to the given value  of type t.  if t==DXType::UndefinedType, then
1754 // be sure it can be assigned to one of the allowed types in the
1755 // ParameterDefinition.  If 'value' is NULL, then clear the value (and handle
1756 // as a successful setting) and return the default type for the given
1757 // parameter.
1758 // We you the Parameter methods to try and help certain values, become
1759 // the given type (i.e. by adding "'s, {}'s, []'s and so on).
1760 // If send is true (the default), the results will be sent to the server
1761 // if possible.
1762 // If notify is TRUE, then call ioParameterStatusChanged() with one of
1763 // Node::ParameterSetValueChanged and Node::ParameterValueChanged.
1764 // index is 1 based.
1765 //
1766 //
setIOValue(List * io,int index,const char * value,Type t,boolean send,boolean notify)1767 Type Node::setIOValue(List *io,
1768 		      int index,
1769 		      const char *value,
1770 		      Type t,
1771 		      boolean send,
1772 		      boolean notify)
1773 {
1774     ASSERT( index >= 1 );
1775 
1776     Parameter *p = (Parameter*)io->getElement(index);
1777     ASSERT(p);
1778     boolean was_set = !p->isDefaulting();
1779 
1780     Type type = DXType::UndefinedType;
1781     if (t == DXType::UndefinedType)
1782      	type = p->setValue(value);
1783     else if (p->setValue(value, t))
1784 	type = t;
1785 
1786     //
1787     // If a NULL value is found (i.e. clearing the value), then return the
1788     // type as the default type for the parameter as "NULL" should match any
1789     // type.
1790     //
1791     if (!value)
1792         type = p->getDefaultType();
1793 
1794     if (type != DXType::UndefinedType) {	// Success?
1795 	//
1796 	// And now send the value to the executive if there is a connection.
1797 	// Note that we don't need to set the network dirty, because we can
1798 	// send the changes ourselves.
1799 	//
1800 	if (send)
1801 	{
1802 	    DXPacketIF *pif = theDXApplication->getPacketIF();
1803 	    if (pif != NUL(DXPacketIF*))
1804 		 this->sendValues(FALSE);
1805 	}
1806 
1807 	if (notify) {
1808 	    //
1809 	    // Let those who need to know that the value has changed.
1810 	    //
1811 	    this->notifyIoParameterStatusChanged(io == &this->inputParameters, index,
1812 				was_set ?
1813 				    Node::ParameterSetValueChanged :
1814 				    Node::ParameterValueChanged);
1815 	}
1816      }
1817      return type;
1818 }
1819 
1820 //
1821 // This is similar to setIOValue.
1822 // We update the values internally, and send the shadowing input
1823 // value back to the executive with an Executive() call.
1824 // We use the Executive call instead of a direct assignment, because if
1825 // we are currently in execute-on-change  mode, the assignment would cause
1826 // extra executions.  The Executive() call (a dictionary update) avoids that.
1827 //
setIOValueQuietly(List * io,int index,const char * value,Type t)1828 Type Node::setIOValueQuietly(List *io, int index, const char *value, Type t)
1829 {
1830     t = this->setIOValue(io, index, value, t, FALSE);
1831     if (t == DXType::UndefinedType)
1832 	return t;
1833 
1834     this->sendValuesQuietly();
1835 
1836     return t;
1837 }
1838 
1839 //
1840 // Send all dirty input and output values to the executive in the
1841 // quiet way using the Executive("assign noexecute",...); call.
1842 //
sendValuesQuietly()1843 void Node::sendValuesQuietly()
1844 {
1845     DXPacketIF *pif = theDXApplication->getPacketIF();
1846 #define MAXMSGLEN 4096  // Longest message that the exec can accept
1847     char msg[MAXMSGLEN];
1848     char varname[500];
1849     const char *varval;
1850     int i;
1851 
1852 #if defined(STATIC_MACROS)
1853     //
1854     // Values sent quietly are always global variables.  Tool inputs
1855     // inside of macros are never sent as global variables so we want
1856     // to be sure we are not trying to do this.
1857     //
1858     // FIXME: now that I've removed the assert, are static macros endangered?
1859     //ASSERT(!this->network->isMacro());
1860 #endif
1861     if (!pif)
1862         return;
1863 
1864     for (i=1 ; i<=this->getInputCount() ; i++) {
1865         Parameter *p = this->getInputParameter(i);
1866         if (p->isNeededValue(FALSE)) {
1867             (void)this->getNetworkInputNameString(i, varname);
1868             varval = this->getInputValueString(i);
1869             sprintf(msg,"Executive(\"assign noexecute\",\"%s\",%s);",
1870                                         varname,varval);
1871             pif->send(DXPacketIF::FOREGROUND, msg);
1872             p->clearDirty();
1873         }
1874     }
1875     for (i=1 ; i<=this->getOutputCount() ; i++) {
1876         Parameter *p = this->getOutputParameter(i);
1877         if (p->isNeededValue(FALSE)) {
1878             (void)this->getNetworkOutputNameString(i, varname);
1879             varval = this->getOutputValueString(i);
1880             sprintf(msg ,"Executive(\"assign noexecute\",\"%s\",%s);",
1881                                         varname,varval);
1882             pif->send(DXPacketIF::FOREGROUND, msg);
1883             p->clearDirty();
1884         }
1885     }
1886 
1887 
1888 }
1889 
1890 //
1891 // Notify anybody that needs to know that a parameter has changed its
1892 // value.
1893 //
notifyIoParameterStatusChanged(boolean input,int index,NodeParameterStatusChange status)1894 void Node::notifyIoParameterStatusChanged(boolean input, int index,
1895                                 NodeParameterStatusChange status)
1896 {
1897     if (!this->network->isDeleted())
1898 	this->ioParameterStatusChanged(input, index, status);
1899 }
1900 
1901 
ioParameterStatusChanged(boolean input,int index,NodeParameterStatusChange status)1902 void Node::ioParameterStatusChanged(boolean input, int index,
1903 				NodeParameterStatusChange status)
1904 {
1905 
1906     //
1907     // If we have Configuration Dialog, let it know the value, arc or
1908     // visibility was changed.
1909     //
1910     if (this->cdb)  {
1911 	if (input)
1912 	    this->cdb->changeInput(index);
1913 	else
1914 	    this->cdb->changeOutput(index);
1915     }
1916 
1917     //
1918     // Now notify all nodes receiving this output that the value has changed.
1919     //
1920     if (!input && (status & PARAMETER_VALUE_CHANGED)) {
1921 	Ark *a;
1922 	List *l = (List*) this->getOutputArks(index);
1923 	ListIterator iterator(*l);
1924 
1925 	while ( (a = (Ark*)iterator.getNext()) ) {
1926 	    int in_index;
1927 	    Node *n = a->getDestinationNode(in_index);
1928 	    n->notifyIoParameterStatusChanged(TRUE, in_index, status);
1929 	}
1930     }
1931 
1932     //
1933     // Let the standin know about this. We don't notify StandIns about
1934     // arc changes since they are the ones that generate them.
1935     //
1936     if (this->standin && !(status & PARAMETER_ARC_CHANGED))
1937 	this->standin->ioStatusChange(index, !input, status);
1938 
1939     //
1940     // Tell the network that it has changed.
1941     //
1942 #if defined(STATIC_MACROS)
1943     //
1944     // If this is an input and the tool is in a macro, then we must always
1945     // resend the macro defnition because input values are contained within
1946     // the macro definition.  Otherwise we only need to mark the network
1947     // dirty if an arc has changed.
1948     //
1949     if (input && this->network->isMacro())
1950 	this->network->setDirty();
1951     else
1952 #endif
1953     if (status & PARAMETER_ARC_CHANGED)
1954 	this->network->setDirty();
1955     else
1956 	this->network->setFileDirty();
1957 }
1958 //
1959 // Add an Ark to to the index'th parameter of the parameter list given by io.
1960 // index is 1 based.
1961 //
addIOArk(List * io,int index,Ark * a)1962 boolean Node::addIOArk(List *io, int index, Ark *a)
1963 {
1964 
1965      Parameter *p;
1966      ASSERT( index >= 1 );
1967 
1968      p = (Parameter*)io->getElement(index);
1969 
1970      ASSERT(p);
1971      if (!p->addArk(a))
1972 	return FALSE;
1973 
1974      this->notifyIoParameterStatusChanged(io == &this->inputParameters, index,
1975 				Node::ParameterArkAdded);
1976      return TRUE;
1977 
1978 }
1979 ////////////////////////////////////////////////////////////////////////////////
1980 //
1981 // Determine if the index'th parameter in the give list is connected
1982 // (i.e. has an arc) to another parameter.
1983 //
isIOConnected(List * io,int index)1984 boolean Node::isIOConnected(List *io, int index)
1985 {
1986 
1987     Parameter *p;
1988     ASSERT( index >= 1 );
1989 
1990     p = (Parameter*)io->getElement(index);
1991     ASSERT(p);
1992 
1993     return p->isConnected();
1994 }
1995 ////////////////////////////////////////////////////////////////////////////////
1996 //
1997 //  is the index'th parameter defaulting?
1998 //
isIODefaulting(List * io,int index)1999 boolean Node::isIODefaulting(List *io, int index)
2000 {
2001 
2002     Parameter *p;
2003     ASSERT( index >= 1 );
2004 
2005     p = (Parameter*)io->getElement(index);
2006     ASSERT(p);
2007 
2008     return p->isDefaulting();
2009 }
2010 ////////////////////////////////////////////////////////////////////////////////
2011 //
2012 //  is the index'th parameter defaulting?
2013 //
isIOSet(List * io,int index)2014 boolean Node::isIOSet(List *io, int index)
2015 {
2016 
2017     Parameter *p;
2018     ASSERT( index >= 1 );
2019 
2020     p = (Parameter*)io->getElement(index);
2021     ASSERT(p);
2022 
2023     return p->hasValue();
2024 }
2025 ////////////////////////////////////////////////////////////////////////////////
2026 //
2027 //  Get the default value of the index'th parameter in the given list.
2028 //
getIODefaultValueString(List * io,int index)2029 const char *Node::getIODefaultValueString(List *io, int index)
2030 {
2031 
2032     Parameter *p;
2033     ASSERT( index >= 1 );
2034 
2035     p = (Parameter*)io->getElement(index);
2036     ASSERT(p);
2037 
2038     ParameterDefinition *d = p->getDefinition();
2039 
2040     return d->getDefaultValue();
2041 }
2042 ////////////////////////////////////////////////////////////////////////////////
2043 //
2044 //  Get the value of the index'th parameter in the given list.
2045 //
getIOValueString(List * io,int index)2046 const char *Node::getIOValueString(List *io, int index)
2047 {
2048 
2049     Parameter *p;
2050     ASSERT( index >= 1 );
2051 
2052     p = (Parameter*)io->getElement(index);
2053     ASSERT(p);
2054 
2055     return p->getValueString();
2056 }
2057 ////////////////////////////////////////////////////////////////////////////////
2058 //
2059 //  Get the type of the set value of the index'th parameter in the given list.
2060 //
getIOSetValueType(List * io,int index)2061 Type Node::getIOSetValueType(List *io, int index)
2062 {
2063 
2064     Parameter *p;
2065     ASSERT( index >= 1 );
2066 
2067     p = (Parameter*)io->getElement(index);
2068     ASSERT(p);
2069 
2070     return (p->hasValue() ? p->getValueType() : DXType::UndefinedType);
2071 }
2072 ////////////////////////////////////////////////////////////////////////////////
2073 //
2074 //  Get the set value of the index'th parameter in the given list, ignoring
2075 //  whether it's defaulting or not (NULL if not set).
2076 //
getIOSetValueString(List * io,int index)2077 const char *Node::getIOSetValueString(List *io, int index)
2078 {
2079 
2080     Parameter *p;
2081     ASSERT( index >= 1 );
2082 
2083     p = (Parameter*)io->getElement(index);
2084     ASSERT(p);
2085 
2086     return p->getSetValueString();
2087 }
2088 ////////////////////////////////////////////////////////////////////////////////
2089 //
2090 // Get the name of the parameter (as it appears in the MDF).
2091 // If there are repeatable parameter and the index indicates one of
2092 // the repeatable parameters (not in the first set), then add an index#
2093 // For example, Compute uses the following names
2094 //              "expression", "input", "input1", "input2",...
2095 //
getIONameString(List * io,int index,char * buf)2096 char *Node::getIONameString(List *io, int index, char *buf)
2097 {
2098     Parameter *p;
2099     ASSERT( index >= 1 );
2100     int repeat_num;     // The number on the MDF's REPEAT line
2101     int mdf_params=0;    // The number of in/outputs including the first
2102 			// set of inputs/outputs
2103     boolean input = (io == &this->inputParameters);
2104     char pname[128];
2105     const char *rval;
2106 
2107     p = (Parameter*)io->getElement(index);
2108     ASSERT(p);
2109 
2110     rval = p->getNameString();
2111 
2112     if ((input && this->isInputRepeatable()) ||
2113         (!input && this->isOutputRepeatable())) {
2114 	NodeDefinition *def = this->getDefinition();
2115  	if (input) {
2116 	    repeat_num = def->getInputRepeatCount();
2117 	    mdf_params = def->getInputCount();
2118 	} else {
2119 	    repeat_num = def->getOutputRepeatCount();
2120 	    mdf_params = def->getOutputCount();
2121 	}
2122     } else {
2123         repeat_num = 0;
2124     }
2125 
2126 
2127     //
2128     // If there are repeatable parameter and the index indicates one of
2129     // the repeatable parameters (not in the first set), then add an index
2130     // For example, Compute uses the following names
2131     //          "expression", "input", "input1", "input2",...
2132     //
2133     if ((repeat_num != 0) && (index > mdf_params)) {
2134         index = (index - mdf_params - 1) / repeat_num + 1;
2135         sprintf(pname,"%s%d",rval,index);
2136         rval = pname;
2137     }
2138 
2139     if (buf) {
2140         strcpy(buf,rval);
2141         rval = buf;
2142     } else {
2143         rval = DuplicateString(rval);
2144     }
2145 
2146     return (char*)rval;
2147 
2148 }
2149 
2150 ////////////////////////////////////////////////////////////////////////////////
2151 //
2152 // Get a list of strings that represent the allowed types for the index'th
2153 // parameter in the give list.  The return list is null terminated.
2154 //
getIOTypeStrings(List * io,int index)2155 const char * const *Node::getIOTypeStrings(List *io, int index)
2156 {
2157     Parameter *p;
2158     ASSERT( index >= 1 );
2159 
2160     p = (Parameter*)io->getElement(index);
2161     ASSERT(p);
2162 
2163     return p->getTypeStrings();
2164 }
2165 
2166 ////////////////////////////////////////////////////////////////////////////////
2167 //
2168 // Get a list of allowed types for the index'th
2169 // parameter in the give list.  The list must NOT be deleted by the caller.
2170 //
getIOTypes(List * io,int index)2171 List *Node::getIOTypes(List *io, int index)
2172 {
2173     Parameter *p;
2174     ASSERT( index >= 1 );
2175 
2176     p = (Parameter*)io->getElement(index);
2177     ASSERT(p);
2178 
2179     return p->getDefinition()->getTypes();
2180 }
2181 
2182 ////////////////////////////////////////////////////////////////////////////////
2183 //
2184 // Get the list of arcs for the index'th parameter in the given list.
2185 //
getIOArks(List * io,int index)2186 const List *Node::getIOArks(List *io, int index)
2187 {
2188     Parameter *p;
2189     ASSERT( index >= 1 );
2190 
2191     p = (Parameter*)io->getElement(index);
2192     ASSERT(p);
2193 
2194     return (const List*)&p->arcs;
2195 }
2196 
2197 ////////////////////////////////////////////////////////////////////////////////
2198 //
2199 // Return TRUE/FALSE indicating whether or not the give parameter from
2200 // the given list is set to be visible.
2201 //
isIOVisible(List * io,int index)2202 boolean Node::isIOVisible(List *io, int index)
2203 {
2204     Parameter *p;
2205     ASSERT( index >= 1 );
2206 
2207     p = (Parameter*)io->getElement(index);
2208     ASSERT(p);
2209 
2210     return p->isVisible();
2211 }
2212 ////////////////////////////////////////////////////////////////////////////////
2213 //
2214 // Set TRUE/FALSE indicating whether or not the give parameter from
2215 // the given list is set to be visible.
2216 //
setIOVisibility(List * io,int index,boolean v)2217 void Node::setIOVisibility(List *io, int index, boolean v)
2218 {
2219     Parameter *p;
2220     ASSERT( index >= 1 );
2221 
2222     p = (Parameter*)io->getElement(index);
2223     ASSERT(p);
2224 
2225     if (p->isVisible() == v)
2226 	return;
2227 
2228     p->setVisibility(v);
2229 
2230     this->notifyIoParameterStatusChanged(io == &this->inputParameters, index,
2231 			   (v ? Node::ParameterBecomesVisible :
2232 				Node::ParameterBecomesInvisible));
2233 }
2234 
2235 ////////////////////////////////////////////////////////////////////////////////
2236 //
2237 // Set TRUE/FALSE indicating whether or not all parameters from
2238 // the given list is set to be visible.
2239 //
2240 // FIXME:
2241 // See the #if 0's below.  It's really bad to be doing an XtSetValues here
2242 // This was done because the Workspace widget doesn't deal with standins being
2243 // managed/unmanaged if they've got lines connected.  This needs attention after
2244 // the 3.1 release.  (You have to do something like manage/unmanage because watching
2245 // an Image standin grow/shrink is painfull.
2246 //
2247 // A possible fix:  Go to WorkspaceW.c.  In the GeometryManager method, look for
2248 // PerformSpaceWars.  Add a call there to RerouteLines.  Then you can switch back
2249 // to {un}manage.  Drawback: it's an expensive fix.
2250 //
setAllIOVisibility(List * io,boolean v)2251 void Node::setAllIOVisibility(List *io, boolean v)
2252 {
2253     Parameter *p;
2254     ListIterator li(*io);
2255     int index = 1;
2256     boolean isInput = io == &this->inputParameters;
2257 
2258 #if 0
2259     this->standin->unmanage();
2260 #else
2261     XtVaSetValues (this->standin->getRootWidget(),
2262 	XmNmappedWhenManaged, False,
2263     NULL);
2264 #endif
2265     while( (p = (Parameter *)li.getNext()) )
2266     {
2267 	boolean newv = v || p->isConnected();
2268 	boolean oldv = p->isVisible();
2269 	if (newv != oldv) {
2270 	    p->setVisibility(newv);
2271 	    this->notifyIoParameterStatusChanged(isInput, index,
2272 			   (newv ? Node::ParameterBecomesVisible :
2273 			   	   Node::ParameterBecomesInvisible));
2274 	}
2275 	++index;
2276     }
2277 #if 0
2278     this->standin->manage();
2279 #else
2280     XtVaSetValues (this->standin->getRootWidget(),
2281 	XmNmappedWhenManaged, True,
2282     NULL);
2283 #endif
2284 }
2285 ////////////////////////////////////////////////////////////////////////////////
2286 //
2287 // Return TRUE/FALSE indicating whether or not the give parameter from
2288 // the given list is viewable.
2289 //
isIOViewable(List * io,int index)2290 boolean Node::isIOViewable(List *io, int index)
2291 {
2292     Parameter *p;
2293     ASSERT( index >= 1 );
2294 
2295     p = (Parameter*)io->getElement(index);
2296     ASSERT(p);
2297 
2298     return p->isViewable();
2299 }
2300 
2301 ////////////////////////////////////////////////////////////////////////////////
2302 //
2303 // Return TRUE/FALSE indicating whether or not the given i/o parameter is
2304 // a required parameter.
2305 //
isIORequired(List * io,int index)2306 boolean Node::isIORequired(List *io, int index)
2307 {
2308     Parameter *p;
2309     ASSERT( index >= 1 );
2310 
2311     p = (Parameter*)io->getElement(index);
2312     ASSERT(p);
2313 
2314     return p->isRequired();
2315 }
2316 ////////////////////////////////////////////////////////////////////////////////
2317 //
2318 // Return TRUE/FALSE indicating whether or not the given parameter list
2319 // contains parameters that can be hidden.
2320 //
hasHideableIO(List * io)2321 boolean Node::hasHideableIO(List *io)
2322 {
2323     ListIterator iterator(*io);
2324     Parameter *p;
2325     while ( (p = (Parameter*)iterator.getNext()) ) {
2326 	if (p->isVisible() && !p->isConnected())
2327 	    return TRUE;
2328     }
2329     return FALSE;
2330 }
2331 ////////////////////////////////////////////////////////////////////////////////
2332 //
2333 // Return TRUE/FALSE indicating whether or not the given parameter list
2334 // contains parameters that can be exposed.
2335 //
hasExposableIO(List * io)2336 boolean Node::hasExposableIO(List *io)
2337 {
2338     ListIterator iterator(*io);
2339     Parameter *p;
2340 
2341     while ( (p = (Parameter*)iterator.getNext()) ) {
2342 	if (p->isViewable() && !p->isVisible())
2343 	    return TRUE;
2344     }
2345     return FALSE;
2346 }
2347 
2348 ////////////////////////////////////////////////////////////////////////////////
2349 //
2350 // Get the description for the index'th parameter in the given list.
2351 //
getIODescription(List * io,int index)2352 const char *Node::getIODescription(List *io, int index)
2353 {
2354     Parameter *p;
2355     ASSERT( index >= 1 );
2356 
2357     p = (Parameter*)io->getElement(index);
2358     ASSERT(p);
2359 
2360     return p->getDescription();
2361 }
2362 
2363 ////////////////////////////////////////////////////////////////////////////////
isIOCacheabilityWriteable(List * io,int index)2364 boolean Node::isIOCacheabilityWriteable(List *io, int index)
2365 {
2366     Parameter *p;
2367     ASSERT( index >= 1 );
2368     p = (Parameter*)io->getElement(index);
2369     ASSERT(p);
2370     return p->hasWriteableCacheability();
2371 
2372 }
2373 ////////////////////////////////////////////////////////////////////////////////
2374 //
2375 // Get the cacheability for the index'th parameter in the given list.
2376 //
getIOCacheability(List * io,int index)2377 Cacheability Node::getIOCacheability(List *io, int index)
2378 {
2379     Parameter *p;
2380     ASSERT( index >= 1 );
2381     p = (Parameter*)io->getElement(index);
2382     ASSERT(p);
2383     return p->getCacheability();
2384 }
2385 
2386 ////////////////////////////////////////////////////////////////////////////////
2387 //
2388 // Set the cacheability for the index'th parameter in the given list.
2389 //
setIOCacheability(List * io,int index,Cacheability c)2390 void Node::setIOCacheability(List *io, int index, Cacheability c)
2391 {
2392     Parameter *p;
2393     ASSERT( index >= 1 );
2394 
2395     p = (Parameter*)io->getElement(index);
2396     ASSERT(p);
2397     if (c != p->getCacheability())
2398     {
2399 	//
2400 	// Version 2.0.0 (possibly an unreleased version) was putting
2401 	// 'cache:1' on interactor outputs, which was causing an assertion
2402 	// failure.  So now, if the cacheability is not writable during
2403 	// a .net read, then ignore the request.
2404 	//
2405 	boolean r = this->isIOCacheabilityWriteable(io, index);
2406 	if (!r && this->network->isReadingNetwork())
2407 	   return;
2408 	else
2409 	   ASSERT(r);
2410 	p->setCacheability(c);
2411 	this->getNetwork()->setDirty();
2412 	if (this->cdb)
2413 	    this->cdb->changeOutput(index);
2414     }
2415 }
2416 
2417 ////////////////////////////////////////////////////////////////////////////////
2418 //
2419 // Set the cacheability for the node.
2420 //
setNodeCacheability(Cacheability val)2421 void Node::setNodeCacheability(Cacheability val)
2422 {
2423     if (val != this->getNodeCacheability())
2424     {
2425 	ASSERT(this->hasWriteableCacheability());
2426 	this->nodeCacheability = val;
2427 	this->getNetwork()->setDirty();
2428     }
2429 }
2430 
2431 ////////////////////////////////////////////////////////////////////////////////
2432 //
2433 //
2434 //
2435 //
typeMatchOutputToInput(int output_index,Node * dest,int input_index)2436 boolean Node::typeMatchOutputToInput(int output_index,
2437 				     Node *dest, int input_index)
2438 {
2439     Parameter *pin, *pout;
2440     ASSERT( output_index >= 1 );
2441     ASSERT( input_index >= 1 );
2442 
2443     pout = (Parameter*)this->outputParameters.getElement(output_index);
2444     pin  = (Parameter*)dest->inputParameters.getElement(input_index);
2445     ASSERT(pin && pout);
2446 
2447     return pin->typeMatch(pout);
2448 }
2449 
2450 
2451 ////////////////////////////////////////////////////////////////////////////////
2452 //
2453 // Determine if this node has repeatable inputs that can be removed.
2454 // We can remove repeats if the total number of parameters in this node
2455 // is currently greater than the number of non-repeatable input parameters
2456 // found in the definition (the initial number of inputs minus the number of
2457 // repeats).
2458 //
hasRemoveableInput()2459 boolean Node::hasRemoveableInput()
2460 {
2461     NodeDefinition *def = this->definition;
2462     int icnt = this->getInputCount();
2463 
2464     if (!def->isInputRepeatable() || (icnt == 0))
2465 	return FALSE;
2466 
2467     return icnt > (def->getInputCount() - def->getInputRepeatCount());
2468 }
hasRemoveableOutput()2469 boolean Node::hasRemoveableOutput()
2470 {
2471     NodeDefinition *def = this->definition;
2472     int icnt = this->getOutputCount();
2473 
2474     if (!def->isOutputRepeatable() || (icnt == 0))
2475 	return FALSE;
2476 
2477     return icnt > (def->getOutputCount() - def->getOutputRepeatCount());
2478 }
2479 ////////////////////////////////////////////////////////////////////////////////
2480 //
2481 // Add a set of repeatable input or output parameters to the given node.
2482 // This request may be made by the parse (below) or by the Editor or StandIn.
2483 // If we have ConfigurationDialog, let it know about the added parameters.
2484 //
addRepeats(boolean input)2485 boolean Node::addRepeats(boolean input)
2486 {
2487     int i, iocnt, repeats;
2488     List *plist;
2489     ParameterDefinition *pd;
2490     NodeDefinition *nd;
2491     Parameter *p;
2492 
2493     nd = this->definition;
2494 
2495     if (input) {
2496 	repeats = nd->getInputRepeatCount();
2497 	plist = &this->inputParameters;
2498         iocnt = this->getInputCount();
2499     } else {
2500 	repeats = nd->getOutputRepeatCount();
2501 	plist = &this->outputParameters;
2502         iocnt = this->getOutputCount();
2503     }
2504 
2505 
2506     ASSERT(repeats > 0);
2507 
2508     this->network->setDirty();	// Let our network know that we have changed.
2509 
2510     for (i=1 ; i<=repeats ; i++) {	// Indexing is 1 based
2511 	if (input)
2512 	    pd = (ParameterDefinition*) nd->getInputDefinition(iocnt+i);
2513  	else
2514 	    pd = (ParameterDefinition*) nd->getOutputDefinition(iocnt+i);
2515  	p = nd->newParameter(pd,this,iocnt+i);
2516 	plist->appendElement(p);
2517         if (this->cdb) { 	// Let the configuration Dialog know about this
2518             if (input)
2519                 this->cdb->newInput(iocnt + i);
2520             else
2521                 this->cdb->newOutput(iocnt + i);
2522 	}
2523         if (this->standin) { 	// Let the standin know about this
2524             if (input)
2525                 this->standin->addInput(iocnt + i);
2526             else
2527                 this->standin->addOutput(iocnt + i);
2528 	}
2529     }
2530 
2531 
2532     return TRUE;
2533 }
2534 ///////////////////////////////////////////////////////////////////////////////
2535 //
2536 // Remove a set of repeatable input or output parameters from the given node.
2537 // The parameters that are removed are deleted.
2538 // NOTE: this is a friend of the Node class.
2539 //
removeRepeats(boolean input)2540 boolean Node::removeRepeats(boolean input)
2541 {
2542     int i, repeats;
2543     List *plist;
2544     Parameter *p;
2545     NodeDefinition *nd;
2546 
2547     nd = this->definition;
2548 
2549     if (input) {
2550 	repeats = nd->getInputRepeatCount();
2551 	plist = &this->inputParameters;
2552     } else {
2553 	repeats = nd->getOutputRepeatCount();
2554 	plist = &this->outputParameters;
2555     }
2556 
2557 
2558     ASSERT(repeats > 0);
2559 
2560     this->network->setDirty();	// Let our network know that we have changed.
2561 
2562     int cnt = plist->getSize();
2563     for (i=0 ; i<repeats ; i++)  {
2564 	p = (Parameter*)plist->getElement(cnt);
2565 	delete p;
2566 	plist->deleteElement(cnt);
2567 	if (this->cdb) {
2568             if (input)
2569                 this->cdb->deleteInput(cnt);
2570             else
2571                 this->cdb->deleteOutput(cnt);
2572 	}
2573         if (this->standin) { 	// Let the standin know about this
2574             if (input)
2575                 this->standin->removeLastInput();
2576             else
2577                 this->standin->removeLastOutput();
2578 	}
2579 	cnt--;
2580     }
2581 
2582 
2583     return TRUE;
2584 }
2585 ///////////////////////////////////////////////////////////////////////////////
2586 //
2587 // Change a parameter from either the assigned or default value to the
2588 // default or assigned value.
2589 // Set the index'th i/o parameter to use either the default value
2590 // or the assigned valued. if notify is TRUE then call
2591 // ioParameterStatusChanged() with Node::ParameterSetValueToDefaulting.
2592 // If there is a connection to the executive, then send the change.
2593 //
setIODefaultingStatus(int index,boolean input,boolean defaulting,boolean send,boolean notify)2594 void Node::setIODefaultingStatus(int index,
2595 				 boolean input,
2596 				 boolean defaulting,
2597 				 boolean send,
2598 				 boolean notify)
2599 {
2600     Parameter *p;
2601     if (input)
2602 	p = this->getInputParameter(index);
2603     else
2604 	p = this->getOutputParameter(index);
2605 
2606     boolean was_defaulting = p->isDefaulting();
2607     if (was_defaulting == defaulting)
2608 	return;
2609 
2610     p->setUnconnectedDefaultingStatus(defaulting);
2611 
2612     //
2613     // And now send the value to the executive if there is a connection.
2614     // Note that we don't need to set the network dirty, because we can
2615     // send the changes ourselves.
2616     //
2617     if (send)
2618     {
2619 	DXPacketIF *pif = theDXApplication->getPacketIF();
2620 	if (pif != NUL(DXPacketIF*))
2621 	     this->sendValues(FALSE);
2622     }
2623 
2624     ASSERT(!p->isConnected());
2625     if (notify)
2626 	this->notifyIoParameterStatusChanged(input, index,
2627 			Node::ParameterSetValueToDefaulting);
2628 
2629 
2630 }
2631 ///////////////////////////////////////////////////////////////////////////////
2632 //
2633 // Open this nodes configuration dialog box.
2634 //
openConfigurationDialog(Widget parent)2635 void Node::openConfigurationDialog(Widget parent)
2636 {
2637     if (!this->cdb)
2638 	this->newConfigurationDialog(parent);
2639     this->cdb->post();
2640 }
2641 ///////////////////////////////////////////////////////////////////////////////
2642 //
2643 // Define the default action that is taken when the StandIn asks for the
2644 // the default action.
2645 //
openDefaultWindow(Widget parent)2646 void Node::openDefaultWindow(Widget parent)
2647 {
2648     this->openConfigurationDialog(parent);
2649 }
2650 
2651 ///////////////////////////////////////////////////////////////////////////////
2652 //
2653 // Display help for this node in a window.
2654 // FIXME: use real help system here.
2655 //
openHelpWindow(Widget parent)2656 void Node::openHelpWindow(Widget parent)
2657 {
2658     ErrorMessage("Help not available for %s\n",this->getNameString());
2659 }
2660 
2661 //////////////////////////////////////////////////////////////////////////////
2662 //
2663 // Print the stuff that goes in a .cfg file.
2664 // The default is to succeed without printing anything.
2665 //
cfgPrintNode(FILE * f,PrintType)2666 boolean Node::cfgPrintNode(FILE *f, PrintType)
2667 {
2668    return TRUE;
2669 }
2670 //////////////////////////////////////////////////////////////////////////////
2671 //
2672 // Parse a comment in a .cfg file comment section for this node.
2673 // Be default nodes have lines of the following form
2674 // '// node %s[%d]:'
2675 //
cfgParseComment(const char * comment,const char * filename,int lineno)2676 boolean Node::cfgParseComment(const char* comment,
2677 		const char* filename, int lineno)
2678 {
2679     return this->cfgParseNodeLeader(comment,filename,lineno);
2680 }
2681 
setLabelString(const char * label)2682 boolean Node::setLabelString(const char *label)
2683 {
2684 
2685     this->labelSymbol = theSymbolManager->registerSymbol(label);
2686     if (this->cdb)
2687 	this->cdb->changeLabel();
2688     if (this->getStandIn())
2689 	this->getStandIn()->notifyLabelChange();
2690     return TRUE;
2691 }
getLabelString()2692 const char *Node::getLabelString()
2693 {
2694     if (this->labelSymbol == 0)
2695         return this->getNameString();
2696     else
2697         return theSymbolManager->getSymbolString(this->labelSymbol);
2698 }
2699 
initialize()2700 boolean Node::initialize()
2701 {
2702     return TRUE;
2703 }
2704 
deleteArk(Ark * a)2705 boolean Node::deleteArk(Ark *a)
2706 {
2707     Node*      sourceNode;
2708     Node*      destNode;
2709     int        sourceIndex, destIndex;
2710 
2711     sourceNode = a->getSourceNode(sourceIndex);
2712     destNode   = a->getDestinationNode(destIndex);
2713 
2714 
2715     destNode->removeInputArk(destIndex, a);
2716     sourceNode->removeOutputArk(sourceIndex, a);
2717 
2718     return TRUE;
2719 
2720 }
2721 
removeIOArk(List * io,int index,Ark * a)2722 boolean Node::removeIOArk(List *io, int index, Ark *a)
2723 {
2724     Parameter *p = (Parameter*)io->getElement(index);
2725 
2726     p->removeArk(a);
2727 
2728     this->notifyIoParameterStatusChanged(io == &this->inputParameters, index,
2729 				Node::ParameterArkRemoved);
2730 
2731     return TRUE;
2732 }
2733 
2734 
2735 void
updateDefinition()2736 Node::updateDefinition()
2737 {
2738 	struct ArkInfo {
2739 		int   srcIndex;
2740 		int   dstIndex;
2741 		Node *src;
2742 		Node *dst;
2743 	};
2744 
2745 	//
2746 	// Types may have changed so delete the cdb.
2747 	//
2748 	if (this->cdb) {
2749 		delete this->cdb;
2750 		this->cdb = NULL;
2751 	}
2752 
2753 #if 11 	// This is the beginning of an attemp to fix bug DAWOOD91
2754 #else
2755 	boolean hadStandIn = FALSE;
2756 
2757 	//
2758 	// Recreate the standin if need be
2759 	//
2760 	if (this->standin) {
2761 		delete this->standin;
2762 		this->standin = NULL;
2763 		hadStandIn = TRUE;
2764 	}
2765 #endif
2766 
2767 	// For each of the input ParameterDefinitions in the new definition,
2768 	// make sure that the types of the parameter are correct, and
2769 	// disconnect arcs or reset the values to NULL.
2770 
2771 	int numInputs = this->getInputCount();
2772 	boolean *defaulting = NULL;
2773 	boolean *visibilities = NULL;
2774 	char **values = NULL;
2775 	List **inputArks = NULL;
2776 	if (numInputs != 0)
2777 	{
2778 		defaulting = new boolean[numInputs];
2779 		values = new char *[numInputs];
2780 		inputArks = new List *[numInputs];
2781 		visibilities = new boolean[numInputs];
2782 	}
2783 	int i;
2784 	for (i = 1; i <= numInputs; ++i)
2785 	{
2786 		inputArks[i-1] = NULL;
2787 		values[i-1] = NULL;
2788 		defaulting[i-1] = FALSE;
2789 		visibilities[i-1] = this->isInputVisible(i);
2790 		if (this->isInputConnected(i))
2791 		{
2792 			const List *arcs = this->getInputArks(i);
2793 			inputArks[i-1] = new List;
2794 			ListIterator li(*(List*)arcs);
2795 			Ark *a;
2796 			while( (a = (Ark*)li.getNext()) )
2797 			{
2798 				ArkInfo *ai = new ArkInfo;
2799 				ai->src = a->getSourceNode(ai->srcIndex);
2800 				ai->dst = a->getDestinationNode(ai->dstIndex);
2801 				inputArks[i-1]->appendElement(ai);
2802 			}
2803 		}
2804 		else if (!(defaulting[i-1] = this->isInputDefaulting(i)))
2805 			values[i-1] = DuplicateString(this->getInputValueString(i));
2806 		delete this->getInputParameter(i);
2807 	}
2808 	this->inputParameters.clear();
2809 
2810 	int numOutputs = this->getOutputCount();
2811 	List  **outputArks = NULL;
2812 	if (numOutputs != 0)
2813 		outputArks = new List *[numOutputs];
2814 	for (i = 1; i <= numOutputs; ++i)
2815 	{
2816 		outputArks[i-1] = NULL;
2817 		if (this->isOutputConnected(i))
2818 		{
2819 			const List *arcs = this->getOutputArks(i);
2820 			outputArks[i-1] = new List;
2821 			ListIterator li(*(List*)arcs);
2822 			Ark *a;
2823 			while( (a = (Ark*)li.getNext()) )
2824 			{
2825 				ArkInfo *ai = new ArkInfo;
2826 				ai->src = a->getSourceNode(ai->srcIndex);
2827 				ai->dst = a->getDestinationNode(ai->dstIndex);
2828 				outputArks[i-1]->appendElement(ai);
2829 			}
2830 		}
2831 		delete this->getOutputParameter(i);
2832 	}
2833 	this->outputParameters.clear();
2834 
2835 	this->buildParameterLists();
2836 
2837 	for (i = 1; i <= numInputs && i <= this->getInputCount(); ++i)
2838 	{
2839 		this->setInputVisibility(i, visibilities[i-1]);
2840 		if (inputArks[i-1])
2841 		{
2842 			ListIterator li(*inputArks[i-1]);
2843 			ArkInfo *ai;
2844 			while( (ai = (ArkInfo*)li.getNext()) )
2845 			{
2846 				if (ai->src->typeMatchOutputToInput(ai->srcIndex,
2847 					ai->dst, ai->dstIndex))
2848 				{
2849 					Ark *newArk = new Ark(ai->src, ai->srcIndex,
2850 						ai->dst, ai->dstIndex);
2851 					if (ai->src->getNetwork()->getEditor() &&
2852 						ai->src->getStandIn())
2853 						ai->src->getStandIn()->addArk(
2854 						ai->src->getNetwork()->getEditor(),
2855 						newArk);
2856 				}
2857 				delete ai;
2858 			}
2859 			delete inputArks[i-1];
2860 		}
2861 		else if (defaulting[i-1])
2862 			this->useDefaultInputValue(i);
2863 		else
2864 			this->setInputValue(i, values[i-1]);
2865 	}
2866 #if 11
2867 	// must increase j by the number of repeats added in buildParameterLists()
2868 	int repeats = this->getInputCount() - this->definition->getInputCount();
2869 	int j = numInputs + repeats;
2870 	for (; j >= i; --j)
2871 	{
2872 		if (this->cdb)
2873 			this->cdb->deleteInput(j);
2874 		if (this->standin)
2875 			this->standin->removeLastInput();
2876 	}
2877 	for (; i <= this->getInputCount(); ++i)
2878 	{
2879 		if (this->cdb)
2880 			this->cdb->newInput(i);
2881 		if (this->standin)
2882 			this->standin->addInput(i);
2883 	}
2884 #endif
2885 	if (numInputs != 0)
2886 	{
2887 		delete[] defaulting;
2888 		delete[] visibilities;
2889 		delete[] values;
2890 		delete[] inputArks;
2891 	}
2892 
2893 	for (i = 1; i <= numOutputs && i <= this->getOutputCount(); ++i)
2894 	{
2895 		if (outputArks[i-1])
2896 		{
2897 			ListIterator li(*outputArks[i-1]);
2898 			ArkInfo *ai;
2899 			while( (ai = (ArkInfo*)li.getNext()) )
2900 			{
2901 				if (ai->src->typeMatchOutputToInput(ai->srcIndex,
2902 					ai->dst, ai->dstIndex))
2903 				{
2904 					Ark *newArk = new Ark(ai->src, ai->srcIndex,
2905 						ai->dst, ai->dstIndex);
2906 					if (ai->src->getNetwork()->getEditor() &&
2907 						ai->src->getStandIn())
2908 						ai->src->getStandIn()->addArk(
2909 						ai->src->getNetwork()->getEditor(),
2910 						newArk);
2911 				}
2912 				delete ai;
2913 			}
2914 			delete outputArks[i-1];
2915 		}
2916 		this->notifyIoParameterStatusChanged(FALSE, i, Node::ParameterValueChanged);
2917 	}
2918 #if 11
2919 	j = numOutputs;
2920 	for (; j >= i; --j)
2921 	{
2922 		if (this->cdb)
2923 			this->cdb->deleteOutput(j);
2924 		if (this->standin)
2925 			this->standin->removeLastOutput();
2926 	}
2927 	for (; i <= this->getOutputCount(); ++i)
2928 	{
2929 		if (this->cdb)
2930 			this->cdb->newOutput(i);
2931 		if (this->standin)
2932 			this->standin->addOutput(i);
2933 	}
2934 #endif
2935 	if (numOutputs != 0)
2936 		delete[] outputArks;
2937 
2938 #if 11
2939 #else
2940 	if (hadStandIn) {
2941 		EditorWindow *e = this->getNetwork()->getEditor();
2942 		this->standin = this->newStandIn(e->getWorkSpace());
2943 	}
2944 #endif
2945 
2946 	//
2947 	// Because of undo in Editor, provide notification that a defintion
2948 	// has changed.  The undo list will probably have to be tossed out
2949 	//
2950 	EditorWindow *e = this->getNetwork()->getEditor();
2951 	if (e) e->notifyDefinitionChange(this);
2952 }
2953 
2954 //
2955 // Based on a Node's definition, build a parameter list for the given node.
2956 //
buildParameterLists()2957 boolean Node::buildParameterLists()
2958 {
2959     int ninputs, noutputs, i;
2960     Parameter *p;
2961     ParameterDefinition *pd;
2962     NodeDefinition *nd = this->getDefinition();
2963 
2964     ninputs = nd->getInputCount();
2965     for (i=1 ; i<=ninputs ; i++) {
2966 	pd = nd->getInputDefinition(i);
2967 	ASSERT(pd);
2968         p = nd->newParameter(pd,this,i);
2969         ASSERT(p);
2970 	boolean r = this->appendInput(p); // FIXME: handle error
2971 	ASSERT(r);
2972     }
2973     if (nd->isInputRepeatable())
2974 	this->addRepeats(TRUE);
2975 
2976     noutputs = nd->getOutputCount();
2977     for (i=1 ; i<=noutputs ; i++) {
2978 	pd = nd->getOutputDefinition(i);
2979 	ASSERT(pd);
2980         p = nd->newParameter(pd,this,i);
2981         ASSERT(p);
2982 	boolean r = this->appendOutput(p);
2983 	ASSERT(r);
2984     }
2985     if (nd->isOutputRepeatable())
2986 	this->addRepeats(FALSE);
2987 
2988     return TRUE;
2989 }
2990 
2991 #if WORKSPACE_PAGES
2992 #else
setGroupName(const char * name)2993 void Node::setGroupName(const char *name)
2994 {
2995     if (!name) {
2996 	this->groupNameSymbol = 0;
2997     } else {
2998 	this->groupNameSymbol = theSymbolManager->registerSymbol(name);
2999     }
3000 
3001     this->network->setDirty();
3002 }
3003 
getGroupName()3004 const char* Node::getGroupName()
3005 {
3006     if (!this->groupNameSymbol)
3007 	return NULL;
3008 
3009     return theSymbolManager->getSymbolString(this->groupNameSymbol);
3010 }
3011 
addToGroup(const char * group)3012 void Node::addToGroup(const char* group)
3013 {
3014     this->setGroupName(group);
3015     theDXApplication->PGManager->registerGroup(group, this->network);
3016 }
3017 #endif
3018 
netEndOfMacroNodeString(const char * prefix)3019 char *Node::netEndOfMacroNodeString(const char *prefix)
3020 {
3021     return NULL;
3022 }
3023 
netBeginningOfMacroNodeString(const char * prefix)3024 char *Node::netBeginningOfMacroNodeString(const char *prefix)
3025 {
3026     return NULL;
3027 }
3028 
3029 
3030 //
3031 // Print the invocation of any script language that is
3032 // to occur at the beginning of the containing macro.
3033 //
netPrintBeginningOfMacroNode(FILE * f,PrintType dest,const char * prefix,PacketIFCallback callback,void * clientdata)3034 boolean	Node::netPrintBeginningOfMacroNode(FILE *f,
3035 		      PrintType dest,
3036 		      const char *prefix,
3037 		      PacketIFCallback callback,
3038 		      void *clientdata)
3039 {
3040     boolean r = TRUE;
3041 
3042     char *s = netBeginningOfMacroNodeString(prefix);
3043     if (s == NULL)
3044 	return TRUE;
3045 
3046     if (dest == PrintFile || dest == PrintCut || dest == PrintCPBuffer) {
3047 	if (fputs(s, f) < 0)
3048 	    r = FALSE;
3049 	if (callback != NUL(PacketIFCallback))
3050 	    callback(clientdata,s);
3051     } else {
3052 	ASSERT (dest == PrintExec);
3053 	DXPacketIF *pif = theDXApplication->getPacketIF();
3054 	pif->sendBytes(s);
3055     }
3056 
3057 
3058     delete s;
3059 
3060     return r;
3061 }
3062 
3063 //
3064 // Print the invocation of any script language that is
3065 // to occur at the end of the containing macro.
3066 //
netPrintEndOfMacroNode(FILE * f,PrintType dest,const char * prefix,PacketIFCallback callback,void * clientdata)3067 boolean	Node::netPrintEndOfMacroNode(FILE *f,
3068 		      PrintType dest,
3069 		      const char *prefix,
3070 		      PacketIFCallback callback,
3071 		      void *clientdata)
3072 {
3073     boolean r = TRUE;
3074 
3075     char *s = netEndOfMacroNodeString(prefix);
3076     if (s == NULL)
3077 	return TRUE;
3078 
3079     if (dest == PrintFile || dest == PrintCut || dest == PrintCPBuffer) {
3080 	if (fputs(s, f) < 0)
3081 	    r = FALSE;
3082 	if (callback != NUL(PacketIFCallback))
3083 	    callback(clientdata,s);
3084     } else {
3085 	ASSERT (dest == PrintExec);
3086 	DXPacketIF *pif = theDXApplication->getPacketIF();
3087 	pif->sendBytes(s);
3088     }
3089 
3090     delete s;
3091 
3092     return r;
3093 }
isInputRepeatable()3094 boolean Node::isInputRepeatable()
3095 {
3096     NodeDefinition *def = this->definition;
3097     if (!def->isInputRepeatable())
3098 	return FALSE;
3099     int icnt = this->getInputCount();
3100     int rcnt = icnt - (def->getInputCount() - def->getInputRepeatCount());
3101     int sets = rcnt / def->getInputRepeatCount();
3102     return sets < (MAX_INPUT_SETS);
3103 }
isOutputRepeatable()3104 boolean Node::isOutputRepeatable()
3105 {
3106     NodeDefinition *def = this->definition;
3107     if (!def->isOutputRepeatable())
3108 	return FALSE;
3109     int icnt = this->getOutputCount();
3110     int rcnt = icnt - (def->getOutputCount() - def->getOutputRepeatCount());
3111     int sets = rcnt / def->getOutputRepeatCount();
3112     return sets < (MAX_OUTPUT_SETS);
3113 }
3114 
3115 //
3116 // Reset the node to using the default cfg state (probably before reading
3117 // in a new cfg file).
3118 //
setDefaultCfgState()3119 void Node::setDefaultCfgState()
3120 {
3121 }
3122 //
3123 // Return TRUE if this node has state that will be saved in a .cfg file.
3124 // At this level, nodes do not have cfg state.
3125 //
hasCfgState()3126 boolean Node::hasCfgState()
3127 {
3128     return FALSE;
3129 }
3130 
3131 
3132 //
3133 // Generate a new instance number for this node.  We notify the
3134 // standIn and mark the network and the node dirty.
3135 // The new instance number is returned.
3136 //
assignNewInstanceNumber()3137 int Node::assignNewInstanceNumber()
3138 {
3139     NodeDefinition *nd = this->definition;
3140     ASSERT(nd);
3141     this->instanceNumber = nd->newInstanceNumber();
3142 #if 0
3143     // FIXME: must notify standIn when in UIDebug mode
3144     if (this->standIn) {
3145 	this->standIn-??
3146 #endif
3147 
3148     //
3149     // Require that the network resend all tools.
3150     //
3151     this->network->setDirty();
3152 
3153     //
3154     // Mark all inputs and outputs dirty so that they are resent with the
3155     // new parameter names.
3156     //
3157     int i, cnt = this->getInputCount();
3158     for (i=1 ; i<=cnt ; i++)
3159 	this->setInputDirty(i);
3160     cnt = this->getOutputCount();
3161     for (i=1 ; i<=cnt ; i++)
3162 	this->setOutputDirty(i);
3163 
3164     if (this->moduleMessageId) {
3165         delete this->moduleMessageId;
3166         this->moduleMessageId = NULL;
3167     }
3168     return this->instanceNumber;
3169 }
3170 //
3171 // Disconnect all input and output arcs from this node.
3172 //
3173 boolean Node::disconnectArks()
3174 {
3175     int i;
3176     ListIterator li;
3177     Parameter *p;
3178 
3179     //
3180     // Disconnect the inputs.
3181     //
3182     li.setList(this->inputParameters);
3183     for (i=1 ; (p = (Parameter*)li.getNext()) ; i++) {
3184 	if (p->isConnected()) {
3185 	    p->disconnectArks();
3186 	    this->notifyIoParameterStatusChanged(TRUE, i, Node::ParameterArkRemoved);
3187 	}
3188     }
3189 
3190     //
3191     // Disconnect the outputs.
3192     //
3193     li.setList(this->outputParameters);
3194     for (i=1 ; (p = (Parameter*)li.getNext()) ; i++) {
3195 	if (p->isConnected()) {
3196 	    p->disconnectArks();
3197 	    this->notifyIoParameterStatusChanged(FALSE, i, Node::ParameterArkRemoved);
3198 	}
3199     }
3200 
3201 
3202     return TRUE;
3203 }
3204 //
3205 // Return TRUE if the node can be switched (pasted/merged/moved) from the 'from'
3206 // net to the 'to' net.
3207 //
3208 boolean Node::canSwitchNetwork(Network *from, Network *to)
3209 {
3210     if (to->isMacro() && !this->isAllowedInMacro()) {
3211 	WarningMessage("%s tools are not allowed in macros.\n"
3212 			"Attempt to add a %s tool to macro ignored.",
3213 			this->getNameString(), this->getNameString());
3214 	return FALSE;
3215     }
3216 
3217     return TRUE;
3218 }
3219 //
3220 // Do whatever is necessary to switch the node to the new Network.
3221 //
3222 void Node::switchNetwork(Network *from, Network *to, boolean silently)
3223 {
3224     if (this->cdb) {
3225 	delete this->cdb;
3226 	this->cdb = NULL;
3227     }
3228     if (this->standin) {
3229 	delete this->standin;
3230 	this->standin = NULL;
3231     }
3232 
3233     this->network = to;
3234 }
3235 
3236 //
3237 // Get the selectable values for the n'th input.
3238 // This returns a pointer to a constant array of pointers to
3239 // constant strings which is NOT to be manipulated by the caller.
3240 // The returned array of pointers is NULL terminated.
3241 //
3242 const char * const *Node::getInputValueOptions(int index)
3243 {
3244     Parameter *p;
3245     ASSERT( index >= 1 );
3246 
3247     p = (Parameter*)this->inputParameters.getElement(index);
3248     ASSERT(p);
3249 
3250     return p->getValueOptions();
3251 }
3252 
3253 #ifdef DXUI_DEVKIT
3254 
3255 #define OBJVAL_FORMAT "%s_%s"
3256 #define MODINPUT_FORMAT "%s_%d_in"
3257 #define MODOUTPUT_FORMAT "%s_%d_out"
3258 #define INDENT "    "
3259 
3260 static int phaseNumber = 0;
3261 boolean Node::beginDXCallModule(FILE *f)
3262 {
3263     const char *name = this->getNameString();
3264     int i, instance_number = this->getInstanceNumber();
3265     char modinput_name[128];
3266     char modoutput_name[128];
3267     int input_count = this->getInputCount();
3268     int output_count = this->getOutputCount();
3269 
3270     if (phaseNumber == 0) {
3271 	phaseNumber = 1;
3272 	if (fprintf(f,	"    /*\n"
3273 		      	"     * Temporary variables used by all module calls\n"
3274 		      	"     */\n"
3275 			"    int 	  i, rcode;\n"
3276 			"    Object	  objinput[32];\n"
3277 			"    ModuleInput  minput[32];\n"
3278 			"    ModuleOutput moutput[32];\n"
3279 			"    /*\n"
3280 		      	"     * Per module variables follow (if needed)\n"
3281 		      	"     */\n") <= 0)
3282 	    return FALSE;
3283     }
3284 
3285 
3286     if (input_count > 0) {
3287         sprintf(modinput_name, MODINPUT_FORMAT,name,instance_number);
3288 	for (i=1 ; i<=input_count ; i++) {
3289 	    if (!this->isInputConnected(i) && !this->isInputDefaulting(i)) {
3290 		char oname[128];
3291 		Parameter *p = this->getInputParameter(i);
3292 		sprintf(oname,OBJVAL_FORMAT,modinput_name,
3293 					    this->getInputNameString(i));
3294 		char *code = p->getObjectCodeDecl(INDENT,oname);
3295 		if (code) {
3296 		    if (fprintf(f,code) <= 0)
3297 			return FALSE;
3298 		    delete code;
3299 		}
3300 	    }
3301 	}
3302     }
3303 
3304     if (output_count > 0) {
3305         sprintf(modoutput_name, MODOUTPUT_FORMAT,name,instance_number);
3306 	for (i=1 ; i<=output_count ; i++) {
3307 	    if (this->isOutputConnected(i)) {
3308 		char oname[256];
3309 		sprintf(oname,OBJVAL_FORMAT,modoutput_name,
3310 					this->getOutputNameString(i));
3311 		if (fprintf(f,"%sObject %s = NULL;\n",INDENT,oname) <= 0)
3312 		    return FALSE;
3313 	    }
3314 	}
3315     }
3316 
3317     return TRUE;
3318 
3319 }
3320 boolean Node::callDXCallModule(FILE *f)
3321 {
3322     const char *name = this->getNameString();
3323     int objnum, i, instance_number = this->getInstanceNumber();
3324     boolean r;
3325 
3326     if (phaseNumber == 1) {
3327 	phaseNumber = 2;
3328 	if (fprintf(f,"\n    /*\n"
3329 			"     * Some initializations\n"
3330 			"     */\n"
3331 			"    for (i=0 ; i<32 ; i++) \n"
3332 			"        objinput[i] = NULL;\n") <= 0)
3333 	    return FALSE;
3334     }
3335 
3336     if (fprintf(f,"\n    /*\n"
3337 		    "     * %s:%d - setup in/outputs and call module\n"
3338 		    "     */\n",name,instance_number) <= 0)
3339 	return FALSE;
3340 
3341     char modinput_name[128];
3342     int ninput = 0;
3343     int input_count = this->getInputCount();
3344     if  (input_count <= 0) {
3345 	strcpy(modinput_name,"NULL");
3346     } else {
3347 	//
3348 	// Generate the code to set the ModuleInputs
3349 	//
3350 	sprintf(modinput_name, MODINPUT_FORMAT,name,instance_number);
3351 	for (objnum=0, i=1 ; i<=input_count ; i++) {
3352 
3353 	    if (this->isInputDefaulting(i))
3354 		continue;
3355 
3356 	    const char *input_name = this->getInputNameString(i);
3357 	    char input_val[512];
3358 	    char *init_code = NULL;
3359 	    if (this->isInputConnected(i)) {
3360 		Parameter *p = this->getInputParameter(i);
3361 		Ark  *a = p->getArk(1);
3362 		int param;
3363 		ASSERT(a);
3364 		Node *onode = a->getSourceNode(param);
3365 		ASSERT(onode);
3366 		char oname[256];
3367 		sprintf(oname, MODOUTPUT_FORMAT,onode->getNameString(),
3368 						onode->getInstanceNumber());
3369 		sprintf(input_val, "%s_%s", oname,
3370 					onode->getOutputNameString(param));
3371 
3372 	    } else {	// Parameter has a tab down value
3373 		Parameter *p = this->getInputParameter(i);
3374 		char oname[256];
3375 		sprintf(oname,OBJVAL_FORMAT,modinput_name,
3376 					this->getInputNameString(i));
3377 		sprintf(input_val, "objinput[%d]", objnum++);
3378 		init_code = p->getObjectCreateCode(INDENT,oname,input_val);
3379 	    }
3380 
3381 	    if (init_code && fprintf(f,init_code) <= 0) {
3382 		delete init_code;
3383 		return FALSE;
3384 	    }
3385 	    r = fprintf(f,"%sDXModSetObjectInput(minput + %d,\"%s\",%s);\n",
3386 				    INDENT,ninput++, input_name, input_val) > 0;
3387 	    if (init_code)
3388 		delete init_code;
3389 	    if (!r)
3390 		return FALSE;
3391 	}
3392     }
3393 
3394     //
3395     // Generate the code to set the ModuleOutputs
3396     //
3397     char modoutput_name[128];
3398     int noutput = 0;
3399     int output_count = this->getOutputCount();
3400 
3401     //
3402     // Generate the code to set the ModuleOutputs
3403     //
3404     sprintf(modoutput_name, MODOUTPUT_FORMAT,name,instance_number);
3405     for (i=1 ; i<=output_count ; i++) {
3406 	if (!this->isOutputConnected(i))
3407 	    continue;
3408 
3409 	const char *output_name = this->getOutputNameString(i);
3410 	char output_objptr[512];
3411 	// FIXME; what if the output has a value (i.e. an interactor)
3412 	char oname[256];
3413 	sprintf(oname,OBJVAL_FORMAT,modoutput_name,
3414 				this->getOutputNameString(i));
3415 	sprintf(output_objptr,"&%s",oname);
3416 
3417 	if (fprintf(f,"%sDXModSetObjectOutput(moutput + %d,\"%s\",%s);\n",
3418 		      INDENT,noutput++,output_name,output_objptr) <= 0)
3419 	    return FALSE;
3420     }
3421 
3422 
3423     //
3424     // Finally, generate the call to DXCallModule
3425     //
3426     if (fprintf(f,"%srcode = DXCallModule(\"%s\",%d,minput,%d,moutput);\n",
3427 			INDENT,this->getNameString(),ninput,noutput) <= 0)
3428 	return FALSE;
3429 
3430 
3431     //
3432     // Reference connected outputs
3433     //
3434     for (i=1 ; i<=output_count ; i++)
3435 	if (this->isOutputConnected(i))
3436 	{
3437 	    const char *output_name = this->getOutputNameString(i);
3438 	    char oname[256];
3439 
3440 	    sprintf(oname,OBJVAL_FORMAT,modoutput_name,
3441 				    this->getOutputNameString(i));
3442 
3443 	    if (fprintf(f,"%sDXReference(%s);\n", INDENT, oname) <= 0)
3444 		return FALSE;
3445 	}
3446 
3447 
3448     if (fprintf(f,"%sif (rcode == ERROR) goto error;\n", INDENT) <= 0)
3449 	return FALSE;
3450 
3451     return TRUE;
3452 }
3453 boolean Node::endDXCallModule(FILE *f)
3454 {
3455 
3456     const char *name = this->getNameString();
3457     int i, instance_number = this->getInstanceNumber();
3458     char modinput_name[128];
3459     char modoutput_name[128];
3460     int input_count = this->getInputCount();
3461     int output_count = this->getOutputCount();
3462 
3463     phaseNumber = 0;
3464 
3465     if (input_count > 0) {
3466         sprintf(modinput_name, MODINPUT_FORMAT,name,instance_number);
3467 	for (i=1 ; i<=input_count ; i++) {
3468 	    if (!this->isInputConnected(i) && !this->isInputDefaulting(i)) {
3469 		char oname[256];
3470 		sprintf(oname,OBJVAL_FORMAT,modinput_name,
3471 					this->getInputNameString(i));
3472 		Parameter *p = this->getInputParameter(i);
3473 	  	char *cleanup_code = p->getObjectCleanupCode(INDENT,oname);
3474 		if (cleanup_code) {
3475 		    if (fprintf(f,cleanup_code) <= 0) {
3476 			delete cleanup_code;
3477 			return FALSE;
3478 		    }
3479 		    delete cleanup_code;
3480 		}
3481 	    }
3482 	}
3483     }
3484 
3485     if (output_count > 0) {
3486         sprintf(modoutput_name, MODOUTPUT_FORMAT,name,instance_number);
3487 	for (i=1 ; i<=output_count ; i++) {
3488 	    if (this->isOutputConnected(i)) {
3489 		char oname[256];
3490 		sprintf(oname,OBJVAL_FORMAT,modoutput_name,
3491 					this->getOutputNameString(i));
3492 		if (fprintf(f,"%sif (%s) DXDelete(%s);\n",
3493 					INDENT,oname,oname) <= 0)
3494 		    return FALSE;
3495 	    }
3496 	}
3497     }
3498 
3499 
3500     return TRUE;
3501 
3502 }
3503 #endif	// DXUI_DEVKIT
3504 //
3505 // See if the given string is a viable label to be used as an identifier.
3506 // Also make sure it is not a reserved script language word.
3507 // Return TRUE if ok, FALSE otherwise and issue and error message.
3508 //
3509 boolean Node::verifyRestrictedLabel(const char *label)
3510 {
3511     int junk = 0;
3512     if (!IsIdentifier(label, junk) || junk != STRLEN(label))
3513     {
3514         ErrorMessage("%s name \"%s\" must consist of "
3515                      "letters, numbers, or the character '_', and "
3516                      "begin with a letter",
3517                      this->getNameString(),
3518                      label);
3519         return FALSE;
3520     }
3521 
3522     if (IsReservedScriptingWord(label)) {
3523         ErrorMessage("%s name \"%s\" is a reserved word",
3524                      this->getNameString(),
3525                      label);
3526         return FALSE;
3527     }
3528 
3529     return TRUE;
3530 }
3531 
3532 boolean Node::cfgPrintNodeLeader(FILE *f)
3533 {
3534 
3535     if (fprintf(f, "//\n// node %s[%d]:\n",
3536                 this->getNameString(),
3537                 this->getInstanceNumber()) < 0)
3538         return FALSE;
3539 
3540     return TRUE;
3541 }
3542 boolean Node::cfgParseNodeLeader(const char *comment,
3543 				const char *file, int lineno)
3544 {
3545     int d;
3546     if (sscanf(comment, " node %*[^[][%d]:",&d) != 1)
3547         return FALSE;
3548 
3549     return TRUE;
3550 }
3551 
3552 boolean Node::printAsJava(FILE* f)
3553 {
3554     if (this->hasJavaRepresentation() == FALSE) return TRUE;
3555 
3556     const char* indent = "        ";
3557     const char* nn = this->getJavaNodeName();
3558     const char* ns = this->getNameString();
3559     int instno = this->getInstanceNumber();
3560 
3561     fprintf (f,
3562 	"\n\n%s%s %s_%d = new %s (this.network, \"%s\", %d, \"%s\");\n",
3563 	indent, nn, ns, instno, nn, ns, instno, this->getLabelString()
3564     );
3565     fprintf (f,
3566 	"%sthis.network.addElement((Object)%s_%d);\n",
3567 	indent, ns, instno
3568     );
3569 
3570 
3571     //
3572     // Loop over all inputs.  If the node wants that input's value
3573     // printed as java, then oblige.
3574     //
3575     int i, icnt = this->getInputCount();
3576     for (i=1; i<=icnt; i++) {
3577 	char src_name[128];
3578 	int src_out = 0;
3579 	strcpy (src_name, "null");
3580 	if (this->printInputAsJava(i)) {
3581 	    if (this->isInputConnected(i)) {
3582 		const List* ia = (List*)getInputArks(i);
3583 		Ark* a = NUL(Ark*);
3584 		Node* src = NUL(Node*);
3585 		if (ia) {
3586 		    ListIterator li(*(List*)ia);
3587 		    a = (Ark*)li.getNext();
3588 		}
3589 		if (a) src = (Node*)a->getSourceNode(src_out);
3590 		if ((src)&&(src->isA(src->hasJavaRepresentation()))) {
3591 		    const char* src_ns = src->getNameString();
3592 		    int src_instno = src->getInstanceNumber();
3593 		    sprintf (src_name, "%s_%d", src_ns, src_instno);
3594 		}
3595 
3596 		fprintf (f, "%s%s_%d.addInputArk (%d, %s, %d);\n",
3597 		    indent, ns, instno, i, src_name, src_out);
3598 	    }
3599 	    const char* valstr = this->getJavaInputValueString(i);
3600 	    if ((valstr) && (EqualString(valstr, "NULL")==FALSE)) {
3601 		if (valstr[0] == '"') {
3602 		    if (fprintf (f, "%s%s_%d.setInputValueString(%d, %s);\n",
3603 			indent, ns, instno, i, valstr) == FALSE) return FALSE;
3604 		} else {
3605 		    if (fprintf (f, "%s%s_%d.setInputValueString(%d, \"%s\");\n",
3606 			indent, ns, instno, i, valstr) == FALSE) return FALSE;
3607 		}
3608 	    }
3609 	}
3610     }
3611 
3612     return TRUE;
3613 }
3614 
3615 void Node::setLayoutInformation(Base* li)
3616 {
3617     if (this->layout_information)
3618 	delete this->layout_information;
3619     this->layout_information = li;
3620 }
3621