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 #ifdef OS2
14 #include <stdlib.h>
15 #include <types.h>
16 #endif
17 #include <time.h>
18 #include <stdio.h>	// For fprintf(), fseek() and rename()
19 
20 #if defined(DXD_WIN) || defined(OS2)          //SMH get correct name for unlink for NT in stdio.h
21 #define unlink _unlink
22 
23 #if 0
24 #if defined(windows) && defined(HAVE_WINSOCK_H)
25 #include <winsock.h>
26 #elif defined(HAVE_CYGWIN_SOCKET_H)
27 #include <cygwin/socket.h>
28 #elif defined(HAVE_SYS_SOCKET_H)
29 #include <sys/socket.h>
30 #endif
31 #endif
32 
33 #undef send             //SMH without stepping on things
34 #undef FLOAT
35 #undef PFLOAT
36 #else
37 #include <unistd.h>	// For unlink()
38 #endif
39 #include <errno.h>	// For errno
40 #include <sys/stat.h>
41 
42 #include "lex.h"
43 #include "DXStrings.h"
44 #include "Network.h"
45 #include "List.h"
46 #include "ListIterator.h"
47 #include "Parameter.h"
48 
49 #include "CommandScope.h"
50 #include "ControlPanel.h"
51 //#include "InfoDialogManager.h"
52 #include "ErrorDialogManager.h"
53 #include "WarningDialogManager.h"
54 #include "InfoDialogManager.h"
55 
56 #include "AccessNetworkPanelsCommand.h"
57 #include "NewCommand.h"
58 #include "NoUndoNetworkCommand.h"
59 
60 #include "SaveAsDialog.h"
61 #include "SaveCFGDialog.h"
62 #include "OpenCFGDialog.h"
63 #include "SetMacroNameDialog.h"
64 
65 #include "Parse.h"
66 #include "MacroDefinition.h"
67 #include "NodeDefinition.h"
68 #include "Node.h"
69 #include "InteractorNode.h"
70 #include "DXLInputNode.h"
71 #include "DXLOutputNode.h"
72 #include "TransmitterNode.h"
73 #include "ReceiverNode.h"
74 #include "MacroNode.h"
75 #include "Ark.h"
76 #include "SymbolManager.h"
77 #include "DXPacketIF.h"
78 #include "ApplicIF.h"
79 #include "DXVersion.h"
80 #include "EditorWindow.h"
81 #include "ImageWindow.h"
82 #include "DXAnchorWindow.h" // for resetWindowTitle()
83 #include "ImageNode.h"
84 #include "StandIn.h"
85 #include "SequencerNode.h"
86 #include "ProcessGroupManager.h"
87 #if WORKSPACE_PAGES
88 #include "PageGroupManager.h"
89 #include "AnnotationGroupManager.h"
90 #include "GroupStyle.h"
91 #endif
92 #include "PanelGroupManager.h"
93 #include "PanelAccessManager.h"
94 #include "MacroParameterNode.h"
95 
96 #include "DXApplication.h"
97 
98 #include "ColormapNode.h"
99 #include "DisplayNode.h"
100 #include "UniqueNameNode.h"
101 
102 #include "Dictionary.h"
103 #include "NDAllocatorDictionary.h"
104 #include "SetNetworkCommentDialog.h"
105 #include "HelpOnNetworkDialog.h"
106 #include "DeferrableAction.h"
107 #include "DictionaryIterator.h"
108 #include "VPEAnnotator.h"
109 #include "DecoratorStyle.h"
110 #include "DecoratorInfo.h"
111 #include "EditorWorkSpace.h"
112 
113 #include "CascadeMenu.h"
114 #include "ButtonInterface.h"
115 #include "QuestionDialogManager.h"
116 
117 #include "MsgWin.h"
118 
119 #ifdef	DXD_WIN
120 #include <process.h>
121 #define	getpid	_getpid
122 #define	popen	_popen
123 #define pclose	_pclose
124 #endif
125 
126 //
127 // These are the file name extensions assumed for the network file and
128 // the configuration file.  The code assumes that they are 4 characters
129 // in length
130 //
131 static const char NetExtension[] = ".net";
132 static const char CfgExtension[] = ".cfg";
133 
134 #ifdef DXD_OS_NON_UNIX           //SMH allow upper case extensions as well
135 static const char NetExtensionUpper[] = ".NET";
136 static const char CfgExtensionUpper[] = ".CFG";
137 #endif
138 
139 static void GenerateModuleMessage(Dictionary *nodes, char *msg, boolean error);
140 
141 #define DEFAULT_MAIN_NAME "main"
142 /***
143  *** Constants:
144  ***/
145 
146 #define _PARSE_CONFIGURATION	1	// Currently parsing the .cfg file
147 #define _PARSE_NETWORK		2	// Currently parsing the .net file
148 
149 #define _LEXER_RUNNING		0	// Initialized and lexing
150 #define _LEXER_INITIALIZE	1	// Set up the lexer for a new run
151 
152 #define _PARSED_NONE		0
153 #define _PARSED_NODE		1	// Parsing the node's cfg info
154 #define _PARSED_PANEL		2	// Parsing the panel's info
155 #define _PARSED_INTERACTOR	3	// Parsing the interactor's info
156 #define _PARSING_NETWORK_CFG	4	// Parsing the network's cfg info
157 #define _PARSED_VCR		5	// Parsing the vcr's info
158 #define _PARSED_WORKSPACE	6	// Parsing the editor workspace info
159 #define _PARSED_VERSION		7	// Parsing .cfg application comments
160 
161 #if WORKSPACE_PAGES
162 #define _SUB_PARSED_NONE	0
163 #define _SUB_PARSED_NODE	1	// Parsed a node most recently
164 #define _SUB_PARSED_DECORATOR	2       // Parsed a node most recently
165 #endif
166 
167 Network          *Network::ParseState::network;
168 char             *Network::ParseState::parse_file;
169 boolean          Network::ParseState::error_occurred;
170 boolean          Network::ParseState::stop_parsing;
171 boolean          Network::ParseState::issued_version_error;
172 boolean          Network::ParseState::ignoreUndefinedModules;
173 Dictionary       *Network::ParseState::undefined_modules;
174 Dictionary       *Network::ParseState::redefined_modules;
175 int              Network::ParseState::parse_mode;
176 boolean          Network::ParseState::main_macro_parsed;
177 
178 List*		Network::RenameTransmitterList = NUL(List*);
179 
ParseState()180 Network::ParseState::ParseState()
181 {
182     this->parse_file = NULL;
183 }
~ParseState()184 Network::ParseState::~ParseState()
185 {
186 }
cleanupAfterParse()187 void Network::ParseState::cleanupAfterParse()
188 {
189     if (this->parse_file)
190 	delete this->parse_file;
191     this->parse_file = NULL;
192 }
initializeForParse(Network * n,int mode,const char * filename)193 void Network::ParseState::initializeForParse(Network *n, int mode,
194 						const char *filename)
195 {
196     this->network = n;
197     this->parse_mode = mode;
198     if (this->parse_file)
199 	delete this->parse_file;
200     this->parse_file = DuplicateString(filename);
201     this->node                = NULL;
202     this->parse_state         = _PARSED_NONE;
203 #if WORKSPACE_PAGES
204     this->parse_sub_state     = _SUB_PARSED_NONE;
205 #endif
206     this->main_macro_parsed   = FALSE;
207     this->error_occurred      = FALSE;
208     this->node_error_occurred = FALSE;
209     this->stop_parsing        = FALSE;
210     this->control_panel       = NUL(ControlPanel*);
211 
212     if (mode == _PARSE_NETWORK) {
213 
214         this->issued_version_error = FALSE;
215 
216 	//
217 	// Initialize the undefined/redefined modules dictionaries.
218 	//
219 	if (Network::ParseState::undefined_modules)
220 	    Network::ParseState::undefined_modules->clear();
221 	else
222 	    Network::ParseState::undefined_modules = new Dictionary;
223 
224 	if (Network::ParseState::redefined_modules)
225 	    Network::ParseState::redefined_modules->clear();
226 	else
227 	    Network::ParseState::redefined_modules = new Dictionary;
228     }
229 }
230 
Network()231 Network::Network()
232 {
233     this->deleting	= FALSE;
234 
235     this->editor       	= NUL(EditorWindow*);
236     this->saveAsDialog 	= NUL(SaveAsDialog*);
237     this->saveCfgDialog = NUL(Dialog*);
238     this->openCfgDialog = NUL(Dialog*);
239     this->setNameDialog = NUL(Dialog*);
240     this->setCommentDialog 	= NULL;
241     this->helpOnNetworkDialog 	= NULL;
242     this->prefix 	= NUL(char*);
243     this->description 	= NULL;
244     this->comment 	= NULL;
245     this->sequencer    	= NUL(SequencerNode*);
246     this->fileName     	= NUL(char *);
247     this->readingNetwork = FALSE;
248     this->definition 	= NULL;
249     this->remapInteractorOutputs = FALSE;
250 
251     this->commandScope = new CommandScope;
252     this->openAllPanelsCmd =
253 	new AccessNetworkPanelsCommand
254 	    ("openAllControlPanels", this->commandScope, FALSE,
255 		this, AccessNetworkPanelsCommand::OpenAllPanels);
256 
257     //
258     // CommandInterfaces that use this must arrange to set the instance
259     // number of the desired panel in the local data using
260     // UIComponent::setLocalData();
261     //
262     this->openPanelByInstanceCmd =
263 	new AccessNetworkPanelsCommand
264 	    ("openPanelByInstance", this->commandScope, TRUE,
265 		this, AccessNetworkPanelsCommand::OpenPanelByInstance);
266     //
267     // CommandInterfaces that use this must arrange to set the instance
268     // number of the desired panel in the local data using
269     // UIComponent::setLocalData();
270     //
271     this->openPanelGroupByIndexCmd =
272 	new AccessNetworkPanelsCommand
273 	    ("openPanelGroupByIndex", this->commandScope, TRUE,
274 		this, AccessNetworkPanelsCommand::OpenPanelGroupByIndex);
275 
276     this->closeAllPanelsCmd =
277 	new AccessNetworkPanelsCommand
278 	    ("closeAllControlPanels", this->commandScope, FALSE,
279 		this, AccessNetworkPanelsCommand::CloseAllPanels);
280 
281     this->newCmd =
282 	new NewCommand ("new", this->commandScope, FALSE, this,
283 			NULL /* We don't have an anchor window yet */);
284 
285     this->saveAsCmd =
286         new NoUndoNetworkCommand("saveAsCommand", this->commandScope,
287 			FALSE,
288 			this, NoUndoNetworkCommand::SaveNetworkAs);
289 
290     this->saveCmd =
291         new NoUndoNetworkCommand("saveCommand", this->commandScope,
292 			FALSE, this, NoUndoNetworkCommand::SaveNetwork);
293     this->saveCfgCmd =
294         new NoUndoNetworkCommand("saveCfgCommand", this->commandScope,
295 			FALSE, this, NoUndoNetworkCommand::SaveConfiguration);
296     this->openCfgCmd =
297         new NoUndoNetworkCommand("openCfgCommand", this->commandScope,
298 			FALSE, this, NoUndoNetworkCommand::OpenConfiguration);
299     this->setNameCmd =
300         new NoUndoNetworkCommand("setNameCommand", this->commandScope,
301 			TRUE, this, NoUndoNetworkCommand::SetNetworkName);
302     this->helpOnNetworkCmd =
303         new NoUndoNetworkCommand("helpOnNetworkCommand", this->commandScope,
304 			FALSE,this,NoUndoNetworkCommand::HelpOnNetwork);
305 
306     this->panelGroupManager = new PanelGroupManager(this);
307     this->panelAccessManager = new PanelAccessManager(this);
308 
309     //
310     // Set the activation of commands that depend on execution.
311     // Remember to remove them in the destructor.
312     //
313     theDXApplication->executingCmd->autoDeactivate(this->newCmd);
314     theDXApplication->notExecutingCmd->autoActivate(this->newCmd);
315     this->newCmd->autoActivate(theDXApplication->executeOnChangeCmd);
316 
317     this->deferrableRemoveNode = new DeferrableAction(
318 				Network::RemoveNodeWork, (void*)this);
319     this->deferrableAddNode = new DeferrableAction(
320 				Network::AddNodeWork, (void*)this);
321     this->deferrableSendNetwork = new DeferrableAction(
322 				Network::SendNetwork, (void*)this);
323 
324     this->selectionOwner = NUL(ControlPanel*);
325 
326 #if WORKSPACE_PAGES
327     this->groupManagers = BuildTheGroupManagerDictionary(this);
328 #endif
329 
330     this->editorMessages = NUL(List*);
331 
332     this->clear();
333 }
334 
335 
~Network()336 Network::~Network()
337 {
338 
339 #ifndef __PURIFY__
340     ASSERT(this != theDXApplication->network);
341 #endif
342 
343     this->deleting = TRUE;
344 
345     // TRUE means delete the panels now... don't add them to the dump list.
346     this->clear(TRUE);
347 
348     //
349     // This must go after clear() in case the Nodes have items in the
350     // editor.
351     //
352     if (this->editor) {
353 	if (!this->editor->isAnchor())
354 	    delete this->editor;
355 	this->editor = NULL;
356     }
357 
358     //
359     // Remove the auto de/activated commands from the 'server' commands.
360     //
361     theDXApplication->executingCmd->removeAutoCmd(this->newCmd);
362     theDXApplication->notExecutingCmd->removeAutoCmd(this->newCmd);
363 
364 
365     delete this->openAllPanelsCmd;
366     delete this->openPanelByInstanceCmd;
367     delete this->openPanelGroupByIndexCmd;
368     delete this->closeAllPanelsCmd;
369     delete this->newCmd;
370     delete this->saveAsCmd;
371     delete this->saveCmd;
372     if (this->saveCfgCmd) delete this->saveCfgCmd;
373     if (this->openCfgCmd) delete this->openCfgCmd;
374     delete this->setNameCmd;
375     delete this->helpOnNetworkCmd;
376 
377     //
378     // Delete the command scope after the commands.
379     //
380     delete this->commandScope;
381 
382     //
383     // Delete the dialogs.
384     //
385     if (this->setCommentDialog) delete this->setCommentDialog;
386     if (this->helpOnNetworkDialog) delete this->helpOnNetworkDialog;
387     if (this->saveAsDialog) 	delete this->saveAsDialog;
388     if (this->saveCfgDialog) 	delete this->saveCfgDialog;
389     if (this->openCfgDialog) 	delete this->openCfgDialog;
390     if (this->setNameDialog) 	delete this->setNameDialog;
391 
392     //
393     // Delete miscellaneous objects
394     //
395     delete this->deferrableSendNetwork;
396     delete this->deferrableRemoveNode;
397     delete this->deferrableAddNode;
398     delete this->panelGroupManager;
399     delete this->panelAccessManager;
400 
401     ListIterator it(this->decoratorList);
402     Decorator *dec;
403     while ( (dec = (Decorator*)it.getNext()) ) {
404 	this->decoratorList.removeElement((void*)dec);
405         delete dec;
406     }
407 
408 #if WORKSPACE_PAGES
409     //
410     // Delete the dictionary for group managers and every GroupManager
411     //
412     GroupManager *gmgr;
413     DictionaryIterator di(*this->groupManagers);
414     while ( (gmgr = (GroupManager*)di.getNextDefinition()) )
415 	delete gmgr;
416     delete this->groupManagers;
417 #endif
418 
419     if (this->editorMessages) {
420 	ListIterator ml(*this->editorMessages);
421 	char *msg;
422 	while ( (msg = (char*)ml.getNext()) )
423 	    delete msg;
424 	delete this->editorMessages;
425     }
426 }
427 
428 //
429 // Do any work that is necessary to read in a new .cfg file and/or
430 // clear the network of any .cfg information.
431 //
clearCfgInformation(boolean destroyPanelsNow)432 void Network::clearCfgInformation(boolean destroyPanelsNow)
433 {
434     ControlPanel *p;
435     while ( (p = (ControlPanel*) this->panelList.getElement(1)) )
436 	this->deletePanel(p, destroyPanelsNow);
437     this->resetPanelInstanceNumber();
438     this->panelGroupManager->clear();
439     this->panelAccessManager->clear();
440 
441     Node *node;
442     ListIterator l;
443     FOR_EACH_NETWORK_NODE(this, node, l)
444 	node->setDefaultCfgState();
445 
446 }
447 
clear(boolean destroyPanelsNow)448 boolean Network::clear(boolean destroyPanelsNow)
449 {
450     boolean was_deleting = this->deleting;
451 
452     this->deleting = TRUE;
453 
454     this->prepareForNewNetwork();
455 
456     //
457     // Reset the macro name, category, and description
458     //
459     this->name = theSymbolManager->registerSymbol(DEFAULT_MAIN_NAME);
460     if (this->description) {
461 	delete this->description;
462         this->description 	= NULL;
463     }
464     if (this->fileName) delete this->fileName;
465     this->fileName = NUL(char*);
466     this->setNetworkComment(NULL);
467     if (this->prefix)
468     {
469 	delete this->prefix;
470         this->prefix = NUL(char*);
471     }
472 
473 
474     //
475     // Delete the most basic elements first, since these may muck
476     // around with some of the others (i.e. InteractorNodes access their
477     // ControlPanels).  Delete each node from the network list before we
478     // delete it so that there are not references to deleted nodes during
479     // subsequent node deletions.
480     //
481     Node *n;
482     while ( (n = (Node*) this->nodeList.getElement(1)) ) {
483 	this->deleteNode(n);
484     }
485     Decorator *dec;
486     while ( (dec = (Decorator*)this->decoratorList.getElement(1)) ) {
487 	this->decoratorList.removeElement((void*)dec);
488 	delete dec;
489     }
490 
491     //
492     // Now clean up the control panels and other information in the .cfg .
493     //
494     this->clearCfgInformation(destroyPanelsNow);
495 
496     //
497     // Delete all the image windows except the anchor.
498     //
499     ImageWindow *iw, *anchor = NULL;
500     while( (iw = (ImageWindow*)imageList.getElement(1)) ) {
501 	this->imageList.deleteElement(1);
502 	if (iw->isAnchor()) {
503 	    ASSERT(anchor == NULL);
504 	    anchor = iw;
505 	} else {
506 	    delete iw;
507 	}
508     }
509     if (anchor)
510 	this->imageList.appendElement((void*)anchor);
511 
512 
513     if (this->helpOnNetworkDialog)
514         this->helpOnNetworkDialog->unmanage();
515 
516     if (this->setCommentDialog)
517         this->setCommentDialog->unmanage();
518 
519 
520     //
521     // Clear the process group manager if it's the main network.
522     //
523 #if WORKSPACE_PAGES
524     GroupManager *gmgr;
525     DictionaryIterator di(*this->groupManagers);
526     while ( (gmgr = (GroupManager*)di.getNextDefinition()) )
527 	gmgr->clear();
528 #else
529     if (this == theDXApplication->network)
530     	theDXApplication->PGManager->clear();
531 #endif
532 
533     //
534     // Reset the node instance numbers only if there are no other nodes
535     // currently in the system.  This currently means that there are no
536     // macros defined.
537     //
538     if ((this == theDXApplication->network) &&
539 				(theDXApplication->macroList.getSize() == 0))
540         NodeDefinition::ResetInstanceNumbers(theNodeDefinitionDictionary);
541 
542     this->category = 0;
543     this->macro = FALSE;
544     this->dirty = TRUE;
545     this->fileDirty = FALSE;
546 
547     if ((this->definition) && (this->definition->isReadingNet() == FALSE)) {
548 	delete this->definition;
549 	this->definition = NULL;
550     }
551 
552     //
553     // Assume all networks are 0.0.0 unless the version comment in the
554     // .net file indicates otherwise.  This assumes that when we write
555     // out the .net file we use NETFILE_*_VERSION instead of these.
556     //
557     this->netVersion.major = 0;
558     this->netVersion.minor = 0;
559     this->netVersion.micro = 0;
560 
561     //
562     // Assume all networks were written with dx version 1.0.0 unless the
563     // version comment in the .net file indicates otherwise.  This assumes
564     // that when we write out the .net file we use DX_*_VERSION instead of
565     // these.
566     //
567     this->dxVersion.major = 0;
568     this->dxVersion.minor = 0;
569     this->dxVersion.micro = 0;
570 
571 
572     this->completeNewNetwork();
573 
574     //
575     // Go back to the default work space configuration.  This must be done
576     // AFTER the workspace widgets have been marked as being_destroyed in
577     // order for the scrollbars to be removed.
578     //
579     this->workSpaceInfo.setDefaultConfiguration();
580 
581     this->netFileWasEncoded = FALSE;
582 
583     if (!was_deleting)
584 	this->deleting = FALSE;
585 
586     this->changeExistanceWork(NUL(Node*), FALSE);
587     return TRUE;
588 }
589 //
590 // Do whatever is necessary to speed up the process of reading in a
591 // new network.  This includes letting the EditorWindow know by calling
592 // editor->prepareForNewNetwork().
593 //
594 
prepareForNewNetwork()595 void Network::prepareForNewNetwork()
596 {
597     EditorWindow *editor = this->editor;
598 
599     if (Network::RenameTransmitterList)
600 	Network::RenameTransmitterList->clear();
601 
602     this->deferrableAddNode->deferAction();
603     this->deferrableRemoveNode->deferAction();
604 
605     //
606     // Let the editor know that the new network is coming.
607     //
608     if (editor)
609 	editor->prepareForNewNetwork();
610 
611     this->fileHadGetOrSetNodes = FALSE;
612 }
613 //
614 // Do whatever is necessary to speed up the process of reading in a
615 // new network.  This includes letting the EditorWindow know by calling
616 // editor->completeNewNetwork().
617 //
completeNewNetwork()618 void Network::completeNewNetwork()
619 {
620     //
621     // This is to accomadate an optimization in addNode() in which nodes
622     // are placed on the beginning of the list instead of the end.  This
623     // should make finding connected nodes quicker, but leaves
624     // this->nodeList unsorted.
625     //
626     if (this->readingNetwork)
627 	this->sortNetwork();
628 
629     //
630     // Let the editor know that the new network is done.
631     //
632     if (editor) {
633 	editor->installWorkSpaceInfo(&this->workSpaceInfo);
634 	editor->completeNewNetwork();
635     }
636 
637     this->resetWindowTitles();
638 
639     //
640     // Undefer the calls to changeNodeExistanceWork(), which may result in
641     // a call to AddNodeWork().
642     //
643     this->deferrableAddNode->undeferAction();
644     this->deferrableRemoveNode->undeferAction();
645 }
646 
AddNodeWork(void * staticData,void * requestData)647 void Network::AddNodeWork(void *staticData, void *requestData)
648 {
649      Network *n = (Network*)staticData;
650      n->changeExistanceWork((Node*)requestData, TRUE);
651 }
RemoveNodeWork(void * staticData,void * requestData)652 void Network::RemoveNodeWork(void *staticData, void *requestData)
653 {
654      Network *n = (Network*)staticData;
655      n->changeExistanceWork((Node*)requestData, FALSE);
656 }
changeExistanceWork(Node * n,boolean adding)657 void Network::changeExistanceWork(Node *n, boolean adding)
658 {
659     List *l;
660     ListIterator iter;
661     boolean hasCfg = FALSE;
662 
663     //
664     // If this isn't the 'main' network in dxui, then don't modify
665     // the commands of DXApplication.  We arrive at this point in the
666     // code whenever temporary networks are modified.  That shouldn't
667     // change activation of application commands.  ...bug106
668     //
669     boolean modify_application_commands = (this == theDXApplication->network);
670 
671 	if (adding) {
672 		List dummy;
673 		if (n) {
674 			dummy.appendElement((void*)n);
675 			iter.setList(dummy);
676 		} else {
677 			iter.setList(this->nodeList);
678 		}
679 		while ( (n = (Node*)iter.getNext()) ) {
680 			if (!this->sequencer && n->isA(ClassSequencerNode))
681 				this->sequencer = (SequencerNode*)n;
682 			n->initializeAfterNetworkMember();
683 			if (modify_application_commands) {
684 				if (!theDXApplication->openAllColormapCmd->isActive() &&
685 					n->isA(ClassColormapNode))
686 					theDXApplication->openAllColormapCmd->activate();
687 			}
688 			if (!hasCfg && n->hasCfgState())
689 				hasCfg = TRUE;
690 		}
691 		this->newCmd->activate();
692 		if (theDXApplication->appAllowsSavingNetFile(this))
693 			this->saveAsCmd->activate();
694 		if (this->fileName) {
695 			if (theDXApplication->appAllowsSavingNetFile(this))
696 				this->saveCmd->activate();
697 			if (hasCfg) {
698 				if (theDXApplication->appAllowsSavingCfgFile() &&
699 					this->saveCfgCmd)
700 					this->saveCfgCmd->activate();
701 				if (this->openCfgCmd) this->openCfgCmd->activate();
702 			}
703 		}
704 	} else {		// Not adding
705 		if (n) {
706 			if (this->sequencer && n->isA(ClassSequencerNode))
707 				this->sequencer = NULL;
708 			if (theDXApplication->openAllColormapCmd->isActive() &&
709 				n->isA(ClassColormapNode))
710 				if (modify_application_commands) {
711 					if (!this->containsClassOfNode(ClassColormapNode))
712 						theDXApplication->openAllColormapCmd->deactivate();
713 				}
714 		} else {
715 			if (modify_application_commands) {
716 				if (theDXApplication->openAllColormapCmd->isActive() &&
717 					!this->containsClassOfNode(ClassColormapNode))
718 					theDXApplication->openAllColormapCmd->deactivate();
719 			}
720 			if (this->sequencer &&
721 				!this->containsClassOfNode(ClassSequencerNode))
722 				this->sequencer = NULL;
723 		}
724 
725 		iter.setList(this->nodeList);
726 		while (!hasCfg && (n = (Node*)iter.getNext()))
727 			hasCfg = n->hasCfgState();
728 
729 		int count = this->nodeList.getSize();
730 		int decorCount = this->decoratorList.getSize();
731 		int groupCnt = 0;
732 		GroupManager *gmgr;
733 		DictionaryIterator di(*this->groupManagers);
734 		while ( (gmgr = (GroupManager*)di.getNextDefinition()) )
735 			groupCnt+= gmgr->getGroupCount();
736 		if ((count == 0) && (decorCount == 0) && (groupCnt == 0)) {
737 			this->newCmd->deactivate();
738 			this->saveCmd->deactivate();
739 			this->saveAsCmd->deactivate();
740 		}
741 		if ((count == 0) || !hasCfg) {
742 			if (this->saveCfgCmd) this->saveCfgCmd->deactivate();
743 			if (this->openCfgCmd) this->openCfgCmd->deactivate();
744 		}
745 	}
746 
747 	// FIXME : where does this go? Does it belong in DisplayNode
748 	//
749 	// Adjust which DisplayNode is "last"
750 	//
751 	l = this->makeClassifiedNodeList(ClassDisplayNode);
752 
753 	if(l)
754 	{
755 		ListIterator li(*l);
756 		Node        *node;
757 
758 		while ( (node = (Node*)li.getNext()) )
759 		{
760 			// If this is not the last DisplayNode...
761 			if(li.getPosition()-1 != l->getSize())
762 			{
763 				if(((DisplayNode *)(node))->isLastImage())
764 					((DisplayNode *)(node))->setLastImage(FALSE);
765 			}
766 			else
767 			{
768 				if(!((DisplayNode *)(node))->isLastImage())
769 					((DisplayNode *)(node))->setLastImage(TRUE);
770 			}
771 		}
772 		delete l;
773 	}
774 }
775 
776 //
777 // Allocate a new control panel that belongs to this network.
778 //
newControlPanel(int instance)779 ControlPanel *Network::newControlPanel(int instance)
780 {
781     ASSERT(instance >= 0);
782 
783     //
784     // Allocate and initialize the panel.
785     //
786     ControlPanel *panel = theDXApplication->newControlPanel(this);
787     ASSERT(panel);
788 
789     //
790     // Initialization is done when creating the window.
791     //
792     // panel->initialize();
793 
794     this->addPanel(panel, instance);
795 
796     return panel;
797 }
addPanel(ControlPanel * panel,int instance)798 boolean Network::addPanel(ControlPanel *panel, int instance)
799 {
800     //
801     // Add it to the network's list of panels.
802     //
803     boolean result = this->panelList.appendElement(panel);
804     ASSERT(result);
805 
806     //
807     // Allocate an instance number for the panel.
808     //
809     if (instance == 0) {
810 	panel->setInstanceNumber(this->newPanelInstanceNumber());
811     } else {
812 	int last_instance = this->getLastPanelInstanceNumber();
813 	ASSERT(instance > last_instance);
814 	panel->setInstanceNumber(instance);
815 	this->setLastPanelInstanceNumber(instance);
816     }
817     //
818     // Make sure the relevant commands are activated.
819     //
820     this->openAllPanelsCmd->activate();
821     this->closeAllPanelsCmd->activate();
822 
823     //
824     // Notify the DXWindow's (which includes updating their panelAccessDialog).
825     //
826     theDXApplication->notifyPanelChanged();
827 
828     //
829     // Notify the editor (which includes the PanelGroupDialog).
830     //
831     EditorWindow *editor = this->getEditor();
832     if (editor)
833     {
834         editor->notifyCPChange();
835     }
836 
837     return TRUE;
838 }
839 
getPanelByInstance(int instance)840 ControlPanel *Network::getPanelByInstance(int instance)
841 {
842     ListIterator iterator(this->panelList);
843     ControlPanel *cp;
844 
845     while ( (cp = (ControlPanel*)iterator.getNext()) ) {
846         if (cp->getInstanceNumber() == instance)
847             return cp;
848     }
849     return NULL;
850 }
851 
852 
postSequencer()853 void Network::postSequencer()
854 {
855     ASSERT(this->sequencer);
856 
857     this->sequencer->openDefaultWindow(NUL(Widget));
858 
859 }
860 
861 //
862 // Tell all data-driven interactors that they should ask the executive to
863 // remap their outputs.
864 //
setRemapInteractorOutputMode(boolean val)865 void Network::setRemapInteractorOutputMode(boolean val)
866 {
867     Node *node;
868     ListIterator l;
869 
870     if (this->remapInteractorOutputs == val)
871 	return;
872 
873     FOR_EACH_NETWORK_NODE(this, node, l) {
874 	if (node->isA(ClassInteractorNode)) {
875 	    InteractorNode *inode = (InteractorNode*)node;
876 	    if (inode->hasRemappableOutput())
877 		    inode->setOutputRemapping(val);
878 	}
879     }
880 
881     this->remapInteractorOutputs = val;
882 
883 }
884 
885 //
886 // Get the prefix that is prepended to identifiers when communicating with
887 // the Executive.
888 //
getPrefix()889 const char *Network::getPrefix()
890 {
891     const char *s;
892 
893     if (!this->prefix) {
894        ASSERT(this->name != 0);
895        s = theSymbolManager->getSymbolString(this->name);
896        ASSERT(s != NUL(const char*));
897        this->prefix = new char[STRLEN(s) + 2];
898        strcpy(this->prefix,s);
899        strcat(this->prefix,"_");
900     }
901     return this->prefix;
902 }
903 
deletePanel(ControlPanel * panel,boolean destroyPanelsNow)904 boolean Network::deletePanel(ControlPanel* panel, boolean destroyPanelsNow)
905 {
906     boolean result;
907     int     position;
908 
909     ASSERT(panel);
910 
911     if ( (position = this->panelList.getPosition(panel)) )
912     {
913 	//
914 	// Delete the panel from the list.
915 	//
916 	if ( (result = this->panelList.deleteElement(position)) )
917 	{
918 	    if (this->panelList.getSize() == 0)
919 	    {
920 		//
921 		// If no more panels, deactivate the
922 		// "Open All Control Panels" command.
923 		//
924 		this->openAllPanelsCmd->deactivate();
925 		this->closeAllPanelsCmd->deactivate();
926 	    }
927 	    //
928 	    // Move it into the 'dumpedList' and delete it later, but make
929 	    // sure it is removed from the display by unmanaging it.
930 	    //
931 	    // 3/31 - don't always add them to the dump list because it causes
932 	    // free-memory-read problems when clearing the dump list following
933 	    // destruction of a net.
934 	    //
935 	    if (panel->isManaged())
936 		panel->unmanage();
937 	    if (!destroyPanelsNow) theDXApplication->dumpObject(panel);
938 
939 	    //
940 	    // Remove all the InteractorInstances now, so that (probably
941 	    // among other things) the Interactors are not left associated
942 	    // with the Nodes when reading in a new .cfg file.
943 	    //
944        	    panel->clearInstances();
945 
946 	    //
947 	    // Notify the DXWindow's (which includes updating their
948 	    // panelAccessDialog).
949 	    //
950 	    theDXApplication->notifyPanelChanged();
951 
952 	    //
953 	    // Notify the editor (which includes the PanelGroupDialog).
954 	    //
955 	    if(this->getEditor())
956                 this->getEditor()->notifyCPChange();
957 
958 	    if (destroyPanelsNow) delete panel;
959 	}
960     }
961     else
962     {
963 	result = FALSE;
964     }
965 
966     return result;
967 }
968 
addImage(ImageWindow * image)969 boolean Network::addImage(ImageWindow* image)
970 {
971     ASSERT(image);
972 
973     return this->imageList.appendElement(image);
974 }
975 
976 
removeImage(ImageWindow * image)977 boolean Network::removeImage(ImageWindow* image)
978 {
979     int position;
980 
981     if ( (position = this->imageList.getPosition(image)) )
982     {
983 	return this->imageList.deleteElement(position);
984     }
985     else
986     {
987 	return FALSE;
988     }
989 }
990 
addNode(Node * node,EditorWorkSpace * where)991 void Network::addNode(Node *node, EditorWorkSpace *where)
992 {
993     this->setDirty();
994 
995     //
996     // This should make finding connected nodes quicker, but leaves
997     // this->nodeList unsorted (see this->completeNewNetwork()).
998     //
999     if (this->readingNetwork)
1000 	this->nodeList.insertElement(node,1);
1001     else
1002 	this->nodeList.appendElement(node);
1003 
1004     if (this->editor)
1005         this->editor->newNode(node, where);
1006 
1007 
1008     this->deferrableAddNode->requestAction((void*)node);
1009 }
1010 
setDirty()1011 void Network::setDirty()
1012 {
1013     this->dirty = TRUE;
1014     this->fileDirty = TRUE;
1015 
1016     DXExecCtl *execCtl = theDXApplication->getExecCtl();
1017 
1018     execCtl->terminateExecution();
1019 }
1020 
1021 
deleteNode(Node * node,boolean undefer)1022 void Network::deleteNode(Node *node, boolean undefer)
1023 {
1024     //
1025     // Disconnect the node from other nodes in the network first.
1026     // This helps us when a node's destructor results in a call to visitNodes()
1027     // in which arcs from other nodes are followed to the deleted node,
1028     // resulting in the node being put back in the Network.
1029     //
1030     node->disconnectArks();
1031 
1032     this->nodeList.removeElement(node);
1033 
1034     if (undefer) this->deferrableRemoveNode->requestAction((void*)node);
1035 
1036     delete node;        // Marks network dirty in ~Node()...
1037     //
1038     // No confirmation dialog asks the user to save the empty network.
1039     //
1040     if(this->nodeList.getSize() == 0)
1041         this->clearFileDirty();
1042 
1043 }
1044 
findNode(Symbol name,int instance)1045 Node *Network::findNode(Symbol name, int instance)
1046 {
1047     ListIterator li(this->nodeList);
1048     Node        *n;
1049 
1050     for(n = (Node*)li.getNext(); n != NULL; n = (Node*)li.getNext())
1051     {
1052 	if ((n->getNameSymbol() == name) &&
1053 	    ((n->getInstanceNumber() == instance) OR (instance == 0)) )
1054 	    return n;
1055     }
1056     return NUL(Node*);
1057 }
containsClassOfNode(const char * classname)1058 boolean Network::containsClassOfNode(const char *classname)
1059 {
1060     ListIterator iterator;
1061     Node        *node;
1062 
1063     FOR_EACH_NETWORK_NODE(this, node, iterator) {
1064         if (EqualString(node->getClassName(),classname))
1065 	    return TRUE;
1066     }
1067     return FALSE;
1068 
1069 }
1070 //
1071 // look through the network list and make a list of the given class.
1072 // If classname == NULL, then all nodes are included in the list.
1073 // If classname != NULL, and includeSubclasses = FALSE, then nodes must
1074 // be of the given class and not derived from the given class.
1075 // If no nodes were found then NULL is returned.
1076 // The returned List must be deleted by the caller.
1077 //
makeClassifiedNodeList(const char * classname,boolean includeSubclasses)1078 List *Network::makeClassifiedNodeList(const char *classname,
1079 					boolean includeSubclasses)
1080 {
1081     Node *node;
1082     ListIterator iterator;
1083     List        *l = NUL(List*);
1084 
1085     if ((classname != NUL(char*)) && (includeSubclasses == FALSE))
1086 	return this->nodeList.makeClassifiedNodeList(classname);
1087 
1088     FOR_EACH_NETWORK_NODE(this, node, iterator) {
1089         if ((classname == NULL) ||
1090 	    (includeSubclasses && node->isA(classname)) ||
1091 	    EqualString(node->getClassName(),classname)) {
1092             if (!l)
1093                 l = new List;
1094             l->appendElement((const void*) node);
1095         }
1096     }
1097     return l;
1098 }
1099 //
1100 // look through the network list and make a list of the nodes with
1101 // the give name.
1102 // If no nodes were found then NULL is returned.
1103 // The returned List must be deleted by the caller.
1104 //
makeNamedNodeList(const char * nodename)1105 List *Network::makeNamedNodeList(const char *nodename)
1106 {
1107     Node *node;
1108     ListIterator iterator;
1109     List        *l = NUL(List*);
1110 
1111 
1112     FOR_EACH_NETWORK_NODE(this, node, iterator) {
1113         if (EqualString(node->getNameString(),nodename)) {
1114             if (!l)
1115                 l = new List;
1116             l->appendElement((const void*) node);
1117         }
1118     }
1119     return l;
1120 }
1121 
1122 //
1123 // Close the given panel indicated by panelInstance.
1124 // If panelInstance is 0, unmanage all panels.
1125 // If the given panel(s) do not contain any interactors, then delete them
1126 // from the network.
1127 //
closeControlPanel(int panelInstance,boolean do_unmanage)1128 void Network::closeControlPanel(int panelInstance, boolean do_unmanage)
1129 {
1130     ListIterator  iterator(this->panelList);
1131     List	   toDelete, toUnmanage;
1132     ControlPanel* panel;
1133 
1134     while ( (panel = (ControlPanel*)iterator.getNext()) ) {
1135 	if ((panelInstance == 0) ||
1136 	    (panel->getInstanceNumber() == panelInstance)) {
1137 	    // getComponentCount is InstanceCount + DecoratorCount
1138 	    if (panel->getComponentCount() == 0)
1139 	        toDelete.appendElement((void*)panel);
1140 	    if (do_unmanage && panel->isManaged())
1141 	        toUnmanage.appendElement((void*)panel);
1142 	}
1143     }
1144 
1145     //
1146     // Now that we aren't iterating the panelList, we can do
1147     // this->deletePanel() and panel->unmanage().
1148     //
1149     iterator.setList(toDelete);
1150     while ( (panel = (ControlPanel*)iterator.getNext()) )
1151 	this->deletePanel(panel);
1152     iterator.setList(toUnmanage);
1153     while ( (panel = (ControlPanel*)iterator.getNext()) )
1154 	panel->unmanage();
1155 
1156 }
1157 //
1158 // Open the given panel indicated by panelInstance.
1159 // If panelInstance is 0, manage all panels.
1160 // If panelInstance is <0 , manage all panels that are marked as startup panels.
1161 //
openControlPanel(int panelInstance)1162 void Network::openControlPanel(int panelInstance)
1163 {
1164 	ControlPanel* panel;
1165 
1166 	if (panelInstance < 0) {
1167 		ListIterator iterator(this->panelList);
1168 		while ( (panel = (ControlPanel*) iterator.getNext()) ) {
1169 			if (panel->isStartup())
1170 				panel->manage();
1171 		}
1172 	} else if (panelInstance == 0 ) {
1173 		ListIterator  iterator(this->panelList);
1174 		while ( (panel = (ControlPanel*)iterator.getNext()) )
1175 			panel->manage();
1176 	} else {
1177 		panel = this->getPanelByInstance(panelInstance);
1178 		if (panel)
1179 			panel->manage();
1180 	}
1181 }
1182 //
1183 // Open the given panel group indicated by groupIndex.
1184 // Group indices are 1 based.
1185 //
openControlPanelGroup(int groupIndex)1186 void Network::openControlPanelGroup(int groupIndex)
1187 {
1188     List plist;
1189     int panelInstance;
1190 
1191     if (this->panelGroupManager->getPanelGroup(groupIndex,&plist)) {
1192     	ListIterator  iterator(plist);
1193     	while ( (panelInstance = (int)(long)iterator.getNext()) )
1194 	    this->openControlPanel(panelInstance);
1195     }
1196 }
1197 
1198 
1199 
1200 /***
1201  *** External variables:
1202  ***/
1203 
1204 extern "C"
1205 {
1206 extern
1207 FILE* yyin;			/* parser input stream	  */
1208 
1209 #if !defined(YYLINENO_DEFINED)
1210 int yylineno;			/* flex line number */
1211 #else
1212 extern int yylineno;			/* lexer line number      */
1213 #endif
1214 
1215 extern int yylexerstate;
1216 
1217 extern int yyparse();
1218 }
1219 
1220 /***
1221  *** Static variables:
1222  ***/
1223 #ifdef NoParseState
1224 
1225 static
1226 Dictionary *_undefined_modules = NUL(Dictionary*);
1227 				/* undefined module list  */
1228 
1229 static
1230 Dictionary *_redefined_modules = NUL(Dictionary*);
1231 				/* redefined module list  */
1232 
1233 
1234 static
1235 boolean _ignoreUndefinedModules;
1236 static
1237 boolean _main_macro_parsed;	/* main macro parsed?	  */
1238 
1239 static
1240 int _parse_mode;		/* parsing mode		  */
1241 
1242 static
1243 int _parse_state;		/* parse state		  */
1244 
1245 static
1246 const char* _parse_file;		/* parse file string	  */
1247 
1248 static
1249 Network* _network;		/* the network		  */
1250 static
1251 Node* _node;			/* the current Node	  */
1252 ControlPanel *_control_panel;	/* the current control panel */
1253 
1254 static
1255 boolean _error_occurred;	/* error found ?	  */
1256 
1257 static
1258 boolean _stop_parsing;		/* All parse functions return immediately */
1259 static
1260 boolean _issued_version_error;
1261 
1262 static
1263 boolean _node_error_occurred;	/* node error flag	  */
1264 
1265 static
1266 int _input_index;		/* current input param index	  */
1267 
1268 // The name of the current module (during argument parsing).
1269 static char _current_module[64];
1270 
1271 static
1272 int _output_index;		/* current output param index	  */
1273 #endif // NoParseState
1274 
1275 
1276 //
1277 // Open a .net file and a .cfg file (if it exists) and read the network.
1278 // 'netfile' contains the name of network file and should include the .net
1279 // extension.
1280 //
readNetwork(const char * netFile,const char * cfgFile,boolean ignoreUndefinedModules)1281 boolean Network::readNetwork(const char *netFile, const char *cfgFile,
1282 							 boolean ignoreUndefinedModules)
1283 {
1284 	Decorator *dec;
1285 	ListIterator it;
1286 
1287 	FILE *f;
1288 	int	namesize;
1289 	char *netfile, *cfgfile;
1290 
1291 	Network::ParseState::ignoreUndefinedModules = ignoreUndefinedModules;
1292 
1293 	netfile = Network::FilenameToNetname(netFile);
1294 
1295 	f = this->openNetworkFILE(netfile);
1296 
1297 	//
1298 	// If there is an editor and this net file is encoded, then don't
1299 	// allow reading the .net.  Note, to catch all cases, we must also
1300 	// not allow creating of Editor's for encoded nets that have already
1301 	// been read in (i.e. in image mode).
1302 	// See DXApplication::newNetworkEditor() and/or EditorWindow::manage().
1303 	//
1304 	if (this->getEditor() && this->wasNetFileEncoded()) {
1305 		ErrorMessage("This visual program is encoded and is "
1306 			"therefore not viewable with the VPE");
1307 		if (f) {
1308 			this->closeNetworkFILE(f);
1309 			f = NULL;
1310 		}
1311 	}
1312 
1313 	if (!f) {
1314 		delete netfile;
1315 		this->clear();
1316 		return FALSE;
1317 	}
1318 
1319 	if (this->fileName != NULL)
1320 		delete this->fileName;
1321 	this->fileName = netfile;
1322 
1323 #ifdef NoParseState
1324 	//
1325 	// Initialize the undefined/redefined modules dictionaries.
1326 	//
1327 	if (_undefined_modules)
1328 		_undefined_modules->clear();
1329 	else
1330 		_undefined_modules = new Dictionary;
1331 	if (_redefined_modules)
1332 		_redefined_modules->clear();
1333 	else
1334 		_redefined_modules = new Dictionary;
1335 #endif
1336 
1337 	//
1338 	// Parse the .net file
1339 	//
1340 	this->readingNetwork = TRUE;
1341 	this->prepareForNewNetwork();
1342 #ifdef NoParseState
1343 	_parse_mode = _PARSE_NETWORK;
1344 	_parse_file = netfile;
1345 #else
1346 	this->parseState.initializeForParse(this,_PARSE_NETWORK,netfile);
1347 #endif
1348 	boolean parse_terminated =  this->parse(f);
1349 	this->completeNewNetwork();
1350 	this->readingNetwork = FALSE;
1351 	this->closeNetworkFILE(f);
1352 #ifdef NoParseState
1353 #else
1354 	this->parseState.cleanupAfterParse();
1355 #endif
1356 
1357 	if (parse_terminated)  {
1358 		this->clear();
1359 		return FALSE;
1360 	}
1361 
1362 	//
1363 	// Parse the .cfg file if it exists.
1364 	//
1365 	if (!cfgFile) {
1366 		namesize = STRLEN(netfile);
1367 		cfgfile = DuplicateString(netfile);
1368 #ifndef DXD_OS_NON_UNIX          //SMH for NT we'll should handle upper case as well
1369 		ASSERT(netfile[namesize-4] == NetExtension[0]);
1370 		cfgfile[namesize-4]  = CfgExtension[0];
1371 		ASSERT(netfile[namesize-3] == NetExtension[1]);
1372 		cfgfile[namesize-3]  = CfgExtension[1];
1373 		ASSERT(netfile[namesize-2] == NetExtension[2]);
1374 		cfgfile[namesize-2]  = CfgExtension[2];
1375 		ASSERT(netfile[namesize-1] == NetExtension[3]);
1376 		cfgfile[namesize-1]  = CfgExtension[3];
1377 #else
1378 		ASSERT(netfile[namesize-4] == NetExtension[0]);
1379 		cfgfile[namesize-4]  = CfgExtension[0];
1380 		if (netfile[namesize-3] == NetExtension[1])
1381 		{
1382 			cfgfile[namesize-3]  = CfgExtension[1];
1383 			ASSERT(netfile[namesize-2] == NetExtension[2]);
1384 			cfgfile[namesize-2]  = CfgExtension[2];
1385 			ASSERT(netfile[namesize-1] == NetExtension[3]);
1386 			cfgfile[namesize-1]  = CfgExtension[3];
1387 		}
1388 		else if (netfile[namesize-3] == NetExtensionUpper[1])
1389 		{
1390 			cfgfile[namesize-3]  = CfgExtensionUpper[1];
1391 			ASSERT(netfile[namesize-2] == NetExtensionUpper[2]);
1392 			cfgfile[namesize-2]  = CfgExtensionUpper[2];
1393 			ASSERT(netfile[namesize-1] == NetExtensionUpper[3]);
1394 			cfgfile[namesize-1]  = CfgExtensionUpper[3];
1395 		}
1396 		else
1397 		{
1398 			fprintf(stderr,"Internal error detected at \"%s\":%d.\n",
1399 				__FILE__,__LINE__);
1400 		}
1401 #endif
1402 	} else
1403 		cfgfile = (char*)cfgFile;
1404 
1405 	this->openCfgFile(cfgfile, FALSE, FALSE);
1406 
1407 	if (cfgfile != cfgFile)
1408 		delete cfgfile;
1409 
1410 	//
1411 	// If we are in image mode then open control panels that are marked
1412 	// as 'startup' control panels and the sequencer if it exists.
1413 	//
1414 	if (!theDXApplication->inEditMode() &&
1415 		!theDXApplication->appSuppressesStartupWindows()) {
1416 			ListIterator iterator;
1417 
1418 #if USE_WINDOW_STARTUP
1419 			//
1420 			// Do the image windows.
1421 			//
1422 			ImageWindow *iw;
1423 			iterator.setList(this->imageList);
1424 			while(iw = (ImageWindow*)iterator.getNext()) {
1425 				if (iw->isStartup())
1426 					iw->manage();
1427 			}
1428 #endif
1429 
1430 			//
1431 			// Do the startup control panels.
1432 			//
1433 			this->openControlPanel(-1);
1434 
1435 			//
1436 			// Do the sequencer.
1437 			//
1438 			if ((this->sequencer) && (this->sequencer->isStartup()))
1439 				this->postSequencer();
1440 	}
1441 
1442 	if (this->editor) {
1443 		//
1444 		// turn line routing off before adding multiple vpe comments because
1445 		// each one can cause a line reroute.
1446 		//
1447 		boolean hasdec = (this->decoratorList.getSize() > 0);
1448 		if (hasdec) {
1449 			this->editor->beginPageChange();
1450 			FOR_EACH_NETWORK_DECORATOR (this, dec, it) {
1451 				this->editor->newDecorator(dec);
1452 			}
1453 			this->editor->endPageChange();
1454 		}
1455 	}
1456 
1457 	this->setDirty();
1458 
1459 
1460 	//
1461 	// Mark the network file dirty if there were redefined modules.
1462 	//
1463 	if (Network::ParseState::redefined_modules->getSize() > 0)
1464 		this->setFileDirty();
1465 	else
1466 		this->clearFileDirty();
1467 
1468 	/*
1469 	* Generate one collective error message for redefined modules.
1470 	*/
1471 	GenerateModuleMessage(Network::ParseState::redefined_modules,
1472 		"The following tools have been redefined",
1473 		FALSE);
1474 
1475 	/*
1476 	* Generate one collective error message for undefined modules.
1477 	*/
1478 	char msg[1024];
1479 	if (!strcmp(this->getNameString(), "main"))
1480 		SPRINTF(msg,
1481 		"The main visual program contains undefined tools.\n"
1482 		"Reload the visual program after loading the following tools");
1483 	else
1484 		SPRINTF(msg,
1485 		"Macro %s contains undefined tools.\n"
1486 		"Reload macro %s after loading the following tools",
1487 		this->getNameString(), this->getNameString());
1488 	GenerateModuleMessage(Network::ParseState::undefined_modules, msg, TRUE);
1489 
1490 	//
1491 	// These three are 0.0.0 unless they were parsed out of the .net
1492 	// which doesn't contain DX version numbers until DX 2.0.2
1493 	//
1494 	int dx_major = this->getDXMajorVersion();
1495 	int dx_minor = this->getDXMinorVersion();
1496 	int dx_micro = this->getDXMicroVersion();
1497 	int dx_version =   VERSION_NUMBER( dx_major, dx_minor, dx_micro);
1498 	//
1499 	// Version checking was added after version 2.0.2 of Data Explorer
1500 	//
1501 	if (!ParseState::issued_version_error &&
1502 		(dx_version > VERSION_NUMBER(2,0,2))) {
1503 			int net_major = this->getNetMajorVersion();
1504 			int net_minor = this->getNetMinorVersion();
1505 			// int net_micro = this->getNetMicroVersion();
1506 			// int net_version =   VERSION_NUMBER( net_major, net_minor, net_micro);
1507 			if (VERSION_NUMBER(net_major, net_minor,0) >
1508 				VERSION_NUMBER(NETFILE_MAJOR_VERSION,NETFILE_MINOR_VERSION,0)) {
1509 					const char *name = theDXApplication->getInformalName();
1510 					WarningMessage(
1511 						"%s%s was saved in a format defined by\n"
1512 						"a release of %s (version %d.%d.%d) that is\n"
1513 						"more recent than this version (%d.%d.%d).\n"
1514 						"Contact your support center if you would like to obtain a\n"
1515 						"version of %s that can fully support this visual program." ,
1516 						(this->isMacro()?"The macro " : "The visual program "),
1517 						(this->isMacro()?this->getDefinition()->getNameString():""),
1518 						name,dx_major,dx_minor,dx_micro,
1519 						DX_MAJOR_VERSION,DX_MINOR_VERSION,DX_MICRO_VERSION,
1520 						name);
1521 			}
1522 	}
1523 
1524 	//
1525 	// Fixup name conflicts with Transmitters/Receivers read in from old nets.
1526 	// (Must be done after readingNetwork is reset to FALSE, and dirty bit is cleared.)
1527 	//
1528 	this->renameTransmitters();
1529 
1530 	return TRUE;
1531 
1532 }
1533 
1534 //
1535 // Reset all the relevant window titles.
1536 // FIXME: this should be done by sending all DXWindows (i.e. clients
1537 // of the application) a MsgNetworkChanged message, but that requires
1538 // move newCmd, saveCmd and saveAsCmd up into DXApplication where
1539 // the belong anyway.
1540 //
resetWindowTitles()1541 void Network::resetWindowTitles()
1542 {
1543 DXWindow *anchor = theDXApplication->getAnchor();
1544 boolean anchor_reset = FALSE;
1545 
1546     if (this->editor) {
1547 	if (this->editor == anchor) anchor_reset = TRUE;
1548 	this->editor->resetWindowTitle();
1549     }
1550 
1551     ListIterator li(this->imageList);
1552     ImageWindow *iw;
1553     while( (iw = (ImageWindow*)li.getNext()) ) {
1554 	if (iw == anchor) anchor_reset = TRUE;
1555 	iw->resetWindowTitle();
1556     }
1557 
1558     //
1559     // ... and to deal with kiosk in a most clumsy way.
1560     // FIXME: Only 3 of the guys who subclass from DXWindow have resetWindowTitle().
1561     //
1562     if ((!anchor_reset)&&(anchor)) {
1563 	if (strcmp(anchor->getClassName(), ClassDXAnchorWindow) == 0) {
1564 	    DXAnchorWindow *dxa = (DXAnchorWindow*)anchor;
1565 	    dxa->resetWindowTitle();
1566 	}
1567     }
1568 
1569 }
1570 /*****************************************************************************/
1571 /* Parse -								     */
1572 /*                                                                           */
1573 /*                                                                           */
1574 /*****************************************************************************/
1575 
1576 #if defined(USING_BISON)
1577 extern "C" int yychar;
1578 #endif
1579 
1580 //
1581 // Returns TRUE if the parse was prematurely terminated.
1582 //
parse(FILE * input)1583 boolean Network::parse(FILE*    input)
1584 {
1585     boolean  result;
1586 
1587 
1588 
1589     ASSERT(input);
1590 
1591 #ifdef NoParseState
1592     /*
1593      * Save the network.
1594      */
1595     _network = this;
1596 #endif
1597 
1598     /*
1599      * Initialize...
1600      */
1601     yyin                 = input;
1602     yylineno             = 1;
1603     yylexerstate	 = _LEXER_INITIALIZE;
1604 #ifdef NoParseState
1605     _node		 = NULL;
1606     _parse_state         = _PARSED_NONE;
1607     _main_macro_parsed   = FALSE;
1608     _error_occurred      = FALSE;
1609     _node_error_occurred = FALSE;
1610     _stop_parsing 	 = FALSE;
1611     _issued_version_error = FALSE;
1612     _control_panel       = NUL(ControlPanel*);
1613 #endif
1614 
1615     result = TRUE;
1616 
1617 #if defined(USING_BISON)
1618     for (;;)
1619 #else
1620     while (NOT feof(yyin))
1621 #endif
1622     {
1623 	/*
1624 	 * If parse failed...
1625 	 */
1626 	if (yyparse()) {
1627 	    result = FALSE;
1628 	    break;
1629 	}
1630 
1631 #if defined(USING_BISON)
1632 	if (yychar == 0)
1633 	    break;
1634 #endif
1635 
1636 	/*
1637 	 * If error found...
1638 	 */
1639 	if (Network::ParseState::stop_parsing || Network::ParseState::error_occurred) {
1640 	    result = FALSE;
1641 	    break;
1642 	}
1643     }
1644 
1645     // Only nodes found in the .net file are added to the network.
1646     if (result && this->parseState.parse_mode == _PARSE_NETWORK &&
1647 				this->parseState.node != NULL) {
1648 	this->addNode(this->parseState.node);
1649 	this->parseState.node = NUL(Node*);
1650 #if 1
1651     //
1652     // If there's an error, then parseState.node is being cast adrift and in fact,
1653     // might sail its way back and wind up in a Network at some point.  This chunk
1654     // might be a little destabilizing.  I don't know what all the ramifications might
1655     // be.
1656     //
1657     } else if ((this->parseState.node) && (this->parseState.parse_mode==_PARSE_NETWORK)) {
1658 	this->addNode(this->parseState.node);
1659 	this->parseState.node = NUL(Node*);
1660 #endif
1661     }
1662 
1663     return Network::ParseState::stop_parsing;
1664 }
1665 
1666 //
1667 // Post either an error or a warning dialog with the given msg followed
1668 // by the names of the modules found in the dictionary.
1669 // If the dictionary is empty, no dialog is posted.
1670 //
GenerateModuleMessage(Dictionary * nodes,char * msg,boolean error)1671 static void GenerateModuleMessage(Dictionary *nodes, char *msg, boolean error)
1672 {
1673     int i, count;
1674     char *p, *message;
1675 
1676     /*
1677      * Generate one collective error message.
1678      */
1679     count = nodes->getSize();
1680     if (count == 0)
1681 	return;
1682 
1683     //
1684     // sanity check.  Otherwise we'll dump core in ErrorMessage because of
1685     // a fixed buffer.
1686     //
1687     count = MIN(count, 20);
1688 
1689     message = new char [STRLEN(msg) + 128 * count];
1690 
1691     sprintf(message, "%s:\n",msg);
1692     p = message + STRLEN(message);
1693 
1694     for (i = 1; i <= count; i++, p += STRLEN(p))
1695     {
1696 	if (i == count)
1697 	    sprintf(p,"     %s.",nodes->getStringKey(i));
1698 	else
1699 	    sprintf(p,"     %s,\n",nodes->getStringKey(i));
1700     }
1701 
1702     if (error)
1703 	ErrorMessage(message);
1704     else
1705 	WarningMessage(message);
1706     delete message;
1707 }
1708 /*****************************************************************************/
1709 /* ParseMODULEComment -						     */
1710 /*                                                                           */
1711 /* Parses "MODULE" comment.						     */
1712 /*                                                                           */
1713 /*****************************************************************************/
1714 
netParseMODULEComment(const char * comment)1715 void Network::netParseMODULEComment(const char* comment)
1716 {
1717     int  items_parsed;
1718     char name[1024];
1719 
1720     ASSERT(comment);
1721 
1722     items_parsed = sscanf(comment, " MODULE %[^\n]", name);
1723 
1724     if (items_parsed != 1)
1725     {
1726 	ErrorMessage("Invalid MODULE comment at %s:%d",
1727 				Network::ParseState::parse_file, yylineno);
1728 	Network::ParseState::error_occurred = TRUE;
1729 	return;
1730     }
1731 
1732 //    cout << "Module comment: " << name << ":\n";
1733 //    cout.flush();
1734 
1735 
1736     this->name = theSymbolManager->registerSymbol(name);
1737     if (this->prefix)
1738 	delete this->prefix;
1739     this->prefix = NULL;
1740 }
1741 
netParseMacroComment(const char * comment)1742 void Network::netParseMacroComment(const char* comment)
1743 {
1744     int  items_parsed;
1745     char type[1024],name[1024],path[1024];
1746 
1747     ASSERT(comment);
1748 
1749     //
1750     // Comments are one of the following:
1751     //
1752     //    // macro reference (direct) : MACRO_NAME MACRO_PATH
1753     //    // macro reference (indirect) : MACRO_NAME MACRO_PATH
1754     //    // macro definition : MACRO_NAME
1755     //
1756     items_parsed = sscanf(comment, " macro %[^:]: %[^ ] %[^\n]", type, name, path);
1757 
1758     if (items_parsed != 3)
1759     {
1760 	ErrorMessage("Invalid macro comment at %s:%d(ignoring)",
1761 				Network::ParseState::parse_file, yylineno);
1762 	return;
1763     } else if (strstr(type,"reference")) {
1764 	NodeDefinition *nd =
1765 	    (NodeDefinition*)theNodeDefinitionDictionary->findDefinition(name);
1766 
1767 	if (!nd) {	//  Try to load it for them
1768 	    char *errmsg = NULL;
1769 	    char buf[2048];
1770 	    SPRINTF(buf,"Attempting to load undefined macro %s from file %s"
1771 			" while reading %s",
1772 				name,path, Network::ParseState::parse_file);
1773 	    theDXApplication->getMessageWindow()->addInformation(buf);
1774 	    if (!MacroDefinition::LoadMacro(path,&errmsg)) {
1775 		Network::ParseState::undefined_modules->addDefinition(
1776 								name,NULL);
1777 		SPRINTF(buf,"Attempt to load %s failed: %s", name,errmsg);
1778 	        theDXApplication->getMessageWindow()->addInformation(buf);
1779 	        delete errmsg;
1780 	    } else {
1781 		SPRINTF(buf,"Attempt to load %s was successful",name);
1782 	        theDXApplication->getMessageWindow()->addInformation(buf);
1783 	    }
1784 	    theDXApplication->getMessageWindow()->manage();
1785 	}
1786 
1787     }	// else we ignore 'macro' comments
1788     return;
1789 }
1790 
1791 //
1792 // userQuery is a new method in QuestionDialogManager specially designed for the
1793 // temporally challenged.  It doesn't return until the user has responded - it
1794 // contains its own mini event loop (which is a mini loop for events, not a loop
1795 // for mini events).
1796 //
1797 // If the destination file doesn't currently exist don't bother doing anything.
1798 //
versionMismatchQuery(boolean netfile,const char * file)1799 boolean Network::versionMismatchQuery (boolean netfile, const char *file)
1800 {
1801 boolean want_to_proceed = TRUE;
1802 int response;
1803 
1804     if ((file) && (file[0])) {
1805 	struct STATSTRUCT statbuf;
1806 	if (STATFUNC(file, &statbuf) == -1) return TRUE;
1807     }
1808 
1809     if ((this->netVersion.major >= 2) && netfile) {
1810 	char buf[1024];
1811 	if (VERSION_NUMBER(this->netVersion.major, 0, 0) <
1812 	    VERSION_NUMBER(NETFILE_MAJOR_VERSION, 0, 0)) {
1813 	    if (this->dxVersion.major > 0) {
1814 		sprintf (buf, "Saving Data Explorer %d.%d.%d program file in "
1815 			"Data Explorer %d.%d.%d format.\n"
1816 			"NOTE: Programs saved by this version of Data Explorer "
1817 			"will NOT be readable by Data Explorer %d.%d.%d.\n"
1818 			"Do you want to proceed?",
1819 			this->dxVersion.major,
1820 			this->dxVersion.minor,
1821 			this->dxVersion.micro,
1822 			DX_MAJOR_VERSION,
1823 			DX_MINOR_VERSION,
1824 			DX_MICRO_VERSION,
1825 			this->dxVersion.major,
1826 			this->dxVersion.minor,
1827 			this->dxVersion.micro);
1828 		response = theQuestionDialogManager->userQuery (
1829 		    theDXApplication->getRootWidget(),
1830 		    (char *)buf, (char *)"Version Mismatch",
1831 		    (char *)"Yes", (char *)"No", (char *)NULL);
1832 		switch (response) {
1833 		    case QuestionDialogManager::OK:
1834 			want_to_proceed = TRUE;
1835 			break;
1836 		    default:
1837 			want_to_proceed = FALSE;
1838 			break;
1839 		}
1840 	    } else {
1841 		sprintf (buf, "Saving Data Explorer program file in "
1842 			"Data Explorer %d.%d.%d format.\n"
1843 			"NOTE: Programs saved by this version of Data Explorer "
1844 			"will NOT be readable by the version of\nData Explorer "
1845 			"that wrote this program.\n"
1846 			"Do you want to proceed?",
1847 			DX_MAJOR_VERSION,
1848 			DX_MINOR_VERSION,
1849 			DX_MICRO_VERSION);
1850 		response = theQuestionDialogManager->userQuery (
1851 		    theDXApplication->getRootWidget(), buf, "Version Mismatch",
1852 		    "Yes", "No", NULL);
1853 		switch (response) {
1854 		    case QuestionDialogManager::OK:
1855 			want_to_proceed = TRUE;
1856 			break;
1857 		    default:
1858 			want_to_proceed = FALSE;
1859 			break;
1860 		}
1861 	    }
1862 	}
1863     }
1864    return want_to_proceed;
1865 }
1866 
1867 
1868 /*****************************************************************************/
1869 /* parseVersionComment -						     */
1870 /*                                                                           */
1871 /* Parses "version" comment.						     */
1872 /*                                                                           */
1873 /*****************************************************************************/
1874 
parseVersionComment(const char * comment,boolean netfile)1875 void Network::parseVersionComment(const char* comment, boolean netfile)
1876 {
1877 	int  items_parsed;
1878 	int  net_major=0;
1879 	int  net_minor=0;
1880 	int  net_micro=0;
1881 	int  dx_major=0;
1882 	int  dx_minor=0;
1883 	int  dx_micro=0;
1884 
1885 	ASSERT(comment);
1886 
1887 	items_parsed =
1888 		sscanf(comment, " version: %d.%d.%d (format), %d.%d.%d",
1889 		&net_major, &net_minor, &net_micro,
1890 		&dx_major, &dx_minor, &dx_micro);
1891 
1892 	if (netfile) {
1893 		if (items_parsed != 6)
1894 		{
1895 			items_parsed =
1896 				sscanf(comment, " version: %d.%d.%d",
1897 				&net_major, &net_minor, &net_micro);
1898 			if (items_parsed != 3)
1899 			{
1900 
1901 				ErrorMessage("Invalid version comment at %s:%d",
1902 					Network::ParseState::parse_file,
1903 					yylineno);
1904 				Network::ParseState::error_occurred = TRUE;
1905 				return;
1906 			}
1907 		} else {
1908 			//
1909 			// Some sample .net file went out marked as DX version 2.1.100.
1910 			// This happened when we decided to make the rcs 7.0.2 branch,
1911 			// into the refresh release 2.1.5.  At the time the 7.0.2 branch
1912 			// was a "developer's" branch and thus marked as
1913 			// version 2.1.100.  This fixes the information message that
1914 			// pops up with version 3.x and later versions of dxui that
1915 			// tells what version of DX the .net was saved with.
1916 			//
1917 			if ((dx_major == 2) && (dx_minor == 1) && (dx_micro == 100))
1918 				dx_micro = 5;
1919 			this->dxVersion.major = dx_major;
1920 			this->dxVersion.minor = dx_minor;
1921 			this->dxVersion.micro = dx_micro;
1922 		}
1923 		this->netVersion.major = net_major;
1924 		this->netVersion.minor = net_minor;
1925 		this->netVersion.micro = net_micro;
1926 	} else {
1927 		if (items_parsed != 6) {
1928 			ErrorMessage("Invalid version comment at %s:%d",
1929 				Network::ParseState::parse_file, yylineno);
1930 			Network::ParseState::error_occurred = TRUE;
1931 			return;
1932 		}
1933 	}
1934 
1935 
1936     //
1937     // Check all version 2 and later .nets and .cfg against the
1938     // current NETFILE version number.  If the .net or .cfg has
1939     // a later major version number then don't attempt to parse
1940     // the file.
1941     //
1942     if ((net_major > 2) && (net_major > NETFILE_MAJOR_VERSION)) {
1943 	const char *name = theDXApplication->getInformalName();
1944         char buf[1024];
1945         if (netfile) {
1946             if (this->isMacro()) {
1947                 MacroDefinition *md = this->getDefinition();
1948                 sprintf(buf,"The macro %s", md->getNameString());
1949             } else
1950                 strcpy(buf,"This visual program");
1951         } else {
1952             strcpy(buf,"This configuration file");
1953         }
1954         ErrorMessage(
1955            "%s was saved in an incompatible format by\n"
1956            "a release of %s (version %d.%d.%d) that is\n"
1957            "more recent than this version (%s %d.%d.%d).\n"
1958            "Contact your support center if you would like to obtain a\n"
1959            "version of %s that can support this visual program." ,
1960                    buf,
1961                    name,dx_major,dx_minor,dx_micro,
1962                    name,DX_MAJOR_VERSION,DX_MINOR_VERSION,DX_MICRO_VERSION,
1963                    name);
1964 	ParseState::issued_version_error = TRUE;
1965 	Network::ParseState::stop_parsing = TRUE;
1966     }
1967 }
1968 
cfgParseVersionComment(const char * comment)1969 void Network::cfgParseVersionComment(const char* comment)
1970 {
1971     Network::parseVersionComment(comment,FALSE);
1972 }
netParseVersionComment(const char * comment)1973 void Network::netParseVersionComment(const char* comment)
1974 {
1975     Network::parseVersionComment(comment,TRUE);
1976 }
1977 
1978 /*****************************************************************************/
1979 /* ParseCATEGORYComment -						     */
1980 /*                                                                           */
1981 /* Parses "CATEGORY" comment.						     */
1982 /*                                                                           */
1983 /*****************************************************************************/
1984 
netParseCATEGORYComment(const char * comment)1985 void Network::netParseCATEGORYComment(const char* comment)
1986 {
1987     int  items_parsed;
1988     char category[1024];
1989 
1990     ASSERT(comment);
1991 
1992     items_parsed = sscanf(comment, " CATEGORY %[^\n]", category);
1993 
1994     if (items_parsed != 1)
1995     {
1996 	ErrorMessage("Invalid CATEGORY comment at %s:%d",
1997 				Network::ParseState::parse_file, yylineno);
1998 	Network::ParseState::error_occurred = TRUE;
1999 	return;
2000     }
2001 
2002     this->setCategory(category, FALSE);
2003 }
2004 
2005 
2006 /*****************************************************************************/
2007 /* ParseDESCRIPTIONComment -					     */
2008 /*                                                                           */
2009 /* Parses "DESCRIPTION" comment.					     */
2010 /*                                                                           */
2011 /*****************************************************************************/
2012 
netParseDESCRIPTIONComment(const char * comment)2013 void Network::netParseDESCRIPTIONComment(const char* comment)
2014 {
2015     int  items_parsed;
2016     char description[1024];
2017 
2018     ASSERT(comment);
2019 
2020     items_parsed = sscanf(comment, " DESCRIPTION %[^\n]", description);
2021 
2022     if (items_parsed != 1)
2023     {
2024 	ErrorMessage("Invalid DESCRIPTION comment at %s:%d",
2025 					Network::ParseState::parse_file, yylineno);
2026 	Network::ParseState::error_occurred = TRUE;
2027 	return;
2028     }
2029 
2030     this->setDescription(description, FALSE);
2031 }
2032 
2033 
2034 /*****************************************************************************/
2035 /* ParseCommentComment -						     */
2036 /*                                                                           */
2037 /* Parses "comment" comment.						     */
2038 /*                                                                           */
2039 /*****************************************************************************/
2040 
netParseCommentComment(const char * comment)2041 void Network::netParseCommentComment(const char* comment)
2042 {
2043 
2044     if (Network::ParseState::stop_parsing)
2045 	return;
2046 
2047     ASSERT(comment);
2048 
2049     /*
2050      * Save network program comments.
2051      */
2052     if (this->comment == NUL(char*))
2053     {
2054 	this->comment = DuplicateString(comment + STRLEN(" comment: "));
2055     }
2056     else
2057     {
2058 	this->comment =
2059 	    (char*)REALLOC
2060 		(this->comment,
2061 		 (2 + STRLEN(this->comment) + STRLEN(comment) -
2062 		 STRLEN(" comment: ")) * sizeof(char));
2063 	strcat(this->comment, "\n");
2064 	strcat(this->comment, comment + STRLEN(" comment: "));
2065     }
2066     this->setNetworkComment(this->comment);
2067 
2068 }
2069 
2070 /*****************************************************************************/
2071 /* ParseNodeComment -						             */
2072 /*                                                                           */
2073 /* Parses "node" comment.						     */
2074 /*                                                                           */
2075 /*****************************************************************************/
2076 
netParseNodeComment(const char * comment)2077 void Network::netParseNodeComment(const char* comment)
2078 {
2079     int        items_parsed;
2080     int        instance;
2081     char       name[1024];
2082 
2083     ASSERT(comment);
2084 
2085     /*
2086      * Ignore comments that we do not recognize
2087      */
2088     if (strncmp(" node ",comment,6))
2089         return;
2090 
2091     if (this->parseState.node != NULL)
2092 	this->addNode(this->parseState.node);
2093 
2094     this->parseState.node = NULL;
2095 
2096     this->parseState.node_error_occurred = FALSE;
2097 
2098     items_parsed = sscanf(comment, " node %[^[][%d]:", name, &instance);
2099     if (items_parsed != 2) {
2100 	ErrorMessage("Can't parse 'node' comment (file %s, line %d)",
2101 					Network::ParseState::parse_file, yylineno);
2102 	this->parseState.node_error_occurred = TRUE;
2103 	Network::ParseState::error_occurred = TRUE;
2104 	return;
2105     }
2106     NodeDefinition *nd =
2107 	(NodeDefinition*)theNodeDefinitionDictionary->findDefinition(name);
2108 
2109     if (nd == NULL)
2110     {
2111 	Network::ParseState::undefined_modules->addDefinition(name, NULL);
2112 	this->parseState.node_error_occurred = TRUE;
2113 	Network::ParseState::error_occurred = TRUE;
2114 	return;
2115     }
2116     this->parseState.node = nd->createNewNode(this, instance);
2117     if (this->parseState.node == NULL)
2118     {
2119         Network::ParseState::error_occurred      = TRUE;
2120 	this->parseState.node_error_occurred = TRUE;
2121 	return;
2122     }
2123     //
2124     //  Determine if the node definition has changed.
2125     //
2126     const char *p = strstr(comment,"inputs =");
2127     if (p) {
2128 	p += STRLEN("inputs =");
2129 	int inputs = atoi(p);
2130 	if (nd->isUserTool() &&
2131 	    !nd->isInputRepeatable() && (inputs != nd->getInputCount())) {
2132 	    const char *name = nd->getNameString();
2133 #if 0	// Only warn about changes in user modules now 5/18/94.
2134 	    //
2135 	    // Receivers are the only nodes that have 'inputs = 0' (in
2136 	    // old nets) but really do have a single input.
2137 	    //
2138 	    if (!((inputs == 0) && EqualString(name,"Receiver")))
2139 #endif
2140 		Network::ParseState::redefined_modules->addDefinition(name, NULL);
2141 	}
2142     }
2143     p = strstr(comment,"outputs =");
2144     if (p) {
2145 	p += STRLEN("outputs =");
2146 	int outputs = atoi(p);
2147 	if (nd->isUserTool() &&
2148 	    !nd->isOutputRepeatable() && (outputs != nd->getOutputCount())) {
2149 	    const char *name = nd->getNameString();
2150 	    Network::ParseState::redefined_modules->addDefinition(name, NULL);
2151 	}
2152     }
2153 
2154     Symbol sym = nd->getNameSymbol();
2155     if ((sym == NDAllocatorDictionary::GetNodeNameSymbol) ||
2156         (sym == NDAllocatorDictionary::SetNodeNameSymbol))
2157 	this->fileHadGetOrSetNodes = TRUE;
2158 
2159 
2160     this->parseState.input_index = 0;
2161     this->parseState.output_index = 0;
2162 
2163     /*
2164      * 'node' comment parsed successfully:  set the parse state.
2165      */
2166     this->parseState.parse_state = _PARSED_NODE;
2167 
2168     //
2169     // Now ask the node to parse the rest of the information.
2170     //
2171     if (!this->parseState.node->netParseComment(comment,
2172 				Network::ParseState::parse_file, yylineno)){
2173         WarningMessage("Unrecognized comment at line %d of file %s"
2174                         " (ignoring)", yylineno, Network::ParseState::parse_file);
2175 
2176     }
2177 }
2178 /*****************************************************************************/
2179 /* ParseNodeComment -						             */
2180 /*                                                                           */
2181 /* Parses "node" comment.						     */
2182 /*                                                                           */
2183 /*****************************************************************************/
2184 
cfgParseNodeComment(const char * comment)2185 void Network::cfgParseNodeComment(const char* comment)
2186 {
2187     int        items_parsed;
2188     int        instance;
2189     char       name[1024];
2190 
2191     ASSERT(comment);
2192 
2193     /*
2194      * Ignore comments that we do not recognize
2195      */
2196     if (strncmp(" node",comment,5))
2197         return;
2198 
2199     this->parseState.node = NULL;
2200     this->parseState.node_error_occurred = FALSE;
2201 
2202     items_parsed = sscanf(comment, " node %[^[][%d]:", name, &instance);
2203     if (items_parsed != 2) {
2204 	ErrorMessage("Can't parse 'node' comment (file %s, line %d)",
2205 					Network::ParseState::parse_file, yylineno);
2206 	this->parseState.node_error_occurred = TRUE;
2207 	Network::ParseState::error_occurred = TRUE;
2208 	return;
2209     }
2210     NodeDefinition *nd =
2211 	(NodeDefinition*)theNodeDefinitionDictionary->findDefinition(name);
2212 
2213     if (nd == NULL)
2214     {
2215 	Network::ParseState::undefined_modules->addDefinition(name, NULL);
2216 	this->parseState.node_error_occurred = TRUE;
2217 	Network::ParseState::error_occurred = TRUE;
2218 	return;
2219     }
2220     Symbol namesym = theSymbolManager->getSymbol(name);
2221     this->parseState.node = this->findNode(namesym, instance);
2222     if (this->parseState.node == NULL)
2223     {
2224 	WarningMessage("The '%s' tool is referenced at line %d in file %s,\n"
2225 			"but is not found in the program.",
2226 			name,yylineno,Network::ParseState::parse_file);
2227         Network::ParseState::error_occurred      = TRUE;
2228 	this->parseState.node_error_occurred = TRUE;
2229 	return;
2230     }
2231 
2232     /*
2233      * 'node' comment parsed successfully:  set the parse state.
2234      */
2235     this->parseState.parse_state = _PARSED_NODE;
2236 
2237     //
2238     // Now ask the node to parse the rest of the information.
2239     //
2240     if (!this->parseState.node->cfgParseComment(comment,
2241 			Network::ParseState::parse_file, yylineno)) {
2242         WarningMessage("Unrecognized comment at line %d of file %s"
2243                               " (ignoring)",  yylineno, Network::ParseState::parse_file);
2244     }
2245 }
2246 
2247 
2248 //
2249 // Parse all comments out of the .net file
2250 //
netParseComments(const char * comment,const char * filename,int lineno)2251 boolean Network::netParseComments(const char *comment, const char *filename,
2252 					int lineno)
2253 {
2254 
2255     /*
2256      * if .net node comment...
2257      * This signifies the beginning of the node comments
2258      */
2259     if (EqualSubstring(comment, " node", 5))
2260     {
2261 	Network::netParseNodeComment(comment);
2262     }
2263     else if (EqualSubstring(comment, " version", 8))
2264     {
2265 	Network::netParseVersionComment(comment);
2266     }
2267     /*
2268      * If .net MODULE comment...
2269      */
2270     else if (EqualSubstring(comment, " MODULE", 7))
2271     {
2272 	Network::netParseMODULEComment(comment);
2273     }
2274     /*
2275      * If .net CATEGORY comment...
2276      */
2277     else if (EqualSubstring(comment, " CATEGORY", 9))
2278     {
2279 	Network::netParseCATEGORYComment(comment);
2280     }
2281     /*
2282      * If .net pgroup comment...
2283      */
2284 #if WORKSPACE_PAGES
2285     else if (EqualSubstring(comment, " pgroup assignment", 18))
2286     {
2287 	Dictionary *dict = this->groupManagers;
2288 	GroupManager *gmgr = (GroupManager*)dict->findDefinition(PROCESS_GROUP);
2289 	if (gmgr)
2290 	    gmgr->parseComment(comment, Network::ParseState::parse_file, yylineno, this);
2291     }
2292     /*
2293      * If .net page group comment...
2294      */
2295     else if (EqualSubstring(comment, " page assignment", 16))
2296     {
2297 	Dictionary *dict = this->groupManagers;
2298 	GroupManager *gmgr = (GroupManager*)dict->findDefinition(PAGE_GROUP);
2299 	gmgr->parseComment(comment, Network::ParseState::parse_file, yylineno, this);
2300     }
2301 #else
2302     else if (EqualSubstring(comment, " pgroup assignment", 18))
2303     {
2304 	theDXApplication->PGManager->parseComment(comment,
2305 			Network::ParseState::parse_file, yylineno, this);
2306     }
2307 #endif
2308     /*
2309      * If .net DESCRIPTION comment...
2310      */
2311     else if (EqualSubstring(comment, " DESCRIPTION", 12))
2312     {
2313 	Network::netParseDESCRIPTIONComment(comment);
2314     }
2315     /*
2316      * If .net comment comment...
2317      */
2318     else if (EqualSubstring(comment, " comment: ", 10))
2319     {
2320 	this->netParseCommentComment(comment);
2321     }
2322     /*
2323      * If .net comment comment...
2324      */
2325     else if (EqualSubstring(comment, " macro ", 7))
2326     {
2327 	this->netParseMacroComment(comment);
2328     }
2329     /*
2330      * If .net network: end of macro body comment...
2331      */
2332     else if (EqualString(comment, " network: end of macro body"))
2333     {
2334 	this->parseState.main_macro_parsed = TRUE;
2335 	this->parseState.parse_state = _PARSED_NONE;
2336     }
2337     /*
2338      * If decorator comment...
2339      * FIXME: must handle stateful resource comments, but this won't work.
2340      * It will do for now, only because only decorators have resource comments.
2341      */
2342     else if ((EqualSubstring(comment, " decorator", 10)) ||
2343 	     (EqualSubstring(comment, " annotation", 11)) ||
2344 	     (EqualSubstring(comment, " resource", 9)))
2345     {
2346 	if (!this->parseDecoratorComment(comment,
2347 				Network::ParseState::parse_file, yylineno)) {
2348 	    Network::ParseState::error_occurred = TRUE;
2349 	} else {
2350 #if WORKSPACE_PAGES
2351 	    this->parseState.parse_sub_state = _SUB_PARSED_DECORATOR;
2352 #endif
2353 	}
2354     }
2355 #if WORKSPACE_PAGES
2356     else if ((strstr(comment, " group:")) &&
2357 	       (this->parseState.parse_sub_state == _SUB_PARSED_DECORATOR))
2358     {
2359 	if (!this->parseDecoratorComment(comment,
2360 				Network::ParseState::parse_file, yylineno)) {
2361 	    Network::ParseState::error_occurred = TRUE;
2362 	}
2363     }
2364     else if ((this->parseState.parse_state == _PARSED_NODE) &&
2365 	     (this->parseState.parse_sub_state == _SUB_PARSED_NODE) &&
2366 	     (strstr(comment, " group:")) &&
2367 	     (this->parseState.node_error_occurred == FALSE)) {
2368 	if (!this->parseState.node->netParseComment(comment,
2369 				Network::ParseState::parse_file, yylineno)) {
2370 	    WarningMessage("Unrecognized comment at line %d of file %s"
2371 			   " (ignoring)",
2372 			lineno,filename);
2373 	}
2374     }
2375 #endif
2376     /*
2377      * If .net workspace comment...
2378      */
2379 	else if (EqualSubstring(comment, " workspace", 10))
2380 	{
2381 		if (!this->workSpaceInfo.parseComment(comment,
2382 			Network::ParseState::parse_file, yylineno)) {
2383 				Network::ParseState::error_occurred      = TRUE;
2384 		}
2385 		this->parseState.parse_state = _PARSED_WORKSPACE;
2386 	}
2387 	else if (this->parseState.parse_state == _PARSED_NODE &&
2388 		this->parseState.node_error_occurred == FALSE) {
2389 			if (!this->parseState.node->netParseComment(comment,
2390 				Network::ParseState::parse_file, yylineno)) {
2391 					WarningMessage("Unrecognized comment at line %d of file %s"
2392 						" (ignoring)",
2393 						lineno,filename);
2394 			} else {
2395 #if WORKSPACE_PAGES
2396 				this->parseState.parse_sub_state = _SUB_PARSED_NODE;
2397 #endif
2398 			}
2399 	}
2400 	else if (this->parseState.parse_state == _PARSED_WORKSPACE)
2401 	{
2402 		if (!this->workSpaceInfo.parseComment(comment,
2403 			Network::ParseState::parse_file, yylineno)) {
2404 				WarningMessage("Unrecognized comment at line %d of file %s"
2405 					" (ignoring)",
2406 					lineno,filename);
2407 		}
2408 	}
2409 	else if (this->parseState.parse_state == _PARSED_NODE) {
2410 		WarningMessage("Unrecognized comment at line %d of file %s (ignoring)",
2411 			lineno,filename);
2412 		//this->parseState.node_error_occurred = TRUE;
2413 		//this->parseState.error_occurred      = TRUE;
2414 	}
2415 
2416     return (Network::ParseState::error_occurred == FALSE);
2417 
2418 }
2419 
2420 //
2421 // Parse all comments out of the .cfg file
2422 //
cfgParseComments(const char * comment,const char * filename,int lineno)2423 boolean Network::cfgParseComments(const char *comment, const char *filename,
2424 					int lineno)
2425 {
2426 
2427     /*
2428      * if a .cfg interactor comment...
2429      * This signifies the beginning of the interactor comments.
2430      */
2431     if (EqualSubstring(comment, " interactor", 11))
2432     {
2433 	this->cfgParseInteractorComment(comment);
2434     }
2435     /*
2436      * if a .cfg panel comment (this signifies the begining of the panel
2437      * comments)
2438      */
2439     else if (EqualSubstring(comment, " panel[", 7))
2440     {
2441 	this->cfgParsePanelComment(comment);
2442     }
2443     /*
2444      * If version comment(in the .cfg file)...
2445      */
2446     else if (EqualSubstring(comment, " version", 8))
2447     {
2448 	this->cfgParseVersionComment(comment);
2449     }
2450     /*
2451      * If vcr comment(in the .cfg file)...
2452      * In version 3, we started using the '// node Sequencer[%d]:' comments
2453      */
2454     else if ((this->getNetMajorVersion() < 3) &&
2455 		EqualSubstring(comment, " vcr", 4))
2456     {
2457 #if 00
2458 	Node *vcr= this->findNode(
2459 				theSymbolManager->getSymbol("Sequencer"),0);
2460 #else
2461 	Node *vcr= this->sequencer;
2462 	ASSERT(vcr);
2463 #endif
2464 	if (vcr && vcr->cfgParseComment(comment,filename, lineno))
2465 	    this->parseState.parse_state 	 = _PARSED_VCR;
2466     	else
2467 	    this->parseState.error_occurred      = TRUE;
2468     }
2469     else if (EqualSubstring(comment, " node", 5))
2470     {
2471 	this->cfgParseNodeComment(comment);
2472     }
2473     else if ((this->parseState.parse_state == _PARSED_NODE) ||
2474 	     (this->parseState.parse_state == _PARSED_INTERACTOR))
2475     {
2476 	if ((this->parseState.node_error_occurred == FALSE) &&
2477 	    !this->parseState.node->cfgParseComment(comment,filename, lineno)) {
2478 	    WarningMessage("Unrecognized comment at line %d of file %s"
2479 			   " (ignoring)", lineno,filename);
2480 	}
2481     }
2482     else if (this->parseState.parse_state == _PARSED_PANEL)
2483     {
2484 	ASSERT(this->parseState.control_panel);
2485 	if (!this->parseState.control_panel->cfgParseComment(comment,
2486 							filename, lineno)) {
2487 	    WarningMessage("Unrecognized comment at line %d of file %s"
2488 			   " (ignoring)", lineno,filename);
2489 	}
2490     }
2491     else if (this->parseState.parse_state == _PARSING_NETWORK_CFG)
2492     {
2493 	if (!this->cfgParseComment(comment,filename,lineno)) {
2494 	    WarningMessage("Unrecognized comment at line %d of file %s"
2495 			   " (ignoring)", lineno,filename);
2496 	}
2497     }
2498     /*
2499      * The 'time:' comment (in the .cfg file) signifies
2500      * the beginning of the application's cfg comments.
2501      */
2502     else if (EqualSubstring(comment, " time:", 6))
2503     {
2504 	 this->parseState.parse_state = _PARSING_NETWORK_CFG;
2505     }
2506 
2507     return (this->parseState.error_occurred == FALSE);
2508 
2509 }
2510 /*****************************************************************************/
2511 /* uinParseComment -							     */
2512 /*                                                                           */
2513 /* Parses comment.							     */
2514 /*                                                                           */
2515 /*****************************************************************************/
2516 
2517 extern "C"
ParseComment(char * comment)2518 void ParseComment(char* comment)
2519 {
2520     ASSERT(Network::ParseState::network);
2521     Network::ParseState::network->parseComment(comment);
2522 }
2523 
parseComment(char * comment)2524 void Network::parseComment(char* comment)
2525 {
2526     ASSERT(comment);
2527 
2528     /*
2529      * Suppress further processing if first macro has already been
2530      * parsed.
2531      */
2532     if (this->parseState.main_macro_parsed)
2533 	    return;
2534 
2535     /*
2536      * If blank comment...
2537      */
2538     if (IsBlankString(comment))
2539     {
2540 	return;
2541     }
2542 
2543     /*
2544      * Handle either a .cfg or a .net comment
2545      */
2546     if (this->parseState.parse_mode == _PARSE_NETWORK)
2547 	this->netParseComments(comment,
2548 				this->parseState.parse_file, yylineno);
2549     else if (this->parseState.parse_mode == _PARSE_CONFIGURATION)
2550 	this->cfgParseComments(comment,
2551 				this->parseState.parse_file, yylineno);
2552 }
2553 
2554 /*****************************************************************************/
2555 /* uinParseFunctionID -							     */
2556 /*                                                                           */
2557 /* Parses function name.						     */
2558 /*                                                                           */
2559 /*****************************************************************************/
2560 
2561 extern "C"
ParseFunctionID(char * name)2562 void ParseFunctionID(char* name)
2563 {
2564     ASSERT(Network::ParseState::network);
2565     Network::ParseState::network->parseFunctionID(name);
2566 }
parseFunctionID(char * name)2567 void Network::parseFunctionID(char *name)
2568 {
2569 
2570     if (this->parseState.stop_parsing)
2571 	return;
2572 
2573 
2574     /*
2575      * Suppress further processing if first macro has already been
2576      * parsed.
2577      */
2578     if (this->parseState.main_macro_parsed)
2579 	return;
2580 
2581     ASSERT(name);
2582 #if 000
2583     strcpy(_current_module,name);
2584 #endif
2585     this->parseState.output_index = 0;
2586 }
2587 
2588 
2589 /*****************************************************************************/
2590 /* uinParseArgument -							     */
2591 /*                                                                           */
2592 /* Parses function arguments, i.e., uses arguement variable names to	     */
2593 /* generate connections (arcs) between nodes.				     */
2594 /*                                                                           */
2595 /*****************************************************************************/
2596 
2597 extern "C"
ParseArgument(char * name,const boolean isVarname)2598 void ParseArgument(char* name, const boolean isVarname)
2599 {
2600     ASSERT(Network::ParseState::network);
2601     Network::ParseState::network->parseArgument(name,isVarname);
2602 }
parseArgument(char * name,const boolean isVarname)2603 void Network::parseArgument(char* name, const boolean isVarname)
2604 {
2605     int        parsed_items;
2606     int        instance;
2607     int        parameter;
2608     char       type[128];
2609     char       module[512];
2610     boolean parse_error = FALSE;
2611     char macro[250];
2612 
2613     if (this->parseState.stop_parsing || this->parseState.main_macro_parsed)
2614 	return;
2615 
2616     ASSERT(name);
2617     /*
2618      * If the destination node has not yet been specified....
2619      */
2620     if (this->parseState.node == NULL)
2621 	return;
2622 
2623     /*
2624      * Increment the parameter number and save it as the parameter index
2625      * of the destination node.
2626      */
2627     this->parseState.input_index++;
2628 
2629 
2630     if (!isVarname)
2631 	return;
2632 
2633     /*
2634      * Scan the name for components.
2635      */
2636     parsed_items =
2637 	sscanf(name,
2638 	       "%[^_]_%[^_]_%d_%[^_]_%d",
2639 	       macro,
2640 	       module,
2641 	       &instance,
2642 	       type,
2643 	       &parameter);
2644 
2645     if (parsed_items != 5) {
2646 	parsed_items =
2647 	    sscanf(name,
2648 		   "%[^_]_%d_%[^_]_%d",
2649 		   module,
2650 		   &instance,
2651 		   type,
2652 		   &parameter);
2653 	/*
2654 	 * If parse failed...
2655 	 */
2656 	if (parsed_items != 4)
2657 	    parse_error = TRUE;
2658 
2659     } else if (!EqualString(macro, this->getNameString())) {
2660 	parse_error = TRUE;
2661     }
2662 
2663     if (parse_error && !EqualString("NULL", name)) {
2664 	ErrorMessage( "Error parsing tool input %s (in %s, line %d)",
2665 	    name, this->parseState.parse_file, yylineno);
2666 	this->parseState.error_occurred = TRUE;
2667 	return;
2668     }
2669 
2670     /*
2671      * if not "out" or "in"...
2672      */
2673     if (NOT EqualString(type, "out"))
2674     {
2675 	if (NOT EqualString(type, "in"))
2676 	{
2677 	    ErrorMessage( "Error parsing tool input %s (in %s, line %d)",
2678 		name, this->parseState.parse_file, yylineno);
2679 	    this->parseState.error_occurred = TRUE;
2680 	}
2681 #if 000	// Start of changes for expression into Compute 2/23/95
2682 	//
2683 	// If a tool implements itself with a series of module calls,
2684 	// don't bump the index when variable name does not match the current
2685 	// module.  This input will  not be connected to anything, but throws
2686 	// off the other input connections if we don't decrement the index.
2687 	// For example, don't bump the index on 'Compute_1_in_5' in
2688 	// the following:
2689 	//
2690 	//  Compute_1_out_1 = List(Compute_1_in_5,foo_1_out_1);
2691 	//  Compute_1_out_1 = Compute(Compute_1_out_1,bar_1_out_1);
2692 	//
2693 	if (!EqualString(module,_current_module))
2694 	    this->parseState.input_index--;
2695 #endif
2696 	return;
2697     }
2698 
2699 
2700     //
2701     // If this node does not have enough inputs, and they were not added
2702     // earlier because this is a .net without the number of inputs in the
2703     // comment, then add a set of input repeats.
2704     //
2705     if (this->parseState.input_index >
2706 				this->parseState.node->getInputCount()) {
2707 	if (this->parseState.node->isInputRepeatable() &&
2708 				this->getNetMajorVersion() == 0) {
2709 	    this->parseState.node->addInputRepeats();
2710 	} else {
2711 	    ErrorMessage(
2712 		"Node %s had unexpected number of inputs, file %s, line %d",
2713 		this->parseState.node->getNameString(),
2714 					this->parseState.parse_file, yylineno);
2715 	    this->parseState.error_occurred = TRUE;
2716 	    return;
2717 	}
2718     }
2719 
2720     // The following is for 'out' input parameters ONLY!
2721 
2722     Symbol s_of_out = theSymbolManager->registerSymbol(module);
2723     //
2724     //  Skip any nodes that are 'connected to themselves' such as
2725     //  the Colormap module which does something like the following...
2726     //    Colormap_1_out_1 = f(a);
2727     //    Colormap_1_out_1 = g(Colormap_1_out_1);
2728     //		....
2729     //  If the names and instances are the same then we assume we have
2730     //  the above situation.
2731     //
2732     if ((this->parseState.node->getNameSymbol() == s_of_out) &&
2733 	(this->parseState.node->getInstanceNumber() == instance))
2734 	return;
2735 
2736     Node *n;
2737     boolean found = FALSE;
2738 #if 00
2739     ListIterator l;
2740     FOR_EACH_NETWORK_NODE(this, n, l)
2741     {
2742 	if (n->getNameSymbol() == s_of_out &&
2743 	    n->getInstanceNumber() == instance)
2744 #else
2745 	if ( (n = this->findNode(s_of_out, instance)) )
2746 #endif
2747 	{
2748 	    if (n->getOutputCount() < parameter)
2749 		ErrorMessage("Cannot connect output %d of %s to %s, "
2750 			     "too many outputs (in %s, line %d)",
2751 			 parameter, module,
2752 			 this->parseState.node->getNameString(),
2753 			 this->parseState.parse_file, yylineno);
2754 	    else if (this->parseState.node->getInputCount() <
2755 			    this->parseState.input_index)
2756 		ErrorMessage("Cannot connect input %d of %s to %s, "
2757 			     "too many inputs (in %s, line %d)",
2758 			 this->parseState.input_index,
2759 			 this->parseState.node->getNameString(),
2760 			 module,
2761 			 this->parseState.parse_file, yylineno);
2762 	    else
2763 	    {
2764 		// Connect output parameter to input of this->parseState.node
2765 		new Ark(n, parameter, this->parseState.node,
2766 				this->parseState.input_index);
2767 		this->parseState.node->setInputVisibility(
2768 			this->parseState.input_index,TRUE);
2769 		n->setOutputVisibility(parameter,TRUE);
2770 	    }
2771 	    found = TRUE;
2772 #if 00
2773 	    break;
2774 	}
2775 #endif
2776     }
2777     if (!found && !this->parseState.ignoreUndefinedModules)
2778     {
2779 	this->parseState.undefined_modules->addDefinition(module, NULL);
2780 	this->parseState.error_occurred = TRUE;
2781 	return;
2782     }
2783 }
2784 
2785 
2786 /*****************************************************************************/
2787 /* uinParseLValue -							     */
2788 /*                                                                           */
2789 /*                                                                           */
2790 /*****************************************************************************/
2791 
2792 extern "C"
ParseLValue(char * name)2793 void ParseLValue(char* name)
2794 {
2795     ASSERT(Network::ParseState::network);
2796     Network::ParseState::network->parseLValue(name);
2797 }
2798 
parseLValue(char * name)2799 void Network::parseLValue(char* name)
2800 {
2801     if (this->parseState.stop_parsing)
2802 	return;
2803 
2804     /*
2805      * Suppress further processing if first macro has already been
2806      * parsed.
2807      */
2808     if (this->parseState.main_macro_parsed)
2809 	return;
2810 
2811     ASSERT(name);
2812 
2813     //
2814     // Only bump the output index when given an output parameter name.
2815     //
2816     if (strstr(name,"_out_"))
2817         ++this->parseState.output_index;
2818 
2819 }
2820 
2821 extern "C"
ParseStringAttribute(char * name,char * value)2822 void ParseStringAttribute(char* name, char* value)
2823 {
2824     ASSERT(Network::ParseState::network);
2825     Network::ParseState::network->parseStringAttribute(name,value);
2826 }
2827 
parseStringAttribute(char * name,char * value)2828 void Network::parseStringAttribute(char* name, char *value)
2829 {
2830     if (this->parseState.stop_parsing)
2831 	return;
2832 
2833     if(NOT EqualString(name, "pgroup"))
2834 	return;
2835 
2836 #if WORKSPACE_PAGES
2837     this->parseState.node->addToGroup(value, theSymbolManager->getSymbol(PROCESS_GROUP));
2838 #else
2839     this->parseState.node->addToGroup(value);
2840 #endif
2841 }
2842 
2843 extern "C"
ParseIntAttribute(char * name,int value)2844 void ParseIntAttribute(char* name, int value)
2845 {
2846     ASSERT(Network::ParseState::network);
2847     Network::ParseState::network->parseIntAttribute(name, value);
2848 }
2849 
parseIntAttribute(char * name,int value)2850 void Network::parseIntAttribute(char* name, int value)
2851 {
2852     if (!this->parseState.node || this->parseState.stop_parsing)
2853 	return;
2854     //
2855     // Determine if this should be associated with an output
2856     if (this->parseState.node != NULL && this->parseState.output_index > 0)
2857     {
2858 	if (EqualString("cache", name))
2859 	{
2860 	    switch (value) {
2861 	    case 0:
2862 		this->parseState.node->setOutputCacheability(
2863 				this->parseState.output_index,
2864 				ModuleNotCached);
2865 		break;
2866 	    case 1:
2867 		this->parseState.node->setOutputCacheability(
2868 				this->parseState.output_index,
2869 				ModuleFullyCached);
2870 		break;
2871 	    case 2:
2872 		this->parseState.node->setOutputCacheability(
2873 				this->parseState.output_index,
2874 				ModuleCacheOnce);
2875 		break;
2876 	    }
2877 	}
2878     }
2879     //
2880     // associate with the node
2881     else if ((this->parseState.node != NULL) &&
2882 	     (this->parseState.parse_state == _PARSED_NODE))
2883     {
2884 	if (EqualString("cache", name))
2885 	{
2886 	    switch (value) {
2887 	    case 0:
2888 		this->parseState.node->setNodeCacheability( ModuleNotCached);
2889 		break;
2890 	    case 1:
2891 		this->parseState.node->setNodeCacheability( ModuleFullyCached);
2892 		break;
2893 	    case 2:
2894 		this->parseState.node->setNodeCacheability( ModuleCacheOnce);
2895 		break;
2896 	    }
2897 	}
2898     }
2899 }
2900 
2901 
2902 /*****************************************************************************/
2903 /* uinParseRValue -							     */
2904 /*                                                                           */
2905 /*                                                                           */
2906 /*****************************************************************************/
2907 
2908 extern "C"
ParseRValue(char * name)2909 void ParseRValue(char* name)
2910 {
2911     ASSERT(Network::ParseState::network);
2912     Network::ParseState::network->parseRValue(name);
2913 }
2914 
parseRValue(char * name)2915 void Network::parseRValue(char* name)
2916 {
2917     int        parsed_items;
2918     int        instance;
2919     int        parameter;
2920     char       type[128];
2921     char       string[256];
2922     char       macro[256];
2923     boolean	parse_error = FALSE;
2924 
2925     if (!this->parseState.node || this->parseState.stop_parsing)
2926 	return;
2927 
2928     ASSERT(name);
2929 
2930     /*
2931      * Suppress further processing if first macro has already been
2932      * parsed.
2933      */
2934     if (this->parseState.main_macro_parsed)
2935 	return;
2936 
2937 // cout << "ParseRValue: " << name << "\n";
2938 // cout.flush();
2939 
2940 
2941     /*
2942      * Scan the name for components.
2943      */
2944     parsed_items =
2945 	sscanf(name,
2946 	       "%[^_]_%[^_]_%d_%[^_]_%d",
2947 	       macro,
2948 	       string,
2949 	       &instance,
2950 	       type,
2951 	       &parameter);
2952 
2953     if (parsed_items != 5)  {
2954 	/*
2955 	 * If parse failed...try the old (pre 2.0) style
2956 	 */
2957 	parsed_items =
2958 	    sscanf(name,
2959 		   "%[^_]_%d_%[^_]_%d",
2960 		   string,
2961 		   &instance,
2962 		   type,
2963 		   &parameter);
2964 
2965 	if (parsed_items != 4)
2966 	    parse_error = TRUE;
2967     } else if (!EqualString(macro, this->getNameString())) {
2968 	parse_error = TRUE;
2969     }
2970 
2971     if (parse_error || !EqualString(type, "out"))
2972 	return;
2973 
2974     Node *n;
2975     boolean found = FALSE;
2976     Symbol s_of_out = theSymbolManager->registerSymbol(string);
2977 #if 00
2978     ListIterator l;
2979     FOR_EACH_NETWORK_NODE(this, n, l)
2980     {
2981 	if (n->getNameSymbol() == s_of_out &&
2982 	    n->getInstanceNumber() == instance)
2983 #else
2984 	if ( (n = this->findNode(s_of_out, instance)) )
2985 #endif
2986 	{
2987 	    if (n->getOutputCount() < parameter)
2988 		ErrorMessage("Cannot connect output %d of %s to %s, "
2989 			  "too many outputs (in %s, line %d)",
2990 			  parameter, string,
2991 			  this->parseState.node->getNameString(),
2992 			  this->parseState.parse_file, yylineno);
2993 	    else if (this->parseState.node->getInputCount() < 1)
2994 		ErrorMessage("Cannot connect input %d of %s to %s, "
2995 			  "too many inputs (in %s, line %d)",
2996 			  this->parseState.input_index,
2997 			  this->parseState.node->getNameString(),
2998 			  string,
2999 			  this->parseState.parse_file, yylineno);
3000 	    else
3001 	    {
3002 		// Connect output parameter to input of this->parseState.node
3003 		new Ark(n, parameter,
3004 			this->parseState.node, 1);
3005 		this->parseState.node->setInputVisibility(1,
3006 						TRUE);
3007 		n->setOutputVisibility(parameter,TRUE);
3008 	    }
3009 	    found = TRUE;
3010 #if 00
3011 	    break;
3012 	}
3013 #endif
3014     }
3015     if (!found && !this->parseState.ignoreUndefinedModules)
3016     {
3017 	this->parseState.undefined_modules->addDefinition(string, NULL);
3018 	this->parseState.error_occurred = TRUE;
3019 	return;
3020     }
3021 }
3022 
3023 
3024 /*****************************************************************************/
3025 /* uinParseEndOfMacroDefinition -					     */
3026 /*                                                                           */
3027 /*                                                                           */
3028 /*****************************************************************************/
3029 
3030 extern "C"
ParseEndOfMacroDefinition()3031 void ParseEndOfMacroDefinition()
3032 {
3033     ASSERT(Network::ParseState::network);
3034     Network::ParseState::network->parseEndOfMacroDefinition();
3035 }
3036 
parseEndOfMacroDefinition()3037 void Network::parseEndOfMacroDefinition()
3038 {
3039     if (this->parseState.stop_parsing)
3040 	return;
3041     this->parseState.main_macro_parsed = TRUE;
3042 }
3043 
3044 
3045 /*****************************************************************************/
3046 /* yyerror -								     */
3047 /*                                                                           */
3048 /* Parser error routine.                                                     */
3049 /*                                                                           */
3050 /*****************************************************************************/
3051 
3052 extern "C"
yyerror(char *,...)3053 void yyerror(char* , ...)
3054 {
3055     ErrorMessage("Syntax error encountered (%s file, line %d).",
3056 	    Network::ParseState::network->parseState.parse_file, yylineno);
3057     Network::ParseState::network->parseState.error_occurred = TRUE;
3058 }
3059 
3060 //
3061 // Static method that will...
3062 // Build a network (.net) filename (handling semantics of file extension)
3063 // from the given name.  If the given name does not have the required
3064 // extension, then add one.
3065 //
3066 // A newly allocated string is always returned containing the appropriate name.
3067 //
FilenameToNetname(const char * filename)3068 char *Network::FilenameToNetname(const char *filename)
3069 {
3070     const char *ext;
3071     char *file;
3072     int flen = STRLEN(filename);
3073     int len = STRLEN(NetExtension);
3074 
3075     file = new char[flen + len + 1];
3076     strcpy(file, filename);
3077 
3078     //
3079     // Build/add the extension
3080     //
3081 #ifdef DXD_OS_NON_UNIX    //SMH cover upper case extensions
3082     ext = strrstr(file, (char *)NetExtensionUpper);
3083     if (ext) return file;
3084 #endif
3085     ext = strrstr(file, (char *)NetExtension);
3086     if (!ext || (STRLEN(ext) != len))
3087 	strcat(file,NetExtension);
3088 
3089     ASSERT((flen + len + 1) > strlen(file));
3090     return file;
3091 }
3092 //
3093 // Static method that will...
3094 // Build a config (.cfg) filename (handling semantics of file extension)
3095 // from the given name.  If the given name does not have the required
3096 // extension, then add one.
3097 //
3098 // A newly allocated string is always returned containing the appropriate name.
3099 //
FilenameToCfgname(const char * filename)3100 char *Network::FilenameToCfgname(const char *filename)
3101 {
3102     const char *ext;
3103     char *file;
3104     int len = STRLEN(CfgExtension);
3105 
3106     file = new char[STRLEN(filename) + len + 1];
3107     strcpy(file, filename);
3108 
3109     //
3110     // Build/add the extension
3111     //
3112 #ifdef DXD_OS_NON_UNIX    //SMH cover upper case extensions
3113     ext = strrstr(file, (char *)CfgExtensionUpper);
3114     if (ext) return file;
3115 #endif
3116 
3117 #if 0
3118     //
3119     // Remove the .net extension if present
3120     // FIXME
3121     // This code was placed here ifdef-ed out.  We want the code in, but it's left
3122     // out only because of nearness of release date.  When this chunk is enabled,
3123     // go to SaveCFGDialog.C and remove what should look like a dup of this chunk.
3124     //
3125     const char *netext = strrstr(file, (char *)NetExtension);
3126     int netExtLen = STRLEN(NetExtension);
3127     if ((netext) && (STRLEN(netext) == netExtLen)) {
3128 	int filelen = STRLEN(file);
3129 	file[filelen-netExtLen] = '\0';
3130     }
3131 #endif
3132 
3133     ext = strrstr(file, (char *)CfgExtension);
3134     if (!ext || (STRLEN(ext) != len)) {
3135 	strcat(file,CfgExtension);
3136     }
3137 
3138     return file;
3139 }
3140 
3141 //
3142 // Determine if the network is in a state that can be saved to disk.
3143 // If so, then return TRUE, otherwise return FALSE and issue an error dialog.
3144 //
isNetworkSavable()3145 boolean Network::isNetworkSavable()
3146 {
3147     if (this->isMacro() && EqualString(this->getNameString(),DEFAULT_MAIN_NAME))
3148     {
3149 	ErrorMessage("Macros must have a name other than '%s'.\n"
3150 		     "To change the name, use the Macro Name option\n"
3151 		     "available in the Edit menu.",
3152 					DEFAULT_MAIN_NAME);
3153 	return FALSE;
3154     }
3155     return TRUE;
3156 }
3157 
3158 
saveNetwork(const char * name,boolean force)3159 boolean Network::saveNetwork(const char *name, boolean force)
3160 {
3161     char *ext, *buf;
3162 
3163 
3164     if (!this->isNetworkSavable() && !force)
3165 	return FALSE;
3166 
3167     buf = DuplicateString(name);
3168     ext = (char*)strrstr(buf,(char *)NetExtension);
3169     if (!ext)
3170 	ext = (char*)strrstr(buf,(char *)CfgExtension);
3171     if (ext)
3172 	*ext = '\0';
3173 
3174     char *fname = this->fileName;
3175     char *fullName = new char[STRLEN(buf) + STRLEN(NetExtension) + 1];
3176     strcpy(fullName, buf);
3177     strcat(fullName, NetExtension);
3178 
3179     //
3180     // Version checking will return control here after the user has responded
3181     // to a question dialog if it's necessary to ask her a question.
3182     // If fullName doesn't exist there can't be a version mismatch.
3183     //
3184     if (!this->versionMismatchQuery (TRUE, fullName))
3185 	return FALSE;
3186 
3187     this->fileName = fullName;
3188 
3189     //
3190     // Change MacroDefinition's file name.
3191     //
3192     MacroDefinition *md = this->getDefinition();
3193     if (md)
3194         md->setFileName(fullName);
3195 
3196     boolean ret =  this->netPrintNetwork(buf) &&
3197 	           this->cfgPrintNetwork(buf) &&
3198 	           this->auxPrintNetwork();
3199 
3200     if (theDXApplication->dxlAppNotifySaveNet())
3201     {
3202         ApplicIF *applic = theDXApplication->getAppConnection();
3203         if (applic)
3204         {
3205             char *buf = new char [strlen("savednet ") +
3206                                         strlen(this->fileName) + 1];
3207             strcpy(buf, "savednet ");
3208             strcat(buf, this->fileName);
3209 
3210             applic->send(PacketIF::SYSTEM, buf);
3211         }
3212     }
3213 
3214     if (ret)
3215     {
3216 	if (fname)
3217 	    delete fname;
3218 	//
3219 	// Activate these now that the user has give the net a name.
3220 	//
3221 	if (theDXApplication->appAllowsSavingNetFile(this))
3222 	    this->saveCmd->activate();
3223 	if (theDXApplication->appAllowsSavingCfgFile())
3224 	    if (this->saveCfgCmd) this->saveCfgCmd->activate();
3225 	if (this->openCfgCmd) this->openCfgCmd->activate();
3226         this->resetWindowTitles();
3227         this->clearFileDirty();
3228 
3229 	//
3230 	// Change the version info in the current net now that saving has
3231 	// succeeded.
3232 	//
3233 	this->dxVersion.major = DX_MAJOR_VERSION;
3234 	this->dxVersion.minor = DX_MINOR_VERSION;
3235 	this->dxVersion.micro = DX_MICRO_VERSION;
3236 	this->netVersion.major = NETFILE_MAJOR_VERSION;;
3237 	this->netVersion.minor = NETFILE_MINOR_VERSION;;
3238 	this->netVersion.micro = NETFILE_MICRO_VERSION;;
3239 
3240 	//
3241 	// The editor may have something to do if the network is clean.
3242 	// Clearing the undo stack, perhaps?
3243 	//
3244 	if (this->editor) {
3245 	    this->editor->notifySaved();
3246 	}
3247 	theDXApplication->appendReferencedFile(this->fileName);
3248     }
3249     else
3250     {
3251 	delete fullName;
3252 	this->fileName = fname;
3253     }
3254 
3255 
3256     delete buf;
3257 
3258 
3259     return ret;
3260 }
3261 
openCfgFile(const char * name,boolean openStartup,boolean send)3262 boolean Network::openCfgFile(const char *name,
3263 				boolean openStartup, boolean send)
3264 {
3265     char *cfgfile;
3266     boolean ret;
3267     FILE *f;
3268 
3269     if (this->isMacro())
3270 	return TRUE;
3271 
3272     cfgfile = Network::FilenameToCfgname(name);
3273 
3274     f = fopen (cfgfile, "r");
3275     if (f != NULL)  {
3276     	this->clearCfgInformation();
3277 #ifdef NoParseState
3278         _parse_mode = _PARSE_CONFIGURATION;
3279         _parse_file = cfgfile;
3280 #else
3281 	this->parseState.initializeForParse(this,_PARSE_CONFIGURATION,cfgfile);
3282 #endif
3283         this->readingNetwork = TRUE;
3284         boolean stopped_parsing = this->parse(f);
3285 	if (openStartup)
3286 	    this->openControlPanel(-1);
3287 	if (send)
3288 	    this->sendValues(FALSE);
3289 	ret = !stopped_parsing;
3290         this->readingNetwork = FALSE;
3291 #ifdef NoParseState
3292 #else
3293 	this->parseState.cleanupAfterParse();
3294 #endif
3295     }
3296     else {
3297 	ret = FALSE;
3298     }
3299 
3300     if (f) fclose(f);
3301     delete cfgfile;
3302 
3303     return ret;
3304 }
3305 
3306 
saveCfgFile(const char * name)3307 boolean Network::saveCfgFile(const char *name)
3308 {
3309     return this->cfgPrintNetwork(name);
3310 
3311 }
3312 
3313 //
3314 // Print the .net portion of a network to a file with the given name.
3315 // The extension used is NetExtension, and will be added if not present in
3316 // the filename.
3317 //
netPrintNetwork(const char * filename)3318 boolean Network::netPrintNetwork(const char *filename)
3319 {
3320     char *file, *tmpfile, *netfile;
3321     FILE *f;
3322     boolean ret;
3323 
3324     netfile = Network::FilenameToNetname(filename);
3325 #if HAS_RENAME
3326     file = tmpfile = UniqueFilename(netfile);
3327     if (!file) {
3328 	file = netfile;
3329 # define WRITE_PERM_FIX 1
3330 # ifdef  WRITE_PERM_FIX
3331     } else {
3332 	//
3333 	// Make sure we can open the netfile for write.  rename() seems to
3334  	// allow us to overright 444 files if the directory is writable.
3335 	// FIXME: should we do this .cm files?
3336 	//
3337 #ifdef DXD_WIN
3338 	f = fopen(netfile,"a+");
3339 #else
3340 	f = fopen(netfile,"a");
3341 #endif
3342 	if (!f) {
3343 	    ErrorMessage("Can not open file %s for writing", netfile);
3344 	    ret = FALSE;
3345 	    goto out;
3346 	}
3347 	fclose(f);
3348 #if defined(OS2) || defined(DXD_WIN)  // otherwise rename later would fail since file exists
3349         unlink(netfile);
3350 #endif
3351 # endif // WRITE_PERM_FIX
3352     }
3353 #else
3354     tmpfile = NULL;
3355     file = netfile;
3356 #endif
3357 
3358     f = fopen (file, "w");
3359 
3360     if (f == NULL)  {
3361         ErrorMessage("Can not open file %s for writing", netfile);
3362 	ret = FALSE;
3363     } else if (this->printNetwork(f, PrintFile) != TRUE) {
3364         ErrorMessage("Error writing file %s",netfile);
3365         fclose(f);
3366 	unlink(file);
3367 	ret = FALSE;
3368     } else  {
3369         fclose(f);
3370 	ret = TRUE;
3371 #if HAS_RENAME
3372 	if (tmpfile) {
3373 	    rename(tmpfile,netfile);
3374 	}
3375 #endif	// HAS_RENAME
3376     }
3377 
3378 #if HAS_RENAME
3379 out:
3380 #endif
3381     if (netfile) delete netfile;
3382     if (tmpfile) delete tmpfile;
3383 
3384     return ret;
3385 }
3386 //
3387 // Print the .cfg portion of a network to a file with the given name.
3388 // The extension used is found in CfgExtension, and will be added if not
3389 // present in the filename.
3390 //
cfgPrintNetwork(const char * filename,PrintType dest)3391 boolean Network::cfgPrintNetwork(const char *filename, PrintType dest)
3392 {
3393     char *file, *tmpfile, *cfgfile;
3394     FILE *f = NULL;
3395     boolean ret, rmfile = TRUE;
3396 
3397     cfgfile = Network::FilenameToCfgname(filename);
3398 
3399     if (this->isMacro()) {
3400 	unlink(cfgfile);
3401 	tmpfile = NULL;
3402 	ret = TRUE;
3403 	goto out;
3404     }
3405 
3406 #if HAS_RENAME
3407     file = tmpfile = UniqueFilename(cfgfile);
3408     if (!file) {
3409 	file = cfgfile;
3410 # define WRITE_PERM_FIX 1
3411 # ifdef  WRITE_PERM_FIX
3412     } else {
3413         //
3414         // Make sure we can open the cfgfile for write.  rename() seems to
3415         // allow us to overright 444 files if the directory is writable.
3416         //
3417 #ifdef DXD_WIN
3418         f = fopen(cfgfile,"a+");
3419 #else
3420         f = fopen(cfgfile,"a");
3421 #endif
3422         if (!f) {
3423             ErrorMessage("Can not open file %s for writing", cfgfile);
3424             ret = FALSE;
3425             goto out;
3426         }
3427         fclose(f);
3428 #if defined(OS2) || defined(DXD_WIN)                // otherwise rename later would fail since file exists
3429         unlink(cfgfile);
3430 #endif
3431 # endif // WRITE_PERM_FIX
3432     }
3433 #else
3434     tmpfile = NULL;
3435     file = cfgfile;
3436 #endif	// HAS_RENAME
3437 
3438     f = fopen (file, "w");
3439 
3440     ret = TRUE;
3441     if (f == NULL)  {
3442         ErrorMessage("Can not open file %s for writing", file);
3443 	ret = FALSE;
3444     } else {
3445 	Node *n;
3446 	ControlPanel *cp;
3447 	ListIterator l;
3448 	time_t t;
3449 	long int fsize;
3450 
3451 	t = time((time_t*) 0);
3452 
3453 	//
3454   	// Demarcates the beginning of the network cfg comments.
3455 	//
3456 	if (fprintf(f, "//\n// time: %s//\n", ctime(&t)) < 0) {
3457 	    ret = FALSE;
3458 	    goto write_failed;
3459 	}
3460 
3461 	if (fprintf(f,
3462 #ifdef BETA_VERSION
3463 		"// version: %d.%d.%d (format), %d.%d.%d (DX Beta)\n//\n",
3464 #else
3465 		"// version: %d.%d.%d (format), %d.%d.%d (DX)\n//\n",
3466 #endif
3467 			NETFILE_MAJOR_VERSION,
3468 			NETFILE_MINOR_VERSION,
3469 			NETFILE_MICRO_VERSION,
3470 			DX_MAJOR_VERSION,
3471 			DX_MINOR_VERSION,
3472 			DX_MICRO_VERSION) < 0) {
3473 	    ret = FALSE;
3474 	    goto write_failed;
3475 	}
3476 
3477 	//
3478 	// Get the current size of the file. If does not change with next
3479 	// few operations, then unlink it later.
3480 	//
3481 	fflush(f);
3482 	fsize = ftell(f);
3483 
3484 	//
3485 	// Ask the application to print any relevant comments first.
3486 	//
3487 	if(dest == PrintExec || dest == PrintFile) {
3488 	    if (!this->isMacro() && !theDXApplication->printComment(f)) {
3489 		ret = FALSE;
3490 		goto write_failed;
3491 	    }
3492 	}
3493 	//
3494 	// Then the panel group and acess information.
3495 	//
3496 	if (!this->panelGroupManager->cfgPrintComment(f) ||
3497 	    !this->panelAccessManager->cfgPrintInaccessibleComment(f)) {
3498 	    ret = FALSE;
3499 	    goto write_failed;
3500 	}
3501 
3502 
3503 #define FIX_LLOYDT96 1
3504 #if defined(FIX_LLOYDT96)
3505 	//
3506 	// PrintCut is dnd on nodes in the vpe
3507 	//    I think you want to avoid all cfg info because you don't
3508 	//    want any new panels. ???
3509 	// PrintCPBuffer is dnd within a control panel.
3510 	//    Certainly need whatever cfg info there is, but only on
3511 	//    selected things.
3512 	// (If you drag from a vpe to a panel, then it's not writing a file.)
3513 	//
3514 	if (dest==PrintCut)
3515 	{
3516 	}
3517 	else if (dest==PrintCPBuffer)
3518 #else
3519 	if (dest==PrintCPBuffer)
3520 #endif
3521 	{
3522 	    ControlPanel *ownerCp = this->selectionOwner;
3523 	    if (!(ownerCp->cfgPrintPanel(f, PrintCPBuffer))) {
3524 		ret = FALSE;
3525 		goto write_failed;
3526 	    }
3527 
3528 	    //
3529 	    // don't really want to loop over all nodes in network.
3530 	    // Really just want all nodes referenced by instanceList
3531 	    // of ownerCp.
3532 	    //
3533 	    FOR_EACH_NETWORK_NODE(this, n, l) {
3534 		if (ownerCp->nodeIsInInstanceList (n)) {
3535 		    if (!n->cfgPrintNode(f, dest)) {
3536 			ret = FALSE;
3537 			goto write_failed;
3538 		    }
3539 		}
3540 	    }
3541 	}
3542 	else
3543 	{
3544 	    FOR_EACH_NETWORK_PANEL(this, cp, l) {
3545 		if (!cp->cfgPrintPanel(f)) {
3546 		    ret = FALSE;
3547 		    goto write_failed;
3548 		}
3549 	    }
3550 	    FOR_EACH_NETWORK_NODE(this, n, l) {
3551 		boolean selected = FALSE;
3552 		if ((n->getStandIn()) && (n->getStandIn()->isSelected()))
3553 		    selected = TRUE;
3554 		if(dest == PrintCut && selected ||
3555 		    (dest == PrintCPBuffer && selected) ||
3556 		    dest == PrintExec || dest == PrintFile) {
3557 		    if (!n->cfgPrintNode(f, dest)) {
3558 			ret = FALSE;
3559 			goto write_failed;
3560 		    }
3561 		}
3562 	    }
3563 	}
3564 
3565 	//
3566 	// Check to see if the above wrote anything to the file.
3567 	// If not, then we don't need to keep it.
3568 	//
3569 	fflush(f);
3570 	if (ftell(f) != fsize)
3571 	    rmfile = FALSE;
3572     }
3573 
3574 write_failed:
3575     if (f) {
3576         fclose(f);
3577 	if (!ret) {
3578 	    ErrorMessage("Error writing file %s",cfgfile);
3579 	} else {
3580 	    ASSERT(cfgfile);
3581 	    if (rmfile) {
3582 		unlink(cfgfile);
3583 		if (tmpfile)
3584 		    unlink(tmpfile);
3585 	    }
3586 #if HAS_RENAME
3587 	    else if (tmpfile)
3588 		rename(tmpfile, cfgfile);
3589 #endif	// HAS_RENAME
3590 	}
3591     }
3592 
3593 out:
3594     if (cfgfile) delete cfgfile;
3595     if (tmpfile) delete tmpfile;
3596 
3597     return ret;
3598 }
3599 //
3600 // Print any files that are created on a per node basis.
3601 //
auxPrintNetwork()3602 boolean Network::auxPrintNetwork()
3603 {
3604     boolean ret = TRUE;
3605     Node *n;
3606     ListIterator l;
3607 
3608     FOR_EACH_NETWORK_NODE(this, n, l) {
3609 	if (!n->auxPrintNodeFile()) {
3610 	    // Nodes are expected to indicate any errors that occur.
3611 	    ret = FALSE;
3612 	}
3613     }
3614 
3615     return ret;
3616 }
3617 
printNetwork(FILE * f,PrintType dest)3618 boolean Network::printNetwork(FILE *f, PrintType dest)
3619 {
3620     if (!this->printHeader(f, dest))
3621 	return FALSE;
3622     if (!this->printBody(f, dest))
3623 	return FALSE;
3624     if (!this->printTrailer(f, dest))
3625 	return FALSE;
3626     if (!this->printValues(f, dest))
3627 	return FALSE;
3628 
3629 #if WORKSPACE_PAGES
3630     //
3631     // Process group info is only stored in a network if this is the main network.
3632     //
3633     if((dest == PrintFile)||(dest == PrintExec)) {
3634 	DictionaryIterator di(*this->groupManagers);
3635 	GroupManager *gmgr;
3636 	while ( (gmgr = (GroupManager*)di.getNextDefinition()) ) {
3637 	    if (!gmgr->printAssignment(f))
3638 		return FALSE;
3639 	}
3640     }
3641 #endif
3642     if (!this->isMacro())
3643     {
3644 #if WORKSPACE_PAGES
3645 #else
3646 	if((dest == PrintFile)||(dest == PrintExec))
3647 	    if (!theDXApplication->PGManager->printAssignment(f))
3648 		return FALSE;
3649 #endif
3650 
3651 	if (! theDXApplication->dxlAppNoNetworkExecute())
3652 	{
3653 
3654 	    if (fprintf(f, "Executive(\"product version %d %d %d\");\n"
3655 			"$sync\n",
3656 			DX_MAJOR_VERSION,
3657 			DX_MINOR_VERSION,
3658 			DX_MICRO_VERSION) < 0)
3659 		return FALSE;
3660 
3661 	//
3662 	// Don't print the stuff that causes execution of this is a DXLink
3663 	// program, as it may used in DXLLoadVisualProgram() or
3664 	// exDXLLoadScript() which would cause executions when talking to
3665 	// the executive.
3666 	// FIXME: The Node's should be telling us if this is a DXLink program.
3667 	//
3668 	    char *comment;
3669 	    if (this->containsClassOfNode(ClassDXLInputNode) ||
3670 		this->containsClassOfNode(ClassDXLOutputNode))  {
3671 		if(fprintf(f,
3672 "// This network contains DXLink tools.  Therefore, the following line(s)\n"
3673 "// that would cause an execution when run in script mode have been \n"
3674 "// commented out.  This will facilitate the use of the DXLink routines\n"
3675 "// exDXLLoadScript() and DXLLoadVisualProgram() when the DXLink\n"
3676 "// application is connected to an executive.\n") < 0)
3677 		    return FALSE;
3678 		comment = "// ";
3679 	    } else
3680 		comment = "";
3681 
3682 	    if (this->sequencer)
3683 	    {
3684 		if ((fprintf(f, "%s\nsequence %s();\n", comment,
3685 				this->getNameString()) < 0) ||
3686 		    (fprintf(f, "%splay;\n",comment) < 0))
3687 		    return FALSE;
3688 	    }
3689 	    else if (fprintf(f, "%s%s();\n", comment,this->getNameString()) < 0)
3690 		return FALSE;
3691 	}
3692     }
3693 
3694     return TRUE;
3695 }
3696 
printHeader(FILE * f,PrintType dest,PacketIFCallback echoCallback,void * echoClientData)3697 boolean Network::printHeader(FILE *f,
3698 			     PrintType dest,
3699 			     PacketIFCallback echoCallback,
3700 				 void *echoClientData)
3701 {
3702 	DXPacketIF *pif = theDXApplication->getPacketIF();
3703 	char s[1000];
3704 	if (dest == PrintFile || dest == PrintCut || dest == PrintCPBuffer)
3705 	{
3706 		SPRINTF(s, "//\n");
3707 		if (fputs(s, f) < 0) return FALSE;
3708 		if (echoCallback)
3709 			(*echoCallback)(echoClientData, s);
3710 		time_t t = time((time_t*)NULL);
3711 		SPRINTF(s, "// time: %s", ctime(&t));
3712 		if (fputs(s, f) < 0) return FALSE;
3713 		if (echoCallback)
3714 			(*echoCallback)(echoClientData, s);
3715 		SPRINTF(s, "//\n");
3716 		if (fputs(s, f) < 0) return FALSE;
3717 		if (echoCallback)
3718 			(*echoCallback)(echoClientData, s);
3719 		SPRINTF(s,
3720 #ifdef BETA_VERSION
3721 			"// version: %d.%d.%d (format), %d.%d.%d (DX Beta)\n//\n",
3722 #else
3723 			"// version: %d.%d.%d (format), %d.%d.%d (DX)\n//\n",
3724 #endif
3725 			NETFILE_MAJOR_VERSION,
3726 			NETFILE_MINOR_VERSION,
3727 			NETFILE_MICRO_VERSION,
3728 			DX_MAJOR_VERSION,
3729 			DX_MINOR_VERSION,
3730 			DX_MICRO_VERSION);
3731 		if (fputs(s, f) < 0) return FALSE;
3732 		if (echoCallback)
3733 			(*echoCallback)(echoClientData, s);
3734 		SPRINTF(s, "//\n");
3735 		if (fputs(s, f) < 0) return FALSE;
3736 		if (echoCallback)
3737 			(*echoCallback)(echoClientData, s);
3738 
3739 		//
3740 		// Print the referenced
3741 		//
3742 		int inline_define = FALSE;
3743 #ifdef DEBUG
3744 		if (getenv("DXINLINE"))
3745 			inline_define = TRUE;
3746 #endif
3747 		if ((dest == PrintFile) &&
3748 			!this->printMacroReferences(f, inline_define,
3749 			echoCallback,echoClientData))
3750 			return FALSE;
3751 
3752 		if (this->isMacro())
3753 		{
3754 			SPRINTF(s, "// Begin MDF\n");
3755 			if (fputs(s, f) < 0) return FALSE;
3756 			if (echoCallback)
3757 				(*echoCallback)(echoClientData, s);
3758 		}
3759 
3760 		SPRINTF(s, "// MODULE %s\n", theSymbolManager->getSymbolString(this->name));
3761 		if (fputs(s, f) < 0) return FALSE;
3762 		if (echoCallback)
3763 			(*echoCallback)(echoClientData, s);
3764 		if (this->category)
3765 		{
3766 			SPRINTF(s, "// CATEGORY %s\n", this->getCategoryString());
3767 			if (fputs(s, f) < 0) return FALSE;
3768 			if (echoCallback)
3769 				(*echoCallback)(echoClientData, s);
3770 		}
3771 		if (this->description && STRLEN(this->description) > 0)
3772 		{
3773 			SPRINTF(s, "// DESCRIPTION %s\n",
3774 				this->getDescriptionString() ? this->getDescriptionString() : " ");
3775 			if (fputs(s, f) < 0) return FALSE;
3776 			if (echoCallback)
3777 				(*echoCallback)(echoClientData, s);
3778 		}
3779 		if (this->isMacro())
3780 		{
3781 			int i;
3782 			for (i = 1; i <= this->getInputCount(); ++i)
3783 			{
3784 				ParameterDefinition *pd = this->getInputDefinition(i);
3785 				{
3786 					const char * const *strings = pd->getTypeStrings();
3787 					const char *visattr;
3788 					int length = 0;
3789 					int j;
3790 					for (j = 0; strings[j] != NULL; ++j)
3791 						length += STRLEN(strings[j]) + 5;
3792 					char *types = new char[length];
3793 					strcpy(types, strings[0]);
3794 					for (j = 1; strings[j] != NULL; ++j)
3795 					{
3796 						strcat(types, " or ");
3797 						strcat(types, strings[j]);
3798 					}
3799 
3800 					const char *dflt = pd->getDefaultValue();
3801 					if (pd->isRequired())
3802 						dflt = "(none)";
3803 					else if (!dflt || (*dflt == '\0') ||
3804 						EqualString(dflt,"NULL"))
3805 						dflt = "(no default)";
3806 					if (!pd->isViewable()) {
3807 						visattr="[visible:2]";
3808 					} else {
3809 						if (pd->getDefaultVisibility())
3810 							visattr="";
3811 						else
3812 							visattr="[visible:0]";
3813 					}
3814 					SPRINTF(s, "// INPUT %s%s; %s; %s; %s\n",
3815 						pd->getNameString(),
3816 						visattr,
3817 						types,
3818 						dflt? dflt: "(no default)",
3819 						pd->getDescription() ? pd->getDescription() : " ");
3820 					delete types;
3821 					if (fputs(s, f) < 0) return FALSE;
3822 					if (echoCallback)
3823 						(*echoCallback)(echoClientData, s);
3824 
3825 					// If the input parameter has option values...
3826 					const char *const *options = pd->getValueOptions();
3827 					if (options && options[0]) {
3828 						int option_count = 0;
3829 						while (options[option_count]) option_count++;
3830 						strcpy (s, "// OPTIONS");
3831 						int slen = strlen(s);
3832 						int one_less = option_count - 1;
3833 						for (int i=0; i<one_less; i++) {
3834 							SPRINTF (&s[slen], " %s ;", options[i]);
3835 							slen+= strlen(options[i]) + 3;
3836 							option_count++;
3837 						}
3838 						SPRINTF (&s[slen], " %s\n", options[one_less]);
3839 						if (fputs(s, f) < 0) return FALSE;
3840 						if (echoCallback)
3841 							(*echoCallback)(echoClientData, s);
3842 					}
3843 				}
3844 			}
3845 			for (i = 1; i <= this->getOutputCount(); ++i)
3846 			{
3847 				ParameterDefinition *pd = this->getOutputDefinition(i);
3848 				{
3849 					const char * const *strings = pd->getTypeStrings();
3850 					const char *visattr;
3851 					int length = 0;
3852 					int j;
3853 					for (j = 0; strings[j] != NULL; ++j)
3854 						length += STRLEN(strings[j]) + 5;
3855 					char *types = new char[length];
3856 					strcpy(types, strings[0]);
3857 					for (j = 1; strings[j] != NULL; ++j)
3858 					{
3859 						strcat(types, " or ");
3860 						strcat(types, strings[j]);
3861 					}
3862 
3863 					if (!pd->isViewable()) {
3864 						visattr="[visible:2]";
3865 					} else {
3866 						if (pd->getDefaultVisibility())
3867 							visattr="";
3868 						else
3869 							visattr="[visible:0]";
3870 					}
3871 					SPRINTF(s, "// OUTPUT %s%s; %s; %s\n",
3872 						pd->getNameString(),
3873 						visattr,
3874 						types,
3875 						pd->getDescription() ? pd->getDescription() : " ");
3876 					delete types;
3877 				}
3878 				if (fputs(s, f) < 0) return FALSE;
3879 				if (echoCallback)
3880 					(*echoCallback)(echoClientData, s);
3881 			}
3882 			SPRINTF(s, "// End MDF\n");
3883 			if (fputs(s, f) < 0) return FALSE;
3884 			if (echoCallback)
3885 				(*echoCallback)(echoClientData, s);
3886 		}
3887 		//
3888 		// Print comments
3889 		// FIXME: do we care that annotated stuff does not go through
3890 		//	the echoCallback?
3891 		//
3892 		if (this->comment) {
3893 			if (fprintf(f,"//\n// comment: ") < 0)
3894 				return FALSE;
3895 			int i, len=STRLEN(this->comment);
3896 			for (i=0 ; i<len ; i++) {
3897 				char c = this->comment[i];
3898 				if (putc(c, f) == EOF)
3899 					return FALSE;
3900 				if ((c == '\n') && (i+1 != len)) {
3901 					if (fprintf(f,"// comment: ") < 0)
3902 						return FALSE;
3903 				}
3904 			}
3905 			if (fprintf(f,"\n") < 0)
3906 				return FALSE;
3907 		}
3908 
3909 #if WORKSPACE_PAGES
3910 		// Print all the group assignments.
3911 		// Handle the process group specially
3912 		// FIXME: do we care that annotated stuff does not go through
3913 		//	the echoCallback?
3914 		//
3915 		DictionaryIterator di(*this->groupManagers);
3916 		GroupManager *gmgr;
3917 		Symbol psym = theSymbolManager->getSymbol(PROCESS_GROUP);
3918 		while ( (gmgr = (GroupManager*)di.getNextDefinition()) ) {
3919 			if (psym == gmgr->getManagerSymbol()) {
3920 				if ((dest == PrintExec) || (dest == PrintFile))
3921 					if (!this->isMacro())
3922 						if (!gmgr->printComment(f))
3923 							return FALSE;
3924 			} else {
3925 				if (!gmgr->printComment(f))
3926 					return FALSE;
3927 			}
3928 		}
3929 #else
3930 		//
3931 		// Print the process group assignment.
3932 		//
3933 		if ((dest == PrintExec) || (dest == PrintFile))
3934 			if (!this->isMacro() &&
3935 				!theDXApplication->PGManager->printComment(f))
3936 				return FALSE;
3937 #endif
3938 
3939 		//
3940 		// Print workspace information
3941 		//
3942 		this->workSpaceInfo.printComments(f);
3943 		SPRINTF(s, "//\n");
3944 		if (fputs(s, f) < 0) return FALSE;
3945 		if (echoCallback)
3946 			(*echoCallback)(echoClientData, s);
3947 
3948 	}
3949 	//SMH all sprintfs in the remainder of this routine were changed to
3950 	//    remember length of formatted string in variable l
3951 
3952 	int l = SPRINTF(s, "macro %s(\n",
3953 		theSymbolManager->getSymbolString(this->name));
3954 
3955 	if (dest == PrintFile || dest == PrintCut || dest == PrintCPBuffer) {
3956 		if (fputs(s, f) < 0) return FALSE;
3957 		if (echoCallback) (*echoCallback)(echoClientData, s);
3958 	} else {
3959 		ASSERT(dest==PrintExec);
3960 		pif->sendBytes(s);
3961 	}
3962 
3963 	int i;
3964 	for (i = 1; this->isMacro() && i <= this->getInputCount(); ++i)
3965 	{
3966 		ParameterDefinition *param = this->getInputDefinition(i);
3967 		if (param->getNameSymbol() == -1)
3968 			l = SPRINTF(s, "%c%s\n", (i == 1? ' ': ','), "dummy");
3969 		else if (param->isDefaultDescriptive() ||
3970 			param->isRequired() ||
3971 			param->getDefaultValue() == NULL ||
3972 			EqualString(param->getDefaultValue(), "NULL"))
3973 			l = SPRINTF(s, "%c%s\n", (i == 1? ' ': ','), param->getNameString());
3974 		else
3975 			l = SPRINTF(s, "%c%s = %s\n", (i == 1? ' ': ','),
3976 			param->getNameString(), param->getDefaultValue());
3977 		if (dest == PrintFile || dest == PrintCut || dest == PrintCPBuffer) {
3978 			if (fputs(s, f) < 0) return FALSE;
3979 			if (echoCallback) (*echoCallback)(echoClientData, s);
3980 		} else {
3981 			ASSERT(dest==PrintExec);
3982 			pif->sendBytes(s);
3983 		}
3984 	}
3985 	l = SPRINTF(s, ") -> (\n");
3986 
3987 	if (dest == PrintFile || dest == PrintCut || dest == PrintCPBuffer) {
3988 		if (fputs(s, f) < 0) return FALSE;
3989 		if (echoCallback) (*echoCallback)(echoClientData, s);
3990 	} else {
3991 		ASSERT(dest==PrintExec);
3992 		pif->sendBytes(s);
3993 	}
3994 
3995 	for (i = 1; this->isMacro() && i <= this->getOutputCount(); ++i)
3996 	{
3997 		ParameterDefinition *param = this->getOutputDefinition(i);
3998 		if (param->getNameSymbol() == -1)
3999 			l = SPRINTF(s, "%c%s\n", (i == 1? ' ': ','), "dummy");
4000 		else
4001 			l = SPRINTF(s, "%c%s\n", (i == 1? ' ': ','), param->getNameString());
4002 
4003 		if (dest == PrintFile || dest == PrintCut || dest == PrintCPBuffer) {
4004 			if (fputs(s, f) < 0) return FALSE;
4005 			if (echoCallback) (*echoCallback)(echoClientData, s);
4006 		} else {
4007 			ASSERT(dest==PrintExec);
4008 			pif->sendBytes(s);
4009 		}
4010 
4011 	}
4012 	l = SPRINTF(s, ") {\n");
4013 	if (dest == PrintFile || dest == PrintCut || dest == PrintCPBuffer) {
4014 		if (fputs(s, f) < 0) return FALSE;
4015 		if (echoCallback) (*echoCallback)(echoClientData, s);
4016 	} else {
4017 		ASSERT(dest==PrintExec);
4018 		pif->sendBytes(s);
4019 	}
4020 
4021 
4022 	Node *n;
4023 	ListIterator li;
4024 	const char *prefix = this->getPrefix();
4025 	FOR_EACH_NETWORK_NODE(this, n, li)
4026 	{
4027 		if (!n->netPrintBeginningOfMacroNode(f, dest, prefix,
4028 			echoCallback, echoClientData))
4029 			return FALSE;
4030 	}
4031 
4032 	return TRUE;
4033 }
printBody(FILE * f,PrintType dest,PacketIFCallback echoCallback,void * echoClientData)4034 boolean Network::printBody(FILE *f,
4035 			   PrintType dest,
4036 			   PacketIFCallback echoCallback,
4037 			   void *echoClientData)
4038 {
4039     Node *n;
4040     ListIterator l;
4041     const char *prefix;
4042     prefix = this->getPrefix();
4043 
4044     if (this->editor && this->isDirty())
4045 	this->sortNetwork();
4046 
4047     this->resetImageCount();
4048 
4049     FOR_EACH_NETWORK_NODE(this, n, l)
4050     {
4051 	StandIn* si = n->getStandIn();
4052 	if((dest == PrintFile) ||
4053 	   (dest == PrintExec) ||
4054 	   (dest == PrintCPBuffer && (this->selectionOwner->nodeIsInInstanceList(n))) ||
4055 	   (dest == PrintCut && si && si->isSelected()))
4056 	{
4057 	    if (!n->netPrintNode(f, dest, prefix, echoCallback,
4058 				 echoClientData))
4059 		return FALSE;
4060 	}
4061     }
4062 
4063     Decorator *dec;
4064     FOR_EACH_NETWORK_DECORATOR(this, dec, l)
4065     {
4066 	if((dest == PrintFile) ||
4067 	   (dest == PrintCut && dec->isSelected()))
4068 	{
4069 	    if (!dec->printComment (f))
4070 		return FALSE;
4071 	}
4072     }
4073 
4074     return TRUE;
4075 }
printTrailer(FILE * f,PrintType dest,PacketIFCallback echoCallback,void * echoClientData)4076 boolean Network::printTrailer(FILE *f,
4077 			      PrintType dest,
4078 			      PacketIFCallback echoCallback,
4079 			      void *echoClientData)
4080 {
4081     if (dest == PrintFile || dest == PrintCut || dest == PrintCPBuffer)
4082     {
4083         if (fprintf(f, "// network: end of macro body\n") < 0)
4084 	    return FALSE;
4085     }
4086 
4087     Node *n;
4088     ListIterator l;
4089     const char *prefix = this->getPrefix();
4090     FOR_EACH_NETWORK_NODE(this, n, l)
4091     {
4092 	if (!n->netPrintEndOfMacroNode(f, dest, prefix,
4093 					echoCallback, echoClientData))
4094 	    return FALSE;
4095     }
4096 
4097     const char* s = "}\n";
4098     DXPacketIF* pif = theDXApplication->getPacketIF();
4099     if (dest == PrintFile || dest == PrintCut || dest == PrintCPBuffer) {
4100 	if (fputs(s, f) < 0) return FALSE;
4101 	if (echoCallback) (*echoCallback)(echoClientData, (char*)s);
4102     } else {
4103 	ASSERT(dest==PrintExec);
4104 	pif->sendBytes(s);
4105     }
4106 
4107     return TRUE;
4108 }
printValues(FILE * f,PrintType ptype)4109 boolean Network::printValues(FILE *f, PrintType ptype)
4110 {
4111     Node *n;
4112     ListIterator l;
4113     const char *prefix;
4114 
4115     if (ptype == PrintCPBuffer) return TRUE;
4116 
4117     prefix = this->getPrefix();
4118 
4119     FOR_EACH_NETWORK_NODE(this, n, l)
4120     {
4121 	// FIXME: ignoring annotate, requires minor fix to n->printValues().
4122 #if WORKSPACE_PAGES
4123 	StandIn* si = n->getStandIn();
4124 	boolean is_selected = (si?si->isSelected():FALSE);
4125 #endif
4126 	if ((ptype != PrintCut) || (is_selected))
4127 	    if (!n->printValues(f, prefix, ptype))
4128 		return FALSE;
4129     }
4130     return TRUE;
4131 }
SendNetwork(void * staticData,void *)4132 void Network::SendNetwork(void * staticData, void * /*requestData */)
4133 {
4134      Network *n = (Network*)staticData;
4135      n->sendNetwork();
4136 }
sendNetwork()4137 boolean Network::sendNetwork()
4138 {
4139     if (this->deferrableSendNetwork->isActionDeferred()) {
4140       this->deferrableSendNetwork->requestAction(NULL);
4141       return TRUE;
4142     }
4143 
4144     DXPacketIF *pi = theDXApplication->getPacketIF();
4145     if (!pi)
4146 	return TRUE;
4147 
4148     void *cbData;
4149     PacketIFCallback cb;
4150 
4151     //
4152     // Only display the network contents if the file that the net came from
4153     // (if it came from a file) was not encrypted.
4154     //
4155     if (this->netFileWasEncoded)
4156         cb = NULL;
4157     else
4158         cb = pi->getEchoCallback(&cbData);
4159 
4160     pi->sendMacroStart();
4161     if (!this->printHeader(pi->getFILE(), PrintExec, cb, cbData))
4162 	return FALSE;
4163     if (!this->printBody(pi->getFILE(), PrintExec, cb, cbData))
4164 	return FALSE;
4165     if (! this->printTrailer(pi->getFILE(), PrintExec, cb, cbData))
4166 	return FALSE;
4167     pi->sendMacroEnd();
4168 
4169     this->clearDirty();
4170 
4171     return TRUE;
4172 }
sendValues(boolean force)4173 boolean Network::sendValues(boolean force)
4174 {
4175     Node *n;
4176     ListIterator l;
4177 
4178     FOR_EACH_NETWORK_NODE(this, n, l)
4179     {
4180 	if (!n->sendValues(force))
4181 	{
4182 	    return FALSE;
4183 	}
4184     }
4185     return TRUE;
4186 }
4187 
4188 
checkForCycle(Node * srcNode,Node * dstNode)4189 boolean Network::checkForCycle(Node *srcNode, Node *dstNode)
4190 {
4191     Node *n;
4192     ListIterator l;
4193 
4194     FOR_EACH_NETWORK_NODE(this, n, l)
4195 	n->clearMarked();
4196 
4197     return this->markAndCheckForCycle(srcNode,dstNode);
4198 }
markAndCheckForCycle(Node * srcNode,Node * dstNode)4199 boolean Network::markAndCheckForCycle(Node *srcNode, Node *dstNode)
4200 {
4201     int  i;
4202 
4203     if (srcNode == dstNode)
4204         return TRUE;  // A cycle has been detected
4205 
4206     //
4207     // We've already been to this node (and not found a cycle).
4208     //
4209     if (dstNode->isMarked())
4210 	return FALSE;
4211 
4212     //
4213     // Follow the destination Node's output params.
4214     // If they go back to the source Node then adding an
4215     // Ark would create a cycle.
4216     //
4217     int  numParam = dstNode->getOutputCount();
4218 
4219     for (i = 1; i <= numParam; ++i)
4220     {
4221         if (dstNode->isOutputConnected(i))
4222         {
4223             Ark *a;
4224 	    int j;
4225             List *arcs = (List *)dstNode->getOutputArks(i);
4226             for (j = 1; (a = (Ark*)arcs->getElement(j)); ++j)
4227             {
4228                 int paramInd;
4229                 Node *dstPtr = a->getDestinationNode(paramInd);
4230                 if (this->markAndCheckForCycle(srcNode, dstPtr)) {
4231                        return TRUE;  // A cycle has been detected
4232                 }
4233             }
4234          }
4235     }
4236     dstNode->setMarked();
4237     return FALSE; // No cycle has been found
4238 }
4239 
4240 
4241 int
connectedNodes(boolean * marked,int ind,int d)4242 Network::connectedNodes(boolean *marked, int ind, int d)
4243 {
4244     int		markedNodes = 0;
4245     int		i;
4246     Node       *n;
4247     int		j;
4248 
4249     if (marked[ind])
4250 	return markedNodes;
4251 
4252     marked[ind] = TRUE;
4253     ++markedNodes;
4254     n = (Node*)this->nodeList.getElement(ind+1);
4255 
4256     if (d <= 0)
4257     {
4258 	int numParam = n->getInputCount();
4259 	for (i = 1; i <= numParam; ++i)
4260 	{
4261 	    if (n->isInputConnected(i) && n->isInputVisible(i))
4262 	    {
4263 		Ark *a;
4264 		List *arcs = (List *)n->getInputArks(i);
4265 		for (j = 1; (a = (Ark*)arcs->getElement(j)); ++j)
4266 		{
4267 		    int paramInd;
4268 		    Node *n2 = a->getSourceNode(paramInd);
4269 		    markedNodes += this->connectedNodes(
4270 					marked,
4271 					this->nodeList.getPosition((void*)n2)-1,
4272 					d);
4273 		}
4274 	    }
4275 	}
4276     }
4277     if (d >= 0)
4278     {
4279 	int numParam = n->getOutputCount();
4280 	for (i = 1; i <= numParam; ++i)
4281 	{
4282 	    if (n->isOutputConnected(i) && n->isOutputVisible(i))
4283 	    {
4284 		Ark *a;
4285 		List *arcs = (List *)n->getOutputArks(i);
4286 		for (j = 1; (a = (Ark*)arcs->getElement(j)); ++j)
4287 		{
4288 		    int paramInd;
4289 		    Node *n2 = a->getDestinationNode(paramInd);
4290 		    markedNodes += this->connectedNodes(
4291 					marked,
4292 					this->nodeList.getPosition((void*)n2)-1,
4293 					d);
4294 		}
4295 	    }
4296 	}
4297     }
4298 
4299     return markedNodes;
4300 }
4301 
visitNodes(Node * n)4302 int Network::visitNodes(Node *n)
4303 {
4304     int		i;
4305 
4306     int numParam = n->getInputCount();
4307 
4308     for (i = 1; i <= numParam; ++i)
4309     {
4310 	if (n->isInputConnected(i))
4311 	{
4312 	    //
4313 	    // Visit each upstream node.
4314 	    // Note, we don't need to sort the arcs to get a deterministic
4315 	    // sort, because we are going upstream instead of downstream
4316 	    // (i.e. there is one arc per input).
4317 	    //
4318 	    Ark *a;
4319 	    List *arcs = (List *)n->getInputArks(i);
4320 	    ListIterator iter(*arcs);
4321 	    while ( (a = (Ark*)iter.getNext()) )
4322 	    {
4323 		int paramInd;
4324 		Node *n2 = a->getSourceNode(paramInd);
4325 		if (!n2->isMarked())
4326 		    this->visitNodes(n2);
4327 	    }
4328 	}
4329     }
4330 
4331     n->setMarked();
4332     this->nodeList.appendElement((void*)n);
4333 
4334     return 0;
4335 }
4336 
4337 //
4338 // Sort in alphabetic,
4339 // This will make sure, that when there is no ordering between say
4340 // AutoAxes and Compute, AutoAxes will get written out first.
4341 // Also, handle reference numbers similarly so that
4342 // last placed tools (of the same name), get executed last.
4343 // If v > ref return less than 0, else if v < ref return greater than 0,
4344 // else return 0;
4345 //
CompareNodeName(const void * v,const void * ref)4346 static int CompareNodeName(const void *v, const void *ref)
4347 {
4348    Node *refNode = (Node*)ref;
4349    Node *node = (Node*)v;
4350    int r = STRCMP(node->getNameString(),refNode->getNameString());
4351    if (r == 0)
4352 	r = node->getInstanceNumber() - refNode->getInstanceNumber();
4353 
4354    return r;
4355 }
4356 
sortNetwork()4357 void Network::sortNetwork()
4358 {
4359     int	     i;
4360     int      numNodes = this->nodeList.getSize();
4361     ListIterator iterator;
4362     Node	*n;
4363 
4364     if (numNodes <= 1)
4365 	return;
4366 
4367     //
4368     // Sort the nodes so the visitation is deterministic.
4369     //
4370     this->nodeList.sort(CompareNodeName);
4371     List tmpNodeList;
4372     iterator.setList(this->nodeList);
4373     for (i=0 ; (n = (Node*)iterator.getNext()) ; i++) {
4374 	tmpNodeList.appendElement((void*)n);
4375         n->clearMarked();
4376     }
4377     this->nodeList.clear();
4378 
4379     //
4380     // Now that we have a copy of the sorted list, visit all the nodes.
4381     //
4382     iterator.setList(tmpNodeList);
4383     while ( (n = (Node*)iterator.getNext()) ) {
4384 	if (!n->isMarked())
4385 	    this->visitNodes(n);
4386     }
4387 
4388 }
4389 
cfgParseInteractorComment(const char * comment)4390 void Network::cfgParseInteractorComment(const char* comment)
4391 {
4392     Symbol namesym;
4393     int		items_parsed, instance;
4394     char	interactor_name[1024];	// FIXME: allocate this
4395 
4396     ASSERT(comment);
4397 
4398     this->parseState.control_panel = NUL(ControlPanel*);
4399 
4400     items_parsed =
4401         sscanf(comment, " interactor %[^[][%d]:",
4402                interactor_name,
4403                &instance);
4404 
4405     /*
4406      * If all items found...
4407      */
4408     if (items_parsed != 2)
4409     {
4410         ErrorMessage("Bad interactor comment file %s line %d\n",
4411                                         Network::ParseState::parse_file,yylineno);
4412 	Network::ParseState::error_occurred = TRUE;
4413 	return;
4414     }
4415 
4416     /*
4417      * Get the symbol for the name of this node.
4418      * If not found in the symbol table it is an error.
4419      */
4420     namesym = theSymbolManager->getSymbol(interactor_name);
4421     if (!namesym) {
4422         ErrorMessage(
4423             "Interactor %s at line %d file %s not found in the symbol table",
4424                         interactor_name, yylineno, Network::ParseState::parse_file);
4425 	Network::ParseState::error_occurred = TRUE;
4426 	return;
4427     }
4428 
4429 
4430     /*
4431      * Find this node in the current network.
4432      * If not found in the network it is an error.
4433      */
4434     this->parseState.node = this->findNode(namesym,instance);
4435     if (!this->parseState.node) {
4436         ErrorMessage(
4437            "Node %s (instance %d) not found in the program (file %s, line %d)",
4438                         interactor_name, instance,
4439 					Network::ParseState::parse_file, yylineno);
4440 	Network::ParseState::error_occurred = TRUE;
4441 	return;
4442     }
4443 
4444     if (!this->parseState.node->cfgParseComment(comment,
4445 			Network::ParseState::parse_file, yylineno)) {
4446          WarningMessage("Unrecognized comment at line %d of file %s"
4447                          " (ignoring)",  yylineno, Network::ParseState::parse_file);
4448     }
4449     this->parseState.parse_state = _PARSED_INTERACTOR;
4450 }
4451 
4452 //
4453 // Parse any network specific comments found in the .cfg file.
4454 //
cfgParseComment(const char * comment,const char * file,int lineno)4455 boolean Network::cfgParseComment(const char* comment,
4456 					const char *file, int lineno)
4457 {
4458     ASSERT(this->panelGroupManager);
4459     ASSERT(this->panelAccessManager);
4460     return theDXApplication->parseComment(comment,file,lineno) ||
4461 	   this->panelGroupManager->cfgParseComment(comment,file,lineno) ||
4462 	   this->panelAccessManager->cfgParseInaccessibleComment(comment,
4463 							file,lineno);
4464 }
4465 
cfgParsePanelComment(const char * comment)4466 void Network::cfgParsePanelComment(const char* comment)
4467 {
4468     int i;
4469 
4470     ASSERT(comment);
4471 
4472     sscanf(comment, " panel[%d]", &i);
4473     this->parseState.control_panel = this->getPanelByInstance(i+1);
4474     if (NOT this->parseState.control_panel)
4475     	this->parseState.control_panel = this->newControlPanel(i+1);
4476 
4477     if (!this->parseState.control_panel->cfgParseComment(comment,
4478 				Network::ParseState::parse_file, yylineno)) {
4479           WarningMessage("Unrecognized comment at line %d of file %s"
4480                         " (ignoring)",  yylineno, Network::ParseState::parse_file);
4481     }
4482 
4483     this->parseState.parse_state = _PARSED_PANEL;
4484 }
4485 
4486 
4487 //
4488 // Find a node with a specific name and return its instance number
4489 // as well as its position in the list.
4490 //
findNode(const char * name,int * startPos,boolean byLabel)4491 Node *Network::findNode(const char* name, int* startPos, boolean byLabel)
4492 {
4493     ListIterator li(this->nodeList);
4494     Node        *n;
4495 
4496     if (startPos) {
4497 	if (*startPos > (this->nodeList).getSize())
4498 	    return NULL;
4499 	li.setPosition(*startPos);
4500     }
4501 
4502     for(n = (Node*)li.getNext(); n; n = (Node*)li.getNext())
4503     {
4504 	if (startPos)
4505 	    (*startPos)++;
4506 	if (EqualString(n->getLabelString(),name) AND byLabel
4507             OR EqualString(n->getNameString(),name) AND !byLabel)
4508              return(n);
4509     }
4510 
4511     return NULL;
4512 }
4513 
4514 //
4515 // Search the network for a node of the given class and return TRUE
4516 // if found.
4517 //
4518 
4519 
postSaveCfgDialog(Widget parent)4520 void Network::postSaveCfgDialog(Widget parent)
4521 {
4522     if (this->saveCfgDialog == NULL)
4523         this->saveCfgDialog = new SaveCFGDialog(parent, this);
4524 
4525     this->saveCfgDialog->post();
4526 }
postOpenCfgDialog(Widget parent)4527 void Network::postOpenCfgDialog(Widget parent)
4528 {
4529     if (this->openCfgDialog == NULL)
4530         this->openCfgDialog = new OpenCFGDialog(parent, this);
4531 
4532     this->openCfgDialog->post();
4533 }
postSaveAsDialog(Widget parent,Command * cmd)4534 void Network::postSaveAsDialog(Widget parent, Command *cmd)
4535 {
4536     if (this->saveAsDialog == NULL) {
4537         this->saveAsDialog = new SaveAsDialog(parent, this);
4538     }
4539 
4540     this->saveAsDialog->setPostCommand(cmd);
4541     this->saveAsDialog->post();
4542 }
4543 
4544 
isMacro()4545 boolean Network::isMacro()
4546 {
4547     return this->definition != NULL;
4548 }
4549 // FIX me
canBeMacro()4550 boolean Network::canBeMacro()
4551 {
4552     Node *n;
4553     ListIterator li;
4554     FOR_EACH_NETWORK_NODE(this, n, li)
4555 	if (!n->isAllowedInMacro())
4556 	    return FALSE;
4557 
4558     return TRUE;
4559 }
makeMacro(boolean make)4560 boolean Network::makeMacro(boolean make)
4561 {
4562     if (make && !this->canBeMacro())
4563 	return FALSE;
4564     else if (make && this->isMacro())
4565 	return TRUE;
4566     // FIXME: be sure to return false if (!make && I have inputs)
4567 
4568     if (make)
4569     {
4570 	const char *name = this->getNameString();
4571 	MacroDefinition *md = new MacroDefinition();
4572 	md->setName(name);
4573 	md->setCategory(this->getCategorySymbol());
4574 
4575 	this->definition = md;
4576     }
4577     // Make this a non-macro iff it's the main network.  Otherwise, it's
4578     // got to stay a macro.
4579     else if (this == theDXApplication->network)
4580     {
4581 	delete this->definition;
4582 	this->definition = NULL;
4583     }
4584 
4585     return TRUE;
4586 }
4587 
4588 //
4589 // Find the first free index (indices start from 1) for nodes with the
4590 // given name.
4591 // Currently, this only works for Input/Output nodes.
4592 //
findFreeNodeIndex(const char * nodename)4593 int Network::findFreeNodeIndex(const char *nodename)
4594 {
4595     int retindex;
4596 
4597     // MacroParameterNodes are the only ones that have an index (currently).
4598     ASSERT(EqualString(nodename,"Input") ||
4599      	   EqualString(nodename,"Output"));
4600 
4601     List *l = this->makeNamedNodeList(nodename);
4602     if (!l) {
4603 	retindex = 1;
4604     } else {
4605 	int i, j, nodecnt = l->getSize();
4606 	//
4607 	// The following algorithm assumes that all nodes of the
4608 	// given class in the network all have valid indices.
4609 	//
4610 
4611 	//
4612 	// Bubble sort the nodes by index (nodes[0] has smallest index).
4613 	//
4614 	int *indices= new int[nodecnt];
4615 	for (i=0 ; i<nodecnt ; i++) {
4616 	    MacroParameterNode *n = (MacroParameterNode*)l->getElement(i+1);
4617 	    indices[i] = n->getIndex();
4618 	}
4619 	for (i=0 ; i<nodecnt ; i++) {
4620 	    for (j=i+1 ; j<nodecnt ; j++) {
4621 		if (indices[j] < indices[i]) {
4622 		    int tmp  = indices[i];
4623 		    indices[i] = indices[j];
4624 		    indices[j] = tmp;
4625 		}
4626 	    }
4627 	}
4628 	retindex = 0;
4629 	for (i=1 ; !retindex && i<=nodecnt ; i++) {
4630 	    if (indices[i-1] != i)
4631 		retindex = i;
4632 	}
4633 	if (!retindex)
4634 	    retindex = nodecnt + 1;
4635 	delete indices;
4636 	delete l;
4637     }
4638     return retindex;
4639 }
4640 
moveInputPosition(MacroParameterNode * n,int index)4641 boolean Network::moveInputPosition(MacroParameterNode *n, int index)
4642 {
4643 	ASSERT(this->isMacro());
4644 	ParameterDefinition *pd = n->getParameterDefinition();
4645 	int inputCount = this->definition->getInputCount();
4646 	int oldPos = 0;
4647 	for (int i = 1; i <= inputCount; ++i)
4648 	{
4649 		ParameterDefinition *oldPd = this->definition->getInputDefinition(i);
4650 		if (pd == oldPd)
4651 		{
4652 			oldPos = i;
4653 			break;
4654 		}
4655 	}
4656 	ASSERT(oldPos != 0);
4657 
4658 	if (oldPos == index)
4659 		return TRUE;
4660 
4661 	boolean return_val = TRUE;
4662 	this->deferrableSendNetwork->deferAction();
4663 	//
4664 	// At this point, oldPos is where the parameter was, and index is where
4665 	// we want it to be.  First, we put a dummy where the parameter was
4666 	// (unless it was at the end), then we put the parameter where it should
4667 	// be.
4668 	if (oldPos == inputCount)
4669 	{
4670 		this->definition->removeInput(pd);
4671 		inputCount--;
4672 	}
4673 	else
4674 	{
4675 		ParameterDefinition *dummy = new ParameterDefinition(-1);
4676 		dummy->setDummy(TRUE);
4677 		dummy->setName("input");
4678 		dummy->markAsInput();
4679 		dummy->setDefaultVisibility();
4680 		dummy->addType(new DXType(DXType::ObjectType));
4681 		this->definition->replaceInput(dummy, pd);
4682 	}
4683 	if (index > inputCount)
4684 	{
4685 		for (int i = inputCount + 1; i < index; ++i)
4686 		{
4687 			ParameterDefinition *dummy = new ParameterDefinition(-1);
4688 			dummy->setDummy(TRUE);
4689 			dummy->setName("input");
4690 			dummy->markAsInput();
4691 			dummy->setDefaultVisibility();
4692 			dummy->addType(new DXType(DXType::ObjectType));
4693 			dummy->setDescription("Dummy parameter");
4694 			this->definition->addInput(dummy);
4695 		}
4696 		this->definition->addInput(pd);
4697 	}
4698 	else
4699 	{
4700 		ParameterDefinition *targetPd =
4701 			this->definition->getInputDefinition(index);
4702 		List *l = this->makeNamedNodeList(n->getNameString());
4703 		MacroParameterNode *mpn = NULL;
4704 		if (l)
4705 		{
4706 			ListIterator li(*l);
4707 			while( (mpn = (MacroParameterNode*)li.getNext()) )
4708 			{
4709 				if (mpn->getIndex() == index)
4710 					break;
4711 			}
4712 			delete l;
4713 		}
4714 		if (mpn == NULL)
4715 		{
4716 			this->definition->replaceInput(pd, targetPd);
4717 			delete targetPd;
4718 		}
4719 		else
4720 		{
4721 			if (oldPos == inputCount+1)
4722 				this->definition->addInput(pd);
4723 			else
4724 			{
4725 				ParameterDefinition *dummyPd =
4726 					this->definition->getInputDefinition(oldPos);
4727 				this->definition->replaceInput(pd, dummyPd);
4728 				delete dummyPd;
4729 			}
4730 			return_val =  FALSE;
4731 		}
4732 	}
4733 
4734 	if (return_val)
4735 		n->setIndex(index);
4736 
4737 	this->deferrableSendNetwork->undeferAction();
4738 
4739 	return return_val;
4740 }
moveOutputPosition(MacroParameterNode * n,int index)4741 boolean Network::moveOutputPosition(MacroParameterNode *n, int index)
4742 {
4743 	ASSERT(this->isMacro());
4744 	ParameterDefinition *pd = n->getParameterDefinition();
4745 	int outputCount = this->definition->getOutputCount();
4746 	int oldPos = 0;
4747 	for (int i = 1; i <= outputCount; ++i)
4748 	{
4749 		ParameterDefinition *oldPd = this->definition->getOutputDefinition(i);
4750 		if (pd == oldPd)
4751 		{
4752 			oldPos = i;
4753 			break;
4754 		}
4755 	}
4756 	ASSERT(oldPos != 0);
4757 
4758 	if (oldPos == index)
4759 		return TRUE;
4760 
4761 	this->deferrableSendNetwork->deferAction();
4762 	boolean return_val = TRUE;
4763 
4764 	if (oldPos == outputCount)
4765 	{
4766 		this->definition->removeOutput(pd);
4767 		outputCount--;
4768 	}
4769 	else
4770 	{
4771 		ParameterDefinition *dummy = new ParameterDefinition(-1);
4772 		dummy->setDummy(TRUE);
4773 		dummy->setName("output");
4774 		dummy->markAsOutput();
4775 		dummy->setDefaultVisibility();
4776 		dummy->addType(new DXType(DXType::ObjectType));
4777 		dummy->setDescription("Dummy parameter");
4778 		this->definition->replaceOutput(dummy, pd);
4779 	}
4780 	if (index > outputCount)
4781 	{
4782 		for (int i = outputCount + 1; i < index; ++i)
4783 		{
4784 			ParameterDefinition *dummy = new ParameterDefinition(-1);
4785 			dummy->setDummy(TRUE);
4786 			dummy->setName("output");
4787 			dummy->markAsOutput();
4788 			dummy->setDefaultVisibility();
4789 			dummy->addType(new DXType(DXType::ObjectType));
4790 			dummy->setDescription("Dummy parameter");
4791 			this->definition->addOutput(dummy);
4792 		}
4793 		this->definition->addOutput(pd);
4794 	}
4795 	else
4796 	{
4797 		ParameterDefinition *targetPd =
4798 			this->definition->getOutputDefinition(index);
4799 		List *l = this->makeNamedNodeList(n->getNameString());
4800 		MacroParameterNode *mpn = NULL;
4801 		if (l)
4802 		{
4803 			ListIterator li(*l);
4804 			while( (mpn = (MacroParameterNode*)li.getNext()) )
4805 			{
4806 				if (mpn->getIndex() == index)
4807 					break;
4808 			}
4809 			delete l;
4810 		}
4811 		if (mpn == NULL)
4812 		{
4813 			this->definition->replaceOutput(pd, targetPd);
4814 			delete targetPd;
4815 		}
4816 		else
4817 		{
4818 			if (oldPos == outputCount+1)
4819 				this->definition->addOutput(pd);
4820 			else
4821 			{
4822 				ParameterDefinition *dummyPd =
4823 					this->definition->getOutputDefinition(oldPos);
4824 				this->definition->replaceOutput(pd, dummyPd);
4825 				delete dummyPd;
4826 			}
4827 			return_val = FALSE;
4828 		}
4829 	}
4830 	if (return_val)
4831 		n->setIndex(index);
4832 
4833 	this->deferrableSendNetwork->undeferAction();
4834 
4835 	return return_val;
4836 }
4837 
setDefinition(MacroDefinition * md)4838 void Network::setDefinition(MacroDefinition *md)
4839 {
4840     this->definition = md;
4841 }
getDefinition()4842 MacroDefinition *Network::getDefinition()
4843 {
4844     return this->definition;
4845 }
getInputDefinition(int i)4846 ParameterDefinition *Network::getInputDefinition(int i)
4847 {
4848     return this->getDefinition()->getInputDefinition(i);
4849 }
getOutputDefinition(int i)4850 ParameterDefinition *Network::getOutputDefinition(int i)
4851 {
4852     return this->getDefinition()->getOutputDefinition(i);
4853 }
getInputCount()4854 int Network::getInputCount()
4855 {
4856     MacroDefinition *md = this->definition;
4857     Node *node;
4858     ListIterator l;
4859 
4860     if (md)
4861 	return md->getInputCount();
4862 
4863     int count = 0;
4864     FOR_EACH_NETWORK_NODE(this, node, l) {
4865 	if (node->isA(ClassMacroParameterNode)) {
4866 	    MacroParameterNode *mpn = (MacroParameterNode*)node;
4867 	    if (mpn->isInput() && mpn->getIndex() > count)
4868 		count = mpn->getIndex();
4869 	}
4870     }
4871     return count;
4872 }
getOutputCount()4873 int Network::getOutputCount()
4874 {
4875     MacroDefinition *md = this->definition;
4876     Node *node;
4877     ListIterator l;
4878 
4879     if (md)
4880 	return md->getOutputCount();
4881 
4882     int count = 0;
4883     FOR_EACH_NETWORK_NODE(this, node, l) {
4884 	if (node->isA(ClassMacroParameterNode)) {
4885 	    MacroParameterNode *mpn = (MacroParameterNode*)node;
4886 	    if (!mpn->isInput() && mpn->getIndex() > count)
4887 		count = mpn->getIndex();
4888 	}
4889     }
4890     return count;
4891 }
4892 
openColormap(boolean openAll)4893 void Network::openColormap(boolean openAll)
4894 {
4895     ColormapNode        *n;
4896     ListIterator              li;
4897     List *cmaps = NULL;
4898 
4899     if (openAll) {
4900 	cmaps = this->makeClassifiedNodeList(ClassColormapNode);
4901 	if (!cmaps)
4902 	    return;
4903     } else {
4904 	EditorWindow *e = this->editor;
4905 	ASSERT(e);
4906 	cmaps = e->makeSelectedNodeList(ClassColormapNode);
4907     }
4908     li.setList(*cmaps);
4909 
4910     while( (n = (ColormapNode*)li.getNext()) )
4911         n->openDefaultWindow(theDXApplication->getRootWidget());
4912 
4913     delete cmaps;
4914 }
4915 
setDescription(const char * description,boolean markDirty)4916 void Network::setDescription(const char *description, boolean markDirty)
4917 {
4918     if (this->description)
4919 	delete this->description;
4920     this->description = DuplicateString(description);
4921     if (markDirty)
4922 	this->setFileDirty();
4923 }
setCategory(const char * cat,boolean markDirty)4924 Symbol Network::setCategory(const char *cat, boolean markDirty)
4925 {
4926     if ((cat) && (cat[0]))
4927 	this->category = theSymbolManager->registerSymbol(cat);
4928     else
4929 	this->category = 0;
4930     if (markDirty)
4931 	this->setFileDirty();
4932     return this->category;
4933 }
4934 
getDescriptionString()4935 const char *Network::getDescriptionString()
4936 {
4937     return this->description;
4938 }
4939 
postNameDialog()4940 boolean Network::postNameDialog()
4941 {
4942     if (!this->setNameDialog)
4943     {
4944 	// FIXME: should this be an editor command.
4945         EditorWindow *editor = this->getEditor();
4946 	Widget parent;
4947 	if (editor)
4948 	    parent = editor->getRootWidget();
4949 	else
4950 	    parent = theDXApplication->getAnchor()->getRootWidget();
4951 	this->setNameDialog = new SetMacroNameDialog(parent,this);
4952     }
4953     this->setNameDialog->post();
4954     return TRUE;
4955 }
4956 
getNode(const char * name,int instance)4957 Node *Network::getNode(const char *name, int instance)
4958 {
4959     Symbol s = theNDAllocatorDictionary->getSymbolManager()->
4960 		registerSymbol(name);
4961 
4962     return this->findNode(s,instance);
4963 }
editNetworkComment()4964 void Network::editNetworkComment()
4965 {
4966      if (!this->setCommentDialog) {
4967         this->setCommentDialog = new SetNetworkCommentDialog(
4968                                 this->getEditor()->getRootWidget(),
4969                                 FALSE, this);
4970      }
4971      this->setCommentDialog->post();
4972 }
postHelpOnNetworkDialog()4973 void Network::postHelpOnNetworkDialog()
4974 {
4975      if (!this->helpOnNetworkDialog) {
4976 	Widget parent = theDXApplication->getRootWidget();
4977         this->helpOnNetworkDialog = new HelpOnNetworkDialog(
4978 				parent, this);
4979      }
4980      this->helpOnNetworkDialog->post();
4981 }
4982 //
4983 // Set the comment of this network.
4984 //
setNetworkComment(const char * comment)4985 void Network::setNetworkComment(const char *comment)
4986 {
4987 
4988 	if (comment != this->comment) {
4989 		this->setDirty();
4990 		if (this->comment)
4991 			delete this->comment;
4992 		if (comment && STRLEN(comment)) {
4993 			this->comment = DuplicateString(comment);
4994 		} else {
4995 			this->comment = NULL;
4996 		}
4997 	}
4998 
4999 	if (this->comment && STRLEN(this->comment))
5000 		this->helpOnNetworkCmd->activate();
5001 	else
5002 		this->helpOnNetworkCmd->deactivate();
5003 }
5004 
5005 //
5006 // This will reset the image count for isLastImage();
resetImageCount()5007 void Network::resetImageCount()
5008 {
5009     this->imageCount = 0;
5010 }
5011 
5012 //
5013 // Returns true if the caller is the last element of the image list.
5014 // It is assumed that each member of this list will determine, during
5015 // Node::prepareToSendNode, will call this to see if it's the last one.
isLastImage()5016 boolean Network::isLastImage()
5017 {
5018     return ++this->imageCount == this->imageList.getSize();
5019 }
setName(const char * n)5020 Symbol Network::setName(const char *n)
5021 {
5022     Symbol newName = theSymbolManager->registerSymbol(n);
5023     boolean needsValues = this->name != newName && this->prefix != NULL;
5024     this->setDirty();
5025     if (this->prefix)
5026 	delete this->prefix;
5027     this->prefix = NULL;
5028     this->name = newName;
5029     if (needsValues && theDXApplication->getPacketIF() != NULL)
5030 	this->sendValues(TRUE);
5031     return this->name;
5032 }
5033 //
5034 // Given lists of old and new NodeDefinitions, redefine any nodes
5035 // in the current network.
5036 //
redefineNodes(Dictionary * newdefs,Dictionary * olddefs)5037 boolean Network::redefineNodes(Dictionary *newdefs, Dictionary *olddefs)
5038 {
5039     Node *node;
5040     ListIterator l;
5041 
5042     FOR_EACH_NETWORK_NODE(this, node, l) {
5043 	const char *name = node->getNameString();
5044 	if (olddefs->findDefinition(name)) {
5045 	    NodeDefinition *newdef = (NodeDefinition*)
5046 					newdefs->findDefinition(name);
5047 	    if (newdef) {	// Should always be non-zero
5048 		node->setDefinition(newdef);
5049 		node->updateDefinition();
5050 	    }
5051 	}
5052     }
5053     return TRUE;
5054 }
5055 
getNodeCount()5056 int Network::getNodeCount()
5057 {
5058     return this->nodeList.getSize();
5059 }
5060 
5061 //
5062 // Place menu items (ButtonInterfaces) in the CascadeMenu, that when executed
5063 // cause individually named panels and panel groups to be opened.
5064 // If a PanelAccessManager, then only those ControlPanels defined to be
5065 // accessible are placed in the CascadeMenu.
5066 // NOTE: to optimize this method, if the menu is returned deactivated()
5067 //	it may not contain the correct contents and so should no be activated()
5068 //	except through subsequent calls to this method.
5069 //
fillPanelCascade(CascadeMenu * menu,PanelAccessManager * pam)5070 void Network::fillPanelCascade(CascadeMenu *menu, PanelAccessManager *pam)
5071 {
5072     ButtonInterface *bi;
5073     Widget parent;
5074     char *name;
5075     char buttonName[32];
5076     int i, size;
5077     boolean hasChildren = FALSE;
5078 
5079 
5080     if ((size = this->getPanelCount()) != 0) {
5081 
5082         menu->clearComponents();
5083 
5084         parent = menu->getMenuItemParent();
5085 
5086         ASSERT(pam);
5087 
5088         //
5089         // Build the list of panels by name
5090         //
5091         for(i = 0; i<size; i++) {
5092             ControlPanel *cp = this->getPanelByIndex(i+1);
5093             ASSERT(cp);
5094 
5095             long inst = cp->getInstanceNumber();
5096             if (pam) {
5097                 if (NOT pam->isAccessiblePanel(inst) OR
5098                         pam->getControlPanel() == cp)
5099                     continue;
5100             }
5101 
5102 
5103 	    sprintf(buttonName,"panel%d",inst);
5104             ButtonInterface *bi = new ButtonInterface(parent, buttonName,
5105                                         this->openPanelByInstanceCmd);
5106 
5107             name = (char*)cp->getPanelNameString();
5108             if(IsBlankString(name))
5109                 name = "Control Panel";
5110             bi->setLabel(name);
5111             bi->setLocalData((void*)inst);
5112             menu->appendComponent(bi);
5113             hasChildren = TRUE;
5114         }
5115 
5116         //
5117         // Now add panel groups
5118         //
5119         PanelGroupManager *pgm = this->panelGroupManager;
5120         size = pgm->getGroupCount();
5121         if (size > 0) {
5122             for (i=1; i<=size; i++) {
5123                 name = (char*)pgm->getPanelGroup(i, NULL);
5124                 if (pam && pam->isAccessibleGroup(name)) {
5125                     hasChildren = TRUE;
5126 	    	    sprintf(buttonName,"group%d",i);
5127                     bi = new ButtonInterface(parent, buttonName,
5128                                         this->openPanelGroupByIndexCmd);
5129 
5130                     bi->setLabel(name);
5131                     bi->setLocalData((void*)i);
5132                     menu->appendComponent(bi);
5133                 }
5134             }
5135         }
5136 
5137     }
5138 
5139     if (hasChildren)
5140         menu->activate();
5141     else
5142         menu->deactivate();
5143 
5144 }
5145 
5146 #ifdef NOTYET
5147 //
5148 // look through the network list and make a count of the nodes with
5149 // the give name.
5150 // If nodename is NULL then count all of them.
5151 //
countNodesByName(const char * nodename)5152 int Network::countNodesByName(const char *nodename)
5153 {
5154     Node *node;
5155     ListIterator iterator;
5156     int count;
5157 
5158     if (nodename) {
5159         count = 0;
5160         FOR_EACH_NETWORK_NODE(this, node, iterator) {
5161             if (EqualString(node->getNameString(),nodename))
5162                 count++;
5163         }
5164     } else {
5165         count = this->getNodeCount();
5166     }
5167     return count;
5168 }
5169 #endif // NOTYET
5170 //
5171 // Return true if the network is different from that on disk, and the
5172 // application allows saving of .net and .cfg files.
5173 //
saveToFileRequired()5174 boolean Network::saveToFileRequired()
5175 {
5176     int count = this->getNodeCount() + this->decoratorList.getSize();
5177 #if WORKSPACE_PAGES
5178     DictionaryIterator di(*this->groupManagers);
5179     GroupManager* gmgr;
5180     while ( (gmgr = (GroupManager*)di.getNextDefinition()) )
5181 	count+= gmgr->getGroupCount();
5182 #endif
5183     return this->isFileDirty() && (count > 0) &&
5184 	theDXApplication->appAllowsSavingNetFile(this) &&
5185 	theDXApplication->appAllowsSavingCfgFile() &&
5186 	!this->netFileWasEncoded;
5187 }
5188 
5189 //
5190 // Merge the new network into this network.
5191 //
mergeNetworks(Network * new_net,List * panels,boolean allNodes,boolean stitch)5192 boolean Network::mergeNetworks(Network *new_net, List *panels, boolean allNodes, boolean stitch)
5193 {
5194 Node		*cur_node;
5195 Node		*new_node;
5196 ListIterator	cur_l;
5197 ListIterator	new_l;
5198 ControlPanel	*new_cp;
5199 ListIterator	new_cp_l;
5200 List		cpDeleteList;
5201 List		removedNodes;
5202 List		removedDecs;
5203 List		swapFromNodes; 	  // nodes in new_net that aren't going to be
5204 List		swapToNodes;	  // transferred to this network.
5205 
5206 
5207     //
5208     // make sure we don't merge an encoded (unviewable) network into
5209     // a network that has an editor and that would allow viewing of the
5210     // encoded program.
5211     //
5212     if (this->getEditor() && new_net->wasNetFileEncoded()) {
5213 	ErrorMessage("Encoded visual programs are not viewable.\n"
5214 		     "Attempt to merge encoded program aborted.");
5215 	return FALSE;
5216     }
5217 
5218     //
5219     // Delete the image windows: Their network pointers are all wrong.
5220     // They are re-created in DisplayNode::switchNetwork()
5221     //
5222     ImageWindow *iw;
5223     while ( (iw = (ImageWindow *)new_net->imageList.getElement(1)) )
5224 	delete iw;
5225 
5226     FOR_EACH_NETWORK_NODE(new_net, new_node, new_l)
5227     {
5228 	if (allNodes ||
5229 	    (new_node->getStandIn() && new_node->getStandIn()->isSelected()))
5230 	    removedNodes.appendElement(new_node);
5231     }
5232 
5233     Decorator *new_dec;
5234     FOR_EACH_NETWORK_DECORATOR(new_net, new_dec, new_l)
5235     {
5236 	if (allNodes || new_dec->isSelected())
5237 	    removedDecs.appendElement(new_dec);
5238     }
5239 
5240     for (new_l.setList(removedNodes); (new_node = (Node*)new_l.getNext()); )
5241     {
5242 	Symbol new_name = new_node->getNameSymbol();
5243 	long   new_inst = new_node->getInstanceNumber();
5244 
5245 	//
5246 	// See if we have a name/instance collision
5247 	//
5248 	FOR_EACH_NETWORK_NODE(this, cur_node, cur_l)
5249 	{
5250 	    if (!stitch) {
5251 		if((cur_node->getNameSymbol() == new_name) &&
5252 		   (cur_node->getInstanceNumber() == new_inst))
5253 		{
5254 		    new_node->assignNewInstanceNumber();
5255 		}
5256 	    } else {
5257 		// we're helping to undo a node deletion in the vpe.
5258 		// We want to figure out the arcs that were incident on
5259 		// the current node in the incoming network and shift
5260 		// those arcs over to the node in the existing network.
5261 		if((cur_node->getNameSymbol() == new_name) &&
5262 		   (cur_node->getInstanceNumber() == new_inst))
5263 		{
5264 		    swapFromNodes.appendElement (new_node);
5265 		    swapToNodes.appendElement (cur_node);
5266 		}
5267 	    }
5268 	}
5269 	new_net->nodeList.removeElement(new_node);
5270 	// new_net->deferrableRemoveNode->requestAction((void*)new_node);
5271     }
5272 
5273     //
5274     // Check to see if there are any problems with moving things over.  If
5275     // there are, abort the whole process.
5276     //
5277     for (new_l.setList(removedNodes); (new_node = (Node*)new_l.getNext()); )
5278     {
5279 	if (!new_node->canSwitchNetwork(new_net,this))
5280 	{
5281 	    return FALSE;
5282 	}
5283     }
5284 
5285 #if WORKSPACE_PAGES
5286     //
5287     // Deal with group information.
5288     // Rules:
5289     //	1) Throw out all group info from GroupManagers who say they can't
5290     //	survive a network merge.
5291     //	2) Throw out all group info from the first group from GroupManagers who
5292     //	say they can survive a merge and keep group info from remaining groups.
5293     //  caveat: only throw out the first group if its name doesn't match a name
5294     //  already in the current network.
5295     //	3) When keeping group info, if the group doesn't already exist in the
5296     //	current net, then create the group otherwise just cruise along.
5297     //
5298     // I wanted to put this code into a GroupManager::switchNetwork method, but
5299     // it requires scanning the list of removedNodes and it requires knowledge
5300     // of the set of groups rather than just knowledge internal to the group.
5301     //
5302     if (this->editor) this->editor->beginPageChange();
5303     Dictionary* mergingGroup = new_net->getGroupManagers();
5304     DictionaryIterator di(*mergingGroup);
5305     GroupManager* gmgr;
5306     while ( (gmgr = (GroupManager*)di.getNextDefinition()) ) {
5307 	Symbol gmgr_sym = gmgr->getManagerSymbol();
5308 	const char* first_group = NUL(char*);
5309 	//
5310 	// The following check on allNodes assumes that the incoming network
5311 	// originated in a single page.  See EditorWindow::macroify...
5312 	//
5313 	if ((gmgr->survivesMerging() == FALSE) || (allNodes == FALSE)) {
5314 	    for (new_l.setList(removedNodes); (new_node = (Node*)new_l.getNext()); ) {
5315 		const char* group_name = new_node->getGroupName(gmgr_sym);
5316 		if (group_name) {
5317 		    new_node->setGroupName(NUL(GroupRecord*), gmgr_sym);
5318 		}
5319 	    }
5320 	    for (new_l.setList(removedDecs); (new_dec = (Decorator*)new_l.getNext()); ) {
5321 		VPEAnnotator* vpea = (VPEAnnotator*)new_dec;
5322 		const char* group_name = vpea->getGroupName(gmgr_sym);
5323 		if (group_name) {
5324 		    vpea->setGroupName(NUL(GroupRecord*), gmgr_sym);
5325 		}
5326 	    }
5327 	} else {
5328 	    GroupManager* local_gmgr = (GroupManager*)
5329 		this->groupManagers->findDefinition(gmgr_sym);
5330 	    for (new_l.setList(removedNodes); (new_node = (Node*)new_l.getNext()); ) {
5331 		GroupRecord* grec = NUL(GroupRecord*);
5332 		const char* group_name = new_node->getGroupName(gmgr_sym);
5333 		if (group_name) {
5334 		    if (local_gmgr)
5335 			grec = local_gmgr->getGroup(group_name);
5336 
5337 		    if ((grec == NUL(GroupRecord*)) && (first_group == NUL(char*)))
5338 			first_group = group_name;
5339 
5340 		    if ((first_group) && (EqualString(first_group, group_name))) {
5341 			new_node->setGroupName(NUL(GroupRecord*), gmgr_sym);
5342 		    } else {
5343 			if (grec == NUL(GroupRecord*)) {
5344 			    boolean group_created =
5345 				local_gmgr->createGroup (group_name, this);
5346 			    if (!group_created)
5347 				new_node->setGroupName(NUL(GroupRecord*), gmgr_sym);
5348 			    else {
5349 				grec = local_gmgr->getGroup(group_name);
5350 				new_node->setGroupName(grec, gmgr_sym);
5351 			    }
5352 			} else {
5353 			    new_node->setGroupName(grec, gmgr_sym);
5354 			}
5355 		    }
5356 		}
5357 	    }
5358 	    for (new_l.setList(removedDecs); (new_dec = (Decorator*)new_l.getNext()); ) {
5359 		VPEAnnotator* vpea = (VPEAnnotator*)new_dec;
5360 		const char* group_name = vpea->getGroupName(gmgr_sym);
5361 		GroupRecord* grec = NUL(GroupRecord*);
5362 		if (group_name) {
5363 		    if (local_gmgr)
5364 			grec = local_gmgr->getGroup(group_name);
5365 
5366 		    if ((grec == NUL(GroupRecord*)) && (first_group == NUL(char*)))
5367 			first_group = group_name;
5368 
5369 		    if ((first_group) && (EqualString(first_group, group_name))) {
5370 			vpea->setGroupName(NUL(GroupRecord*), gmgr_sym);
5371 		    } else {
5372 			if (grec == NUL(GroupRecord*)) {
5373 			    boolean group_created =
5374 				local_gmgr->createGroup (group_name, this);
5375 			    if (!group_created)
5376 				vpea->setGroupName(NUL(GroupRecord*), gmgr_sym);
5377 			    else {
5378 				grec = local_gmgr->getGroup(group_name);
5379 				vpea->setGroupName(grec, gmgr_sym);
5380 			    }
5381 			} else {
5382 			    vpea->setGroupName(grec, gmgr_sym);
5383 			}
5384 		    }
5385 		}
5386 	    }
5387 	}
5388     }
5389 #endif
5390 
5391     //
5392     // Move them over to the current network
5393     //
5394     this->deferrableAddNode->deferAction();
5395     for (new_l.setList(removedNodes); (new_node = (Node*)new_l.getNext()); )
5396     {
5397 	boolean silently = FALSE;
5398 	if (stitch) {
5399 	    // don't complain about problems with nodes that are
5400 	    // about to go away.
5401 	    if (swapFromNodes.isMember(new_node))
5402 		silently = TRUE;
5403 	}
5404 	new_node->switchNetwork(new_net,this,silently);
5405 	new_net->nodeList.removeElement(new_node);
5406 	this->addNode(new_node);
5407     }
5408 
5409     //
5410     // If we're stitching - a result of undoing a deletion -
5411     // then for every arc that connects to a member of deleteNodes
5412     // from a member of new_net that isn't in deleteNodes, throw
5413     // out the arc and replace the arc with one that connects to
5414     // the existing counter part to the member of deleteNodes.
5415     //
5416     if (stitch) {
5417 	boolean input_tab_problem_detected = FALSE;
5418 	boolean output_tab_problem_detected = FALSE;
5419 	int missing_tab_count = 0;
5420 	int swap_count = swapFromNodes.getSize();
5421 	for (int i=1; i<=swap_count; i++) {
5422 	    Node* fromNode = (Node*)swapFromNodes.getElement(i);
5423 	    const char* cp = fromNode->getLabelString();
5424 	    Node* toNode = (Node*)swapToNodes.getElement(i);
5425 	    ASSERT (fromNode->getNameSymbol() == toNode->getNameSymbol());
5426 	    int input_count = fromNode->getInputCount();
5427 	    int input_count2 = toNode->getInputCount();
5428 	    for (int input=1; input<=input_count; input++) {
5429 		if (!fromNode->isInputVisible(input)) continue;
5430 		List* arcs = (List*)fromNode->getInputArks(input);
5431 		ListIterator iter(*arcs);
5432 		Ark* arc;
5433 		while ((arc=(Ark*)iter.getNext())) {
5434 		    int output;
5435 		    Node* source = arc->getSourceNode(output);
5436 		    // if source is remaining...
5437 		    if (swapFromNodes.isMember(source)) continue;
5438 		    delete arc;
5439 		    if ((input<=input_count2) && (toNode->isInputVisible(input))) {
5440 			if (toNode->isInputConnected(input)) {
5441 			    // can't create the arc because someone else
5442 			    // already wired the input we wanted to use.
5443 			    input_tab_problem_detected = TRUE;
5444 			    missing_tab_count++;
5445 			} else {
5446 			    StandIn* si = toNode->getStandIn();
5447 			    ASSERT (si);
5448 			    si->addArk (this->editor,
5449 				new Ark(source, output, toNode, input));
5450 			}
5451 		    } else {
5452 			// the tab was missing
5453 			input_tab_problem_detected = TRUE;
5454 			missing_tab_count++;
5455 		    }
5456 		}
5457 	    }
5458 	    int output_count = fromNode->getOutputCount();
5459 	    int output_count2 = toNode->getOutputCount();
5460 	    for (int output=1; output<=output_count; output++) {
5461 		if (!fromNode->isOutputVisible(output)) continue;
5462 		List* arcs = (List*)fromNode->getOutputArks(output);
5463 		ListIterator iter(*arcs);
5464 		Ark* arc;
5465 		while ((arc=(Ark*)iter.getNext())) {
5466 		    int input;
5467 		    Node* dest = arc->getDestinationNode(input);
5468 		    if (swapFromNodes.isMember(dest)) continue;
5469 		    delete arc;
5470 		    if ((output<=output_count2) && (toNode->isOutputVisible(output))) {
5471 			if (dest->isInputConnected(input)) {
5472 			    // can't create the arc because someone else
5473 			    // already wired the input we wanted to use.
5474 			    output_tab_problem_detected = TRUE;
5475 			    missing_tab_count++;
5476 			} else {
5477 			    StandIn* si = toNode->getStandIn();
5478 			    ASSERT (si);
5479 			    si->addArk (this->editor,
5480 				new Ark (toNode, output, dest, input));
5481 			}
5482 		    } else {
5483 			// the tab was missing
5484 			output_tab_problem_detected = TRUE;
5485 			missing_tab_count++;
5486 		    }
5487 		}
5488 	    }
5489 	    //delete fromNode;
5490 	}
5491 	//swapFromNodes.clear();
5492 	if ((input_tab_problem_detected) || (output_tab_problem_detected)) {
5493 	    char *cp;
5494 	    if ((input_tab_problem_detected) && (!output_tab_problem_detected)) {
5495 		cp = "input";
5496 	    } else if ((!input_tab_problem_detected) && (output_tab_problem_detected)) {
5497 		cp = "output";
5498 	    } else {
5499 		cp = "input and output";
5500 	    }
5501 	    WarningMessage (
5502 		"The Undo was not completed because %d\n"
5503 		"%s tab(s) had been hidden, removed, or used",
5504 		missing_tab_count, cp);
5505 	}
5506     }
5507 
5508     for (new_l.setList(swapFromNodes); (new_node = (Node*)new_l.getNext()); )
5509     {
5510 	this->deleteNode(new_node, FALSE);
5511     }
5512     swapFromNodes.clear();
5513 
5514 
5515     this->deferrableAddNode->undeferAction();
5516 
5517     if (panels)
5518     {
5519 	//
5520 	// Resolve any instance number collisions among control panels
5521 	//
5522 	for (new_cp_l.setList(*panels);
5523 		(new_cp = (ControlPanel*)new_cp_l.getNext()); )
5524 	{
5525 	    new_cp->switchNetwork(new_net,this);
5526 	    new_net->panelList.removeElement(new_cp);
5527 	    this->addPanel(new_cp,0);
5528 	}
5529     }
5530 
5531     //
5532     // FIXME: Please write a switchNetworks() method for Decorators.
5533     //
5534     for (new_l.setList(removedDecs); (new_dec = (Decorator*)new_l.getNext());)
5535     {
5536 	DecoratorInfo* dnd = new DecoratorInfo (this, (void*)this,
5537 	    (DragInfoFuncPtr)Network::SetOwner,
5538 	    (DragInfoFuncPtr)Network::DeleteSelections,
5539 	    (DragInfoFuncPtr)Network::Select);
5540 	new_dec->setDecoratorInfo (dnd);
5541 	EditorWindow *ew = this->editor;
5542 
5543 #if WORKSPACE_PAGES
5544 	if (new_dec->getRootWidget()) {
5545 	    new_dec->unmanage();
5546 	    new_dec->uncreateDecorator();
5547 	}
5548 	if (ew) ew->newDecorator(new_dec);
5549 #else
5550 	EditorWorkSpace *ews = ew->getWorkSpace();
5551 	new_dec->manage(ews);
5552 #endif
5553 	new_net->decoratorList.removeElement((void*)new_dec);
5554 	this->addDecoratorToList ((void*)new_dec);
5555     }
5556 
5557     this->setDirty();
5558 #if WORKSPACE_PAGES
5559     if (this->editor) this->editor->endPageChange();
5560 #endif
5561     return TRUE;
5562 }
5563 
5564 //
5565 // Set the upper left hand corner of the bounding box of the network nodes
5566 // to a new position, moving all nodes the same amount
5567 //
setTopLeftPos(int x,int y)5568 void Network::setTopLeftPos(int x, int y)
5569 {
5570 Node		*node;
5571 ListIterator	l;
5572 int		minx, miny;
5573 
5574     minx = miny = 1000000;
5575     FOR_EACH_NETWORK_NODE(this, node, l)
5576     {
5577 	minx = MIN(minx, node->getVpeX());
5578 	miny = MIN(miny, node->getVpeY());
5579     }
5580     Decorator *dec;
5581     int decx, decy;
5582     FOR_EACH_NETWORK_DECORATOR(this, dec, l)
5583     {
5584 	dec->getXYPosition(&decx, &decy);
5585 	minx = MIN(minx, decx);
5586 	miny = MIN(miny, decy);
5587     }
5588     FOR_EACH_NETWORK_NODE(this, node, l)
5589     {
5590 	node->setVpePosition(node->getVpeX() - minx + x,
5591 			     node->getVpeY() - miny + y);
5592     }
5593     FOR_EACH_NETWORK_DECORATOR(this, dec, l)
5594     {
5595 	dec->getXYPosition(&decx,&decy);
5596 	dec->setXYPosition(decx-minx+x, decy-miny+y);
5597     }
5598 }
5599 
5600 //
5601 // Return the x,y coords of the south most and east most
5602 // nodes in this network.  ... used by InsertNetworkDialog so that
5603 // he can plop in a new net without having it land on top of the
5604 // existing net.  This isn't really the bounding box because
5605 // "southeast most" excludes width,height of the standin.
5606 //
getBoundingBox(int * x1,int * y1,int * x2,int * y2)5607 void Network::getBoundingBox (int *x1, int *y1, int *x2, int *y2)
5608 {
5609 int x,y;    // minima
5610 int mx,my;  // maxima
5611 boolean emptyNet = TRUE;
5612 Node		*n;
5613 ListIterator	l;
5614 
5615     mx = my = 0;
5616     x = y = 5000; // no way can we seen screen coords bigger than this
5617     FOR_EACH_NETWORK_NODE (this, n, l) {
5618         x = MIN(x, n->getVpeX());
5619         y = MIN(y, n->getVpeY());
5620         mx = MAX(mx, n->getVpeX());
5621         my = MAX(my, n->getVpeY());
5622         emptyNet = FALSE;
5623     }
5624     if (emptyNet) {
5625 	*x1 = *y1 = *x2 = *y2 = 0;
5626     } else {
5627 	*x1 = x; *y1 = y;
5628 	*x2 = mx; *y2 = my;
5629     }
5630 }
5631 
getNonEmptyPanels()5632 List *Network::getNonEmptyPanels()
5633 {
5634     List		*result = new List;
5635     ControlPanel	*cp;
5636     ListIterator	 li;
5637 
5638     //
5639     // Get rid of empty panels
5640     //
5641     FOR_EACH_NETWORK_PANEL(this, cp, li)
5642     {
5643 	// getComponentCount is InstanceCount + DecoratorCount
5644 	if(cp->getComponentCount() != 0)
5645 	{
5646 	    result->appendElement(cp);
5647 	}
5648     }
5649 
5650     return result;
5651 }
5652 
makeNamedControlPanelList(const char * name)5653 List *Network::makeNamedControlPanelList(const char *name)
5654 {
5655     ControlPanel *cp;
5656     ListIterator iterator;
5657     List        *l = NUL(List*);
5658 
5659 
5660     FOR_EACH_NETWORK_PANEL(this, cp, iterator) {
5661         if ((name == NULL) || EqualString(name, "") ||
5662 				EqualString(cp->getPanelNameString(), name))
5663         {
5664             if (!l)
5665                 l = new List;
5666             l->appendElement((const void*) cp);
5667         }
5668     }
5669     return l;
5670 }
5671 
makeLabelledNodeList(const char * label)5672 List *Network::makeLabelledNodeList(const char *label)
5673 {
5674     Node *node;
5675     ListIterator iterator;
5676     List        *l = NUL(List*);
5677 
5678     FOR_EACH_NETWORK_NODE(this, node, iterator) {
5679         if ((label == NULL) || EqualString(node->getLabelString(), label))
5680       {
5681             if (!l)
5682                 l = new List;
5683             l->appendElement((const void*) node);
5684         }
5685     }
5686     return l;
5687 }
5688 #ifndef DXD_LACKS_POPEN
5689 //
5690 // Try and start the network decoder with the given key to decode the
5691 // file given by netfile.  If the envirinment variable DXDECODER does
5692 // not contain the name of the decoder file, then use
5693 // $DXROOT/bin_$ARCH/dxdecode.
5694 // Returns a valid FILE pointer if the key can decode the network,
5695 // otherwise a NULL and error message.  This will exit under certain
5696 // conditions that might indicate someone is trying to break the
5697 // security mechanisms of encoded networks.
5698 //
5699 #if DXD_HAS_CRYPT             //CRYPTKEY
OpenForDecoding(const char * netfile,const char * key)5700 static FILE *OpenForDecoding(const char *netfile, const char *key)
5701 {
5702     char buf[1024];
5703     char cmd[1024];
5704     char envbuf[1024];
5705     FILE *f;
5706     unsigned int code;
5707     char *decoder;
5708 
5709     decoder = getenv("DXDECODER");
5710     if (!decoder) {
5711 	sprintf(buf,"%s/bin_%s/dxdecode",
5712 		theDXApplication->getUIRoot(),DXD_ARCHNAME);
5713 	decoder = buf;
5714     }
5715     sprintf(cmd,"eval \"_$$=%s\";export _$$;%s %s", key, decoder, netfile );
5716     sprintf(envbuf,"__=%d", getpid());
5717     putenv(envbuf);
5718     f = popen (cmd, "r");
5719     if (!f) {
5720         ErrorMessage("Could not start %s to decode networks", decoder);
5721 	return NULL;
5722     }
5723 
5724     putenv("__=");
5725     code = atoi(fgets(buf,80,f)); //check my pid is first thing in mesg
5726     if ( ((unsigned int)(getpid()^1234)) != code ){
5727         fprintf(stderr,"Invalid data from %s, exiting\n", decoder);
5728         exit(1);
5729     }
5730 
5731     // for now we will just check for the first / cause we can
5732     // unget this
5733 
5734     if (fgetc(f) != '/') {
5735         ErrorMessage("Incorrect key for encoded network %s: %s",
5736 					netfile , strerror(errno));
5737 	pclose(f);
5738 	f = NULL;
5739     } else {
5740 	ungetc('/',f);
5741     }
5742 
5743     return f;
5744 }
5745 #endif // DXD_HAS_CRYPT
5746 #endif // DXD_LACKS_POPEN
5747 
5748 //
5749 // Close the .net file that was opened with openNetworkFILE().
5750 //
closeNetworkFILE(FILE * f)5751 void Network::closeNetworkFILE(FILE *f)
5752 {
5753     this->CloseNetworkFILE(f,this->wasNetFileEncoded());
5754 }
CloseNetworkFILE(FILE * f,boolean wasEncoded)5755 void Network::CloseNetworkFILE(FILE *f, boolean wasEncoded)
5756 {
5757 #ifndef DXD_LACKS_POPEN
5758     if (wasEncoded)
5759 	pclose(f);
5760     else
5761 #endif
5762 	fclose(f);
5763 
5764 }
openNetworkFILE(const char * netFileName,char ** errmsg)5765 FILE *Network::openNetworkFILE(const char *netFileName,
5766 					char **errmsg)
5767 {
5768     return this->OpenNetworkFILE(netFileName, &this->netFileWasEncoded, errmsg);
5769 }
OpenNetworkFILE(const char * netFileName,boolean * wasEncoded,char ** errmsg)5770 FILE *Network::OpenNetworkFILE(const char *netFileName,
5771 					boolean *wasEncoded,
5772 					char **errmsg)
5773 {
5774 
5775     FILE *f;
5776     char errbuf[1024];
5777 #if ! DXD_HAS_CRYPT             //CRYPTKEY
5778     char *netfile = DuplicateString(netFileName);
5779     *wasEncoded = FALSE;
5780 #else
5781     char buf[1024];
5782     char cmd[1024];
5783     const char *key = theDXApplication->getCryptKey();
5784     boolean forceEncryption = theDXApplication->appForcesNetFileEncryption();
5785     char *netfile = DuplicateString(netFileName);
5786 
5787     ASSERT(wasEncoded);
5788     *wasEncoded = FALSE;
5789     errbuf[0] = '\0';
5790 
5791     if (!key && forceEncryption) {
5792 	SPRINTF(errbuf,
5793                 "%s must be provided a key to open ecnrypted program files",
5794                 theDXApplication->getInformalName());
5795 	goto error;
5796     }
5797 
5798 
5799     if (key != NULL) {
5800 
5801         // Deal with .ntz (compressed) filenames
5802 
5803         char *p = (char*)strrstr(netfile,".ntz");
5804         if (p != NULL){
5805             strcpy(p,".ntz");
5806         }
5807         else{
5808             p = (char *)strstr(netfile,".net");
5809             ASSERT(p);
5810         }
5811 
5812         f = fopen (netfile, "r");
5813 
5814         if (f == NULL)  {
5815             SPRINTF(errbuf,"Error opening file %s: %s",
5816 					netfile, strerror(errno));
5817 	    goto error;
5818         }
5819 
5820         // Determine if net is encoded by looking for #* in header
5821 
5822         if ((fread(buf,sizeof(unsigned char),2,f)) != 2) {
5823             SPRINTF(errbuf,"Error reading file %s: %s",
5824 					netfile, strerror(errno));
5825 	    goto error;
5826         }
5827 
5828         buf[2] = '\0';
5829 
5830         if (strcmp(buf,"#*") == 0) {
5831 
5832 	    fclose(f);
5833 
5834             // net is encrypted lets see if our key is good.
5835 
5836 	    f = OpenForDecoding(netfile, key);
5837 
5838 	    if (f)
5839 		*wasEncoded = TRUE;
5840         } else if (forceEncryption) {
5841 	    SPRINTF(errbuf,"Network file %s must be encoded", netfile);
5842 	    goto error;
5843 	} else {
5844             fseek(f,0,0);
5845 	}
5846     } else
5847 #endif
5848 	f = fopen (netfile, "r");
5849 
5850 
5851     if (f == NULL)  {
5852         SPRINTF(errbuf,"Error opening file %s: %s", netfile, strerror(errno));
5853 	goto error;
5854     }
5855 
5856     delete[] netfile;
5857     return f;
5858 
5859 error:
5860     if (netfile) delete netfile;
5861     if (errbuf[0]) {
5862 	if (errmsg)
5863 	   *errmsg = DuplicateString(errbuf);
5864 	else
5865 	    ErrorMessage(errbuf);
5866     }
5867     return NULL;
5868 
5869 }
5870 
5871 #ifdef DXUI_DEVKIT
5872 //
5873 // Print the visual program as a .c file that uses libDX calls.
5874 // If the filename does not have a '.c' extension, one is added.
5875 // An error message is printed if there was an error.
5876 //
saveAsCCode(const char * filename)5877 boolean Network::saveAsCCode(const char *filename)
5878 {
5879     const char *p = strrstr(filename,".c");
5880     char *nf;
5881 
5882     if (!p) p = strrstr(filename,".C");
5883 
5884     if (!p) {
5885 	nf = new char[STRLEN(filename) + 3];
5886 	sprintf(nf,"%s.c",filename);
5887     } else {
5888 	nf = (char*)filename;
5889     }
5890 
5891     FILE *f = fopen(nf,"w");
5892     boolean rcode;
5893     if (f) {
5894 	rcode = this->printAsCCode(f);
5895 	fclose(f);
5896 	if (!rcode) {
5897 	    ErrorMessage("Error printing file to %s\n",nf);
5898 	    unlink(nf);
5899 	}
5900     } else {
5901 	ErrorMessage("Could not open file %s for writing\n",nf);
5902 	rcode = FALSE;
5903     }
5904     if (nf != filename) delete nf;
5905 
5906     return rcode;
5907 }
5908 //
5909 // Print the visual program as a .c file that uses libDX calls.
5910 // An error message is printed if there was an error.
5911 //
printAsCCode(FILE * f)5912 boolean Network::printAsCCode(FILE *f)
5913 {
5914     Node *n;
5915     ListIterator l;
5916     const char *unsup_tools[] = { "Switch", "Route", "Colormap", "Transmitter",
5917 				  "Image", "Receiver", "Sequencer", NULL };
5918     const char *unsup_nodeclass[] = { "InteractorNode", "ProbeNode", NULL };
5919     const char **p;
5920 
5921     if (this->isMacro()) {
5922 	ErrorMessage("Can not generate C code from macros");
5923 	return FALSE;
5924     }
5925 
5926     for (p = unsup_tools ; *p ; p++) {
5927 	List *list = this->makeNamedNodeList(*p);
5928 	if (list) {
5929 	    ErrorMessage("Can not generate C code from programs containing"
5930 			" %s tools",*p);
5931 	    delete list;
5932 	    return FALSE;
5933 	}
5934     }
5935 
5936     for (p = unsup_nodeclass ; *p ; p++) {
5937 	List *list = this->makeClassifiedNodeList(*p);
5938 	if (list) {
5939 	    Node *n = (Node*)list->getElement(1);
5940 	    ErrorMessage("Can not generate C code from programs containing"
5941 			" %s tools",n->getNameString());
5942 	    delete list;
5943 	    return FALSE;
5944 	}
5945     }
5946 
5947     if (this->editor && this->isDirty())
5948 	this->sortNetwork();
5949 
5950     this->resetImageCount();
5951 
5952     if (fprintf(f,"#include \"dx/dx.h\"\n\n"
5953 		  "%s()\n{\n"
5954 		  "\n",
5955 		this->getNameString()) <= 0)
5956 	return FALSE;
5957 
5958     FOR_EACH_NETWORK_NODE(this, n, l)
5959     {
5960 	if (!n->beginDXCallModule(f))
5961 	    return FALSE;
5962     }
5963 
5964     fprintf(f, "\n    DXInitModules();\n\n");
5965 
5966     FOR_EACH_NETWORK_NODE(this, n, l)
5967     {
5968 	if (!n->callDXCallModule(f))
5969 	    return FALSE;
5970     }
5971 
5972     // Include a semi-colon statement incase no statements follow
5973     if (fprintf(f,"\n\nerror: ;\n\n") <= 0)
5974 	return FALSE;
5975 
5976     FOR_EACH_NETWORK_NODE(this, n, l)
5977     {
5978 	if (!n->endDXCallModule(f))
5979 	    return FALSE;
5980     }
5981 
5982     if (fprintf(f,"\n}\n") <= 0)
5983 	return FALSE;
5984 
5985     return TRUE;
5986 
5987 }
5988 #endif	// DXUI_DEVKIT
5989 
5990 //
5991 // This is a help function for optimizeNodeOutputCacheability() that
5992 // returns a list of Nodes that are connected to the given output of the
5993 // given node.  This would be trivial, except for Transmitters and Receivers,
5994 // In which case we need to traverse all Receivers for a given Transmitter
5995 // and all output arcs for each receiver.
5996 // If destList is given, then we append the Nodes to that list, otherwise we
5997 // allocate one internally.  In either case, we return a list.  In the latter
5998 // case, the user should delete the returned list.
5999 //
GetDestinationNodes(Node * src,int output_index,List * destList,boolean recvrsOk)6000 List *Network::GetDestinationNodes(Node *src, int output_index,
6001 				List *destList, boolean recvrsOk)
6002 {
6003     Ark *a;
6004 
6005     if (!destList)
6006 	destList = new List;
6007 
6008     List *arcs = (List *)src->getOutputArks(output_index);
6009 
6010     ListIterator iter(*arcs);
6011     while ( (a = (Ark*)iter.getNext()) ) {
6012 	int paramInd;
6013 	Node *dest = a->getDestinationNode(paramInd);
6014 	const char *destClassName = dest->getClassName();
6015 	if (EqualString(destClassName,ClassTransmitterNode)) {
6016 	    //
6017 	    // This is a Transmitter, so get a list of all the Receivers.
6018 	    //
6019 	    List *recvrs = Network::GetDestinationNodes(dest,1,NULL, TRUE);
6020 	    if (recvrs) {
6021 		//
6022 		// For each Receiver, find the connected nodes.
6023 		//
6024 		ListIterator iter(*recvrs);
6025 		Node *rcvr;
6026 		while ( (rcvr = (Node*)iter.getNext()) ) {
6027 		    ASSERT(EqualString(rcvr->getClassName(),ClassReceiverNode));
6028 		    Network::GetDestinationNodes(rcvr,1,destList);
6029 		}
6030 		delete recvrs;
6031 	    }
6032 	} else {
6033 	    ASSERT(recvrsOk || !EqualString(destClassName,ClassReceiverNode));
6034 	    if (!destList->isMember((void*)dest))
6035 		destList->appendElement((void*)dest);
6036 	}
6037     }
6038 
6039     return destList;
6040 
6041 }
6042 //
6043 // Optimally set the output cacheability of all nodes within the network.
6044 // We only operate on those that have writable cacheability.
6045 //
optimizeNodeOutputCacheability()6046 void Network::optimizeNodeOutputCacheability()
6047 {
6048     ListIterator iterator;
6049     Node        *src;
6050     EditorWindow *editor = this->getEditor();
6051 
6052     //
6053     // Need to check destination nodes to see if they're driven.
6054     //
6055     Symbol driven_sym =
6056 	theSymbolManager->registerSymbol(ClassDrivenNode);
6057 
6058     iterator.setList(this->nodeList);
6059     while ( (src = (Node*)iterator.getNext()) ) {
6060 	int i, ocnt = src->getOutputCount();
6061  	if (editor)
6062 	    editor->selectNode(src,FALSE,FALSE);
6063 	//
6064 	// Don't bother with Transmitters or Receivers
6065 	//
6066 	const char *srcClassName = src->getClassName();
6067 	if (EqualString(srcClassName,ClassTransmitterNode) ||
6068 	    EqualString(srcClassName,ClassReceiverNode))
6069 	    continue;
6070 
6071 	//
6072 	// Follow each output arc to see if we need to cache this output
6073 	//
6074 	for (i=1 ; i<=ocnt ; i++) {		// For each node output
6075 	    boolean cache_output = FALSE;
6076 	    if (src->isOutputCacheabilityWriteable(i) == FALSE) continue;
6077 
6078 	    if (src->isOutputConnected(i)) { // If the output is connected
6079 		Node *dest;
6080 		List dests;
6081 		Network::GetDestinationNodes(src,i,&dests);
6082 		ListIterator destIter(dests);
6083 		while (!cache_output && (dest = (Node*)destIter.getNext())) {
6084 		    //
6085 		    // If the destination node does not have any outputs,
6086 		    // is a side-effect module or is the Image tool, then
6087 		    // cache this output (i.e. cache all outputs that
6088 		    // feed modules without any outputs).
6089 		    //
6090 		    if ((dest->getOutputCount() == 0) ||
6091 			EqualString(dest->getClassName(), ClassImageNode) ||
6092 			dest->getDefinition()->isMDFFlagSIDE_EFFECT()) {
6093 			cache_output = TRUE;
6094 			break;
6095 		    }
6096 		    //
6097 		    // If the destination node is a looping tool, then cache this
6098 		    // output.  Looping tools will request their inputs each time
6099 		    // thru the loop.
6100 		    //
6101 		    if (dest->getDefinition()->isMDFFlagLOOP()) {
6102 			cache_output = TRUE;
6103 			break;
6104 		    }
6105 
6106 		    //
6107 		    // If the destination node is a macro, then cache this output.
6108 		    // Some macros run every time but we don't which ones.  It would
6109 		    // be better to turn on caching only preceeding those macros
6110 		    // which are side-effect but we don't have that information.
6111 		    //
6112 		    if (dest->isA(ClassMacroNode)) {
6113 			cache_output = TRUE;
6114 			break;
6115 		    }
6116 
6117 		    //
6118 		    // If this output feeds a DrivenNode then cache this output.
6119 		    // Reason:  In spite of the cache setting on the DrivenNode,
6120 		    // the module will check its inputs for changes in order to
6121 		    // determine if it must run.  To allow it to check we had better
6122 		    // cache this output.
6123 		    // But, doesn't the input value affect the behavior of a driven
6124 		    // node?  And what does caching on Receivers mean?
6125 		    //
6126 		    if (dest->isA(driven_sym)) {
6127 			cache_output = TRUE;
6128 			break;
6129 		    }
6130 
6131 		    //
6132 		    // If this output feeds a module that takes input from
6133 		    // other than this module, then cache this output.
6134 		    //
6135 		    int  k;
6136 		    for (k=1 ; !cache_output && k<=dest->getInputCount() ; k++){
6137 			Ark *a2;
6138 			List *dest_in_arcs = (List*)dest->getInputArks(k);
6139 			ListIterator iter(*dest_in_arcs);
6140 			while ( (a2 = (Ark*)iter.getNext()) ) {
6141 		    	    int paramInd;
6142 			    Node *inode = a2->getSourceNode(paramInd);
6143 			    if (src != inode) {
6144 				//
6145 				// Cache the output if this input is not
6146 				// connected to a Receiver that is connect
6147 				// to the src node directly from the
6148 				// corresponding Transmitter.
6149 				//
6150 				cache_output =
6151 					!EqualString(inode->getClassName(),
6152 							ClassReceiverNode) ||
6153 					((ReceiverNode*)inode)->
6154 						getUltimateSourceNode() != src;
6155 				break;
6156 			    }
6157 			}
6158 		    }
6159 		}
6160 	    }
6161 	    //
6162 	    // I moved the cache setting outside the loop.  Meaning: turn off caching
6163 	    // for outputs which aren't connected.
6164 	    //
6165 	    if (cache_output) {
6166 		src->setOutputCacheability(i,OutputFullyCached);
6167 		if (editor)
6168 		    editor->selectNode(src,TRUE,FALSE);
6169 	    } else
6170 		src->setOutputCacheability(i,OutputNotCached);
6171 	}
6172     }
6173 
6174 }
6175 Decorator* Network::lastObjectParsed = NUL(Decorator*);
6176 //
6177 // Parse the 'decorator' comments in the .net file.
6178 //
6179 //
6180 // Parse the 'resource' comments in the .net file for DynamicResource
6181 // ControlPanel saves state in order to handle resource comments because
6182 // each DynamicResource must belong to a decorator or interactor and it will
6183 // always be the most recently parsed decorator or interactor.
6184 //
parseDecoratorComment(const char * comment,const char * filename,int lineno)6185 boolean Network::parseDecoratorComment (const char *comment,
6186 				const char *filename, int lineno)
6187 {
6188 int items_parsed;
6189 char decoType[128];
6190 char stylename[128];
6191 
6192     ASSERT(comment);
6193 
6194     if ((strncmp(" decorator",comment,10))&&
6195 	(strncmp(" resource",comment,9))&&
6196 	(strncmp(" annotation",comment,11))&&
6197 	(!strstr(comment, " group:")))
6198 	return FALSE;
6199 
6200     // The following is a special case for stateful resource comments.
6201     // Currently they are associated only with Decorators but that
6202     // will change.
6203 	if (!strncmp(" resource",comment,9)) {
6204 		if (!lastObjectParsed)
6205 			return FALSE;
6206 		return lastObjectParsed->parseResourceComment (comment, filename, lineno);
6207 	} else if (!strncmp(" annotation", comment, 11)) {
6208 		if (!lastObjectParsed)
6209 			return FALSE;
6210 		return lastObjectParsed->parseComment (comment, filename, lineno);
6211 	}
6212 
6213 #if WORKSPACE_PAGES
6214 	if (strstr(comment, " group:"))   {
6215 		int i;
6216 		int count = this->groupManagers->getSize();
6217 		boolean group_comment = FALSE;
6218 		GroupManager *gmgr = NUL(GroupManager*);
6219 		for (i=1; i<=count; i++) {
6220 			gmgr = (GroupManager*)this->groupManagers->getDefinition(i);
6221 			const char *mgr_name = gmgr->getManagerName();
6222 			char buf[128];
6223 			sprintf (buf, " %s group:", mgr_name);
6224 			if (EqualSubstring (buf, comment, strlen(buf))) {
6225 				group_comment = TRUE;
6226 				break;
6227 			}
6228 		}
6229 		if (group_comment)
6230 			return lastObjectParsed->parseComment (comment, filename, lineno);
6231 	}
6232 #endif
6233 
6234 
6235     //
6236     // Decorator comments in 3.2 and earlier included only a stylename and not
6237     // the the pair: stylen name / type name.  You need both to handle a look up
6238     // in a dictionary of dictionaries (which is what DecoratorStyle is).  Prior
6239     // to 3.2 stylename was always equal to its dictionary key string and there
6240     // was only 1 style for each type.
6241     //
6242     int junk;
6243     boolean parsed = FALSE;
6244     items_parsed =
6245 	sscanf (comment, " decorator %[^\t]\tpos=(%d,%d) size=%dx%d style(%[^)])",
6246 	    stylename, &junk,&junk,&junk,&junk, decoType);
6247     if (items_parsed == 6) {
6248 	parsed = TRUE;
6249     } else {
6250 	items_parsed =
6251 
6252 // See Decorator::parseComment for an explanation
6253 #ifndef ERASE_ME
6254 	    sscanf (comment, " decorator %[^\t]\tstyle(%[^)]", stylename, decoType);
6255 #else
6256 	    0;
6257 #endif
6258 	if (items_parsed == 2) {
6259 	    parsed = TRUE;
6260 	} else {
6261 	    items_parsed = sscanf(comment, " decorator %[^\t]", stylename);
6262 	    if (items_parsed == 1)
6263 		parsed = TRUE;
6264 	}
6265     }
6266 
6267 
6268 	Dictionary *dict;
6269 	DecoratorStyle *ds;
6270 	if (!parsed) {
6271 		ErrorMessage("Unrecognized 'decorator' comment (file %s, line %d)",
6272 			filename, lineno);
6273 		return FALSE;
6274 	}
6275 	dict = DecoratorStyle::GetDecoratorStyleDictionary (stylename);
6276 	DictionaryIterator di(*dict);
6277 
6278 	if (items_parsed == 1) {
6279 		ds = (DecoratorStyle *)di.getNextDefinition();
6280 		if (!ds) {
6281 			ErrorMessage("Unrecognized 'decorator' type (file %s, line %d)",
6282 				filename, lineno);
6283 			return FALSE;
6284 		}
6285 	} else {
6286 		while ( (ds = (DecoratorStyle*)di.getNextDefinition()) ) {
6287 			if (EqualString (decoType, ds->getNameString())) {
6288 				break;
6289 			}
6290 		}
6291 		if (!ds) {
6292 			ErrorMessage("Unrecognized 'decorator' type (file %s, line %d)",
6293 				filename, lineno);
6294 
6295 			di.setList(*dict);
6296 			ds = (DecoratorStyle*)di.getNextDefinition();
6297 			if (!ds) return FALSE;
6298 		}
6299 	}
6300 
6301 	ASSERT(ds);
6302 	Decorator *d;
6303 	d = ds->createDecorator (TRUE);
6304 	d->setStyle (ds);
6305 	DecoratorInfo* dnd = new DecoratorInfo (this, (void*)this,
6306 		(DragInfoFuncPtr)Network::SetOwner,
6307 		(DragInfoFuncPtr)Network::DeleteSelections,
6308 		(DragInfoFuncPtr)Network::Select);
6309 	d->setDecoratorInfo (dnd);
6310 
6311 	if (!d->parseComment (comment, filename, lineno))
6312 		ErrorMessage("Unrecognized 'decorator' comment (file %s, line %d)",
6313 		filename, lineno);
6314 
6315 	this->addDecoratorToList ((void *)d);
6316 	lastObjectParsed = d;
6317 
6318 	return TRUE;
6319 }
6320 
SetOwner(void * b)6321 void Network::SetOwner(void *b)
6322 {
6323 Network *netw = (Network*)b;
6324     netw->setCPSelectionOwner(NUL(ControlPanel*));
6325 }
6326 
DeleteSelections(void * b)6327 void Network::DeleteSelections(void *b)
6328 {
6329 Network *netw = (Network*)b;
6330 Command *cmd = netw->editor->getDeleteNodeCmd();
6331 
6332     cmd->execute();
6333 }
6334 
Select(void * b)6335 void Network::Select(void *b)
6336 {
6337 Network *netw = (Network*)b;
6338     if (netw->editor) netw->editor->handleDecoratorStatusChange();
6339 }
6340 
6341 //
6342 // Do a recursive depth-first search of this network for macro nodes.
6343 // and append their MacroDefinitions to the given list.  The list will
6344 // come back in depth-first order and will NOT contain duplicates.
6345 // This has the side effect of loading the network bodies for all the
6346 // returned MacroDefinitions.
6347 //
getReferencedMacros(List * macros,List * visited)6348 void Network::getReferencedMacros(List *macros, List *visited)
6349 {
6350     List *l = this->makeClassifiedNodeList(ClassMacroNode, FALSE);
6351 
6352     if (l) {
6353 	MacroNode *mn;
6354 	boolean wasVisitNull;
6355 	if (!visited) {
6356 	    visited = new List();
6357 	    wasVisitNull = TRUE;
6358 	} else
6359 	    wasVisitNull = FALSE;
6360 
6361 	ListIterator iter(*l);
6362 	while ( (mn = (MacroNode*)iter.getNext()) ) {
6363 	    MacroDefinition *md = (MacroDefinition*)mn->getDefinition();
6364 	    //
6365 	    // Search all unvisited macros for other macros
6366 	    //
6367 	    if (!visited->isMember((void*)md)) {
6368 		visited->appendElement((void*)md);
6369 		md->loadNetworkBody();
6370 		Network *md_network = md->getNetwork();;
6371 		md_network->getReferencedMacros(macros,visited);
6372 	    }
6373 	    //
6374 	    // If this macro wasn't found yet, put it on the end of the list.
6375 	    //
6376 	    if (!macros->isMember((void*)md))
6377 		macros->appendElement((void*)md);
6378 	}
6379 
6380 	if (wasVisitNull)
6381 	    delete visited;
6382 
6383 	delete l;
6384     }
6385 
6386 }
6387 //
6388 // Print comments and 'include' statements for the macros that are
6389 // referenced in this network.  If nested is TRUE, then we don't print
6390 // the 'include' statements.  Return TRUE on sucess or FALSE on failure.
6391 //
printMacroReferences(FILE * f,boolean inline_define,PacketIFCallback echoCallback,void * echoClientData)6392 boolean Network::printMacroReferences(FILE *f, boolean inline_define,
6393 			PacketIFCallback echoCallback, void *echoClientData)
6394 
6395 {
6396 
6397     List *l = this->makeClassifiedNodeList(ClassMacroNode);
6398 
6399 
6400     if (l) {
6401 
6402 	MacroNode *mn;
6403 	const char *comment_type;
6404 
6405 	if (inline_define)
6406 	    comment_type = "definition";
6407 	else
6408 	    comment_type = "location ";
6409 
6410 	ListIterator iter(*l);
6411 	List topLevelMacros;
6412 	MacroDefinition *md;
6413 	while ( (mn = (MacroNode*)iter.getNext()) )  {
6414 	    md = (MacroDefinition*)mn->getDefinition();
6415 	    topLevelMacros.appendElement((void*)md);
6416 	}
6417 
6418 	List refMacros;
6419 	this->getReferencedMacros(&refMacros);
6420 
6421 	iter.setList(refMacros);
6422 	while ( (md = (MacroDefinition*)iter.getNext()) ) {
6423 	    boolean top;
6424     	    char s[1024];
6425 	    md->loadNetworkBody();
6426 	    Network *md_net = md->getNetwork();
6427 	    const char *name = md->getNameString();
6428 	    char *path = (char*)md_net->getFileName();
6429 	    path = GetFullFilePath(path);
6430 
6431 	    ASSERT(name && path);
6432 
6433 	    if (topLevelMacros.isMember((void*)md))
6434 		top = TRUE;
6435 	    else
6436 		top = FALSE;
6437 
6438 	    if (inline_define)
6439 		comment_type = "definition";
6440 	    else if (top)
6441 		comment_type = "reference (direct)";
6442 	    else
6443 		comment_type = "reference (indirect)";
6444 
6445 	    SPRINTF(s,
6446 		"//\n"
6447 //		"// macro reference: %s first referenced (%s) by macro %s\n"
6448 		"// macro %s: %s %s\n",
6449 //				name, ref_kind,this->getNameString(),
6450 				comment_type, name, path);
6451 
6452 	    if (!inline_define && top) {
6453 	        char *basename = GetFileBaseName(path,NULL);
6454 		ASSERT(basename);
6455 		char s2[1024];
6456 		SPRINTF(s2, "include \"%s\"\n", basename);
6457 		strcat(s,s2);
6458 		delete basename;
6459 	    }
6460 	    delete path;
6461 
6462 	    if (fputs(s, f) < 0)
6463 		goto error;
6464 	    if (echoCallback)
6465 		(*echoCallback)(echoClientData, s);
6466 
6467 	    //
6468 	    // Now print the inline definition if requested.
6469 	    //
6470 	    if (inline_define && !md_net->printNetwork(f, PrintFile))
6471 		goto error;
6472 	}
6473 	delete l;
6474 
6475 	if (fputs("//\n", f) < 0)
6476 	    goto error;
6477     }
6478 
6479     return TRUE;
6480 
6481 error:
6482     if (l)
6483 	delete l;
6484     return FALSE;
6485 }
6486 
6487 //
6488 // See if the given label is unique among nodes requiring uniqueness.
6489 // Return a node's type name if there is a conflict, 0 otherwise.
6490 // (So that the caller can produce a decent error message)
6491 //
nameConflictExists(UniqueNameNode * passed_in,const char * label)6492 const char * Network::nameConflictExists (UniqueNameNode *passed_in, const char *label)
6493 {
6494     List* cnl = this->makeClassifiedNodeList (ClassUniqueNameNode);
6495     if (cnl) {
6496 	ListIterator it(*cnl);
6497 	UniqueNameNode* existing;
6498 	while ( (existing = (UniqueNameNode*)it.getNext()) ) {
6499 	    if ((passed_in != existing) &&
6500 		(passed_in->namesConflict
6501 		    (existing->getUniqueName(), label, existing->getClassName()))) {
6502 		delete cnl;
6503 		return existing->getNameString();
6504 	    }
6505 	}
6506 	delete cnl;
6507     }
6508 
6509     //
6510     // Do the loop over again in order to account for DXLOutputs.  They aren't
6511     // ClassUniqueNameNodes because they're DrivenNodes.
6512     //
6513     cnl = this->makeClassifiedNodeList (ClassDXLOutputNode, FALSE);
6514     if (cnl) {
6515 	ListIterator it(*cnl);
6516 	Node* existing;
6517 	while ( (existing = (Node*)it.getNext()) ) {
6518 	    if (passed_in->namesConflict
6519 		(existing->getLabelString(), label, existing->getClassName())) {
6520 		delete cnl;
6521 		return existing->getNameString();
6522 	    }
6523 	}
6524 	delete cnl;
6525     }
6526 
6527     return NUL(char*);
6528 }
6529 
6530 
nameConflictExists(const char * label)6531 const char * Network::nameConflictExists (const char *label)
6532 {
6533     List* cnl = this->makeClassifiedNodeList (ClassUniqueNameNode);
6534     if (cnl) {
6535 	ListIterator it(*cnl);
6536 	UniqueNameNode* existing;
6537 	while ( (existing = (UniqueNameNode*)it.getNext()) ) {
6538 	    if (existing->namesConflict
6539 		    (existing->getUniqueName(), label, ClassDXLOutputNode)) {
6540 		delete cnl;
6541 		return existing->getNameString();
6542 	    }
6543 	}
6544 	delete cnl;
6545     }
6546 
6547     return NUL(char*);
6548 }
6549 
6550 //
6551 // Called by ReceiverNode during parsing.  Scenario:  an old network has a name
6552 // conflict between Transmitter/Receiver pair on one hand, and Input,Output,of
6553 // DXLinkInput on the other hand.  Such a Receiver would mark the transmitter for
6554 // fixup which must be done after the network has been read in so that connections
6555 // among Transmitter/Reciever(s) aren't lost.  The corollary to marking them for
6556 // fixup is calling renameTransmitters().  That method is called after reading
6557 // is finished.  This code was added because the ui has become more restrictive
6558 // about naming things which use user supplied names in code generation.  This
6559 // lets existing nets which were created before these new restrictions, live on.
6560 //
fixupTransmitter(TransmitterNode * tn)6561 void Network::fixupTransmitter(TransmitterNode* tn)
6562 {
6563     if (!Network::RenameTransmitterList)
6564 	Network::RenameTransmitterList = new List;
6565 
6566     if (Network::RenameTransmitterList->isMember(tn)) return ;
6567 
6568     Network::RenameTransmitterList->appendElement((const void*)tn);
6569 }
6570 
renameTransmitters()6571 void Network::renameTransmitters()
6572 {
6573 
6574     if (!Network::RenameTransmitterList) return ;
6575     int size = Network::RenameTransmitterList->getSize();
6576     if (!size) return ;
6577 
6578     //
6579     // Form a reasonable warning message.
6580     //
6581     char* msg = new char[(size+1)*256];
6582     char tbuf[128];
6583     int offs = 0;
6584     if (size > 1) {
6585 	if (this->isMacro())
6586 	    sprintf (msg,
6587 		"The following Transmitters in macro %s\n"
6588 		"were renamed due to name conflicts:", this->getNameString());
6589 	else
6590 	    strcpy(msg, "The following Transmitters were renamed due to name conflicts:");
6591 	offs = strlen(msg);
6592     }
6593 
6594     ListIterator it(*Network::RenameTransmitterList);
6595     TransmitterNode* tn;
6596     while ( (tn = (TransmitterNode*)it.getNext()) ) {
6597 	char new_name[128];
6598 	sprintf (new_name, "%s_xcvr", tn->getLabelString());
6599 	if (size == 1) {
6600 	    if (this->isMacro())
6601 		sprintf (msg, "Transmitter \"%s\" in macro %s was\n"
6602 			      "renamed \"%s\" due to a name conflict.",
6603 		    tn->getLabelString(), this->getNameString(), new_name);
6604 	    else
6605 		sprintf(msg,
6606 		    "Transmitter \"%s\" was renamed \"%s\"\ndue to a name conflict.",
6607 		    tn->getLabelString(), new_name);
6608 	} else {
6609 	    sprintf (tbuf, "\n   \"%s\" is now \"%s\"", tn->getLabelString(), new_name);
6610 	    strcpy (&msg[offs], tbuf);
6611 	    offs+= strlen(tbuf);
6612 	}
6613 
6614 	tn->setLabelString(new_name);
6615     }
6616 
6617     this->setDirty();
6618 
6619     this->addEditorMessage(msg);
6620     delete msg;
6621     Network::RenameTransmitterList->clear();
6622 }
6623 
addEditorMessage(const char * msg)6624 void Network::addEditorMessage (const char* msg)
6625 {
6626     if (!this->editorMessages)
6627 	this->editorMessages = new List;
6628     if (this->editor) {
6629 	InfoMessage (msg);
6630     } else {
6631 	char* cp = DuplicateString(msg);
6632 	this->editorMessages->appendElement((void*)cp);
6633     }
6634 }
6635 
showEditorMessages()6636 void Network::showEditorMessages ()
6637 {
6638     if (!this->editorMessages) return ;
6639 
6640     boolean notify = theDXApplication->appAllowsSavingNetFile(this);
6641 
6642     ListIterator it(*this->editorMessages);
6643     char* msg;
6644     while ( (msg = (char*)it.getNext()) ) {
6645 	if (notify) InfoMessage (msg);
6646 	delete msg;
6647     }
6648     this->editorMessages->clear();
6649 }
6650 
addDecoratorToList(void * e)6651 void Network::addDecoratorToList (void* e)
6652 {
6653     this->decoratorList.appendElement(e);
6654     this->setFileDirty();
6655     if (this->readingNetwork == FALSE);
6656 	this->changeExistanceWork(NUL(Node*), TRUE);
6657 }
6658 
removeDecoratorFromList(void * e)6659 void Network::removeDecoratorFromList (void* e)
6660 {
6661     this->decoratorList.removeElement(e);
6662     this->setFileDirty();
6663     this->changeExistanceWork(NUL(Node*), FALSE);
6664 }
6665 
copyGroupInfo(Node * src,Node * dest)6666 void Network::copyGroupInfo (Node* src, Node* dest)
6667 {
6668     List destList;
6669     destList.appendElement((void*)dest);
6670     this->copyGroupInfo(src, &destList);
6671 }
6672 
copyGroupInfo(Node * src,List * destList)6673 void Network::copyGroupInfo (Node* src, List* destList)
6674 {
6675     Dictionary* group_mgrs = this->getGroupManagers();
6676     DictionaryIterator di(*group_mgrs);
6677     GroupManager* gmgr = NUL(GroupManager*);
6678     GroupRecord* grec = NUL(GroupRecord*);
6679     while ( (gmgr = (GroupManager*)di.getNextDefinition()) ) {
6680 	Symbol gmgr_sym = gmgr->getManagerSymbol();
6681 	const char* group_name = src->getGroupName(gmgr_sym);
6682 	ListIterator it(*destList);
6683 	Node* n;
6684 	while ( (n = (Node*)it.getNext()) ) {
6685 	    grec = gmgr->getGroup(group_name);
6686 	    n->setGroupName(grec, gmgr_sym);
6687 	}
6688     }
6689 }
6690 
6691 
6692 //
6693 // If any Node in the list has an arc to any Node not in the list,
6694 // then break the arc, replacing it with Transmitter,Receiver.
6695 //
chopArks(List * selected,Dictionary * tmits,Dictionary * rcvrs)6696 boolean Network::chopArks(List* selected, Dictionary* tmits, Dictionary* rcvrs)
6697 {
6698 int i,j;
6699 
6700     ListIterator it(*selected);
6701     Node* seln;
6702     while ( (seln = (Node*)it.getNext()) ) {
6703 	//
6704 	// Chop input arcs
6705 	//
6706 	int count = seln->getInputCount();
6707 	for (i=1; i<=count; i++) {
6708 	    List* orig = (List*)seln->getInputArks(i);
6709 	    if ((orig == NUL(List*)) || (orig->getSize() == 0)) continue;
6710 	    List* conns = orig->dup();
6711 	    int acnt = conns->getSize();
6712 	    ASSERT (acnt == 1);
6713 	    Ark* a = (Ark*)conns->getElement(1);
6714 	    int pno;
6715 	    Node* src = a->getSourceNode(pno);
6716 	    if (selected->isMember(src) == FALSE)
6717 		this->chopInputArk (seln, i, tmits, rcvrs);
6718 	    delete conns;
6719 	}
6720 
6721 	//
6722 	// Chop output arcs
6723 	//
6724 	count = seln->getOutputCount();
6725 	for (i=1; i<=count; i++) {
6726 	    List* orig = (List*)seln->getOutputArks(i);
6727 	    if ((orig == NUL(List*)) || (orig->getSize() == 0)) continue;
6728 	    List* conns = orig->dup();
6729 	    int acnt = conns->getSize();
6730 	    for (j=1; j<=acnt; j++) {
6731 		Ark* a = (Ark*)conns->getElement(j);
6732 		int pno;
6733 		Node* dest = a->getDestinationNode(pno);
6734 		if (selected->isMember(dest) == FALSE)
6735 		    this->chopInputArk (dest, pno, tmits, rcvrs);
6736 	    }
6737 	    delete conns;
6738 	}
6739     }
6740     Node* n;
6741     DictionaryIterator di;
6742     di.setList(*rcvrs);
6743     while ( (n = (Node*)di.getNextDefinition()) )
6744        this->addNode(n);
6745 
6746     return TRUE;
6747 }
6748 
chopInputArk(Node * n,int pno,Dictionary * tmits,Dictionary * rcvrs)6749 boolean Network::chopInputArk (Node* n, int pno, Dictionary* tmits, Dictionary* rcvrs)
6750 {
6751 int vpex_src, vpey_src;
6752 int vpex_dest, vpey_dest;
6753 char newname[64];
6754 char tmp[64];
6755 int dummy;
6756 
6757     //
6758     // Receivers have input arcs but they're not visible so
6759     // we don't chop them.  Transmitters have output arcs which
6760     // likewise aren't visible so we don't chop them either.
6761     //
6762     if ((n->isA(ClassReceiverNode)) && (pno == 1))
6763 	return TRUE;
6764 
6765     NodeDefinition* tmit_nd = (NodeDefinition*)
6766 	theNodeDefinitionDictionary->findDefinition("Transmitter");
6767     ASSERT(tmit_nd);
6768     NodeDefinition* rcvr_nd = (NodeDefinition*)
6769 	theNodeDefinitionDictionary->findDefinition("Receiver");
6770     ASSERT(rcvr_nd);
6771 
6772     ASSERT (pno <= n->getInputCount());
6773     List* orig = (List*)n->getInputArks(pno);
6774     if ((orig == NUL(List*)) || (orig->getSize()==0)) return TRUE;
6775     int acnt = orig->getSize();
6776     ASSERT (acnt <= 1);
6777 
6778     int src_pno;
6779     Ark* a = (Ark*)orig->getElement(1);
6780     Node* src = a->getSourceNode(src_pno);
6781     delete a;
6782     src->getVpePosition(&vpex_src, &vpey_src);
6783     n->getVpePosition(&vpex_dest, &vpey_dest);
6784     int minx = MIN(vpex_src, vpex_dest);
6785     int maxx = MAX(vpex_src, vpex_dest);
6786     int diffx = maxx - minx;
6787     int diffy = vpey_dest - vpey_src;
6788 
6789     src->getOutputNameString(src_pno, tmp);
6790     sprintf (newname, "%s_%ld_%s", src->getNameString(),
6791 	src->getInstanceNumber(), tmp);
6792 
6793     Node* tmit = (Node*)tmits->findDefinition(newname);
6794     const char* actual_name = newname;
6795 
6796     //
6797     // If the src/param already has a transmitter
6798     // then we don't need to make another one.
6799     //
6800     if (tmit == NUL(Node*)) {
6801 	List* orig = (List*)src->getOutputArks(src_pno);
6802 	if ((orig) && (orig->getSize())) {
6803 	    ListIterator oi(*orig);
6804 	    Ark* a;
6805 	    while ( (a = (Ark*)oi.getNext()) ) {
6806 		Node* dest = a->getDestinationNode(dummy);
6807 		if (dest->isA(ClassTransmitterNode) == FALSE) continue;
6808 		tmit = dest;
6809 		break;
6810 	    }
6811 	}
6812     }
6813 
6814     if (tmit == NUL(Node*)) {
6815 	//
6816 	// If the src/param is already a receiver, then we
6817 	// don't need to make a new transmitter.
6818 	//
6819 	if (src->isA(ClassReceiverNode)) {
6820 	    actual_name = src->getLabelString();
6821 	} else {
6822 	    tmit = tmit_nd->createNewNode(this);
6823 	    tmits->addDefinition(newname, tmit);
6824 	    if ((diffy > 0) && (diffy < 140) && (diffx < 180))
6825 		tmit->setVpePosition(vpex_src+100, vpey_src + 80);
6826 	    else
6827 		tmit->setVpePosition(vpex_src, vpey_src + 80);
6828 	    tmit->setLabelString (newname);
6829 	    actual_name = tmit->getLabelString();
6830 	    this->copyGroupInfo(src, tmit);
6831 	    new Ark (src, src_pno, tmit, 1);
6832 	    this->addNode(tmit);
6833 	}
6834     } else {
6835 	actual_name = tmit->getLabelString();
6836     }
6837 
6838     Node* rcvr = (Node*)rcvrs->findDefinition(actual_name);
6839     if (rcvr == NUL(Node*)) {
6840 	rcvr = rcvr_nd->createNewNode(this);
6841 	rcvrs->addDefinition(actual_name, rcvr);
6842 	if ((diffy > 0) && (diffy < 140) && (diffx < 180))
6843 	    rcvr->setVpePosition(vpex_dest+100, MAX(0,vpey_dest-80));
6844 	else
6845 	    rcvr->setVpePosition(vpex_dest, MAX(0,vpey_dest-80));
6846 	rcvr->setLabelString (actual_name);
6847 	this->copyGroupInfo(src, rcvr);
6848     }
6849 
6850     new Ark (rcvr, 1, n, pno);
6851 
6852     return TRUE;
6853 }
6854 
6855 //
6856 // For each receiver in the list...
6857 //    remove the receiver and replace it with an arc.
6858 //    the source of the arc is found by looking at a
6859 //    matching transmitter.
6860 //
replaceInputArks(List * selected,List *)6861 boolean Network::replaceInputArks(List* selected, List* )
6862 {
6863 
6864 //
6865 // Delete nodes outside the loop because we're iterating over the list.
6866 //
6867 List nodes_to_delete;
6868 
6869     if (!selected) return TRUE;
6870     if (selected->getSize() == 0) return TRUE;
6871     Dictionary erased_rcvrs;
6872     Dictionary* group_mgrs = this->getGroupManagers();
6873     GroupManager* gmgr = (GroupManager*)group_mgrs->findDefinition (PAGE_GROUP);
6874     Symbol gmgr_sym = gmgr->getManagerSymbol();
6875 
6876     ListIterator it(*selected);
6877     Node* no;
6878     while ( (no = (Node*)it.getNext()) ) {
6879 	//
6880 	// Pay attention only to Receiver nodes
6881 	//
6882 	if (no->isA(ClassReceiverNode) == FALSE) continue;
6883 	ReceiverNode* rcvr = (ReceiverNode*)no;
6884 
6885 	//
6886 	// The Receiver's input is the Transmitter
6887 	//
6888 	List* orig_in = (List*)rcvr->getInputArks(1);
6889 	if ((orig_in == NUL(List*)) || (orig_in->getSize() == 0)) continue;
6890 	ASSERT(orig_in->getSize() == 1);
6891 
6892 	//
6893 	// The Transmitter's input is one node/param we want to find
6894 	// We'll look at both ultimate source and immediate source
6895 	// because ultimate source might be null or on a different page
6896 	// in which case we'll use immediate source.
6897 	//
6898 	int pno;
6899 	Node* ultimate_src = rcvr->getUltimateSourceNode(&pno);
6900 	const char* src_page = NUL(char*);
6901 	const char* rcvr_page = rcvr->getGroupName(gmgr_sym);
6902 	if (ultimate_src) src_page = ultimate_src->getGroupName(gmgr_sym);
6903 	boolean same_page = FALSE;
6904 	if ((rcvr_page == NUL(char*)) && (src_page == NUL(char*)) && (ultimate_src)) {
6905 	    same_page = TRUE;
6906 	} else if ((rcvr_page) && (src_page) && (EqualString(rcvr_page,src_page))) {
6907 	    same_page = TRUE;
6908 	}
6909 	if (same_page == FALSE) {
6910 	    List* ia = (List*)rcvr->getInputArks(1);
6911 	    if ((!ia) || (ia->getSize() < 1)) continue;
6912 
6913 	    Node* tmit;
6914 	    Ark* a = (Ark*)ia->getElement(1);
6915 	    int dummy;
6916 	    tmit = a->getSourceNode(dummy);
6917 	    if (!tmit) continue;
6918 	    ia = (List*)tmit->getInputArks(1);
6919 	    if ((!ia) || (ia->getSize() < 1)) continue;
6920 	    a = (Ark*)ia->getElement(1);
6921 	    ultimate_src = a->getSourceNode(pno);
6922 	}
6923 	if (ultimate_src == NUL(Node*)) continue;
6924 	src_page = ultimate_src->getGroupName(gmgr_sym);
6925 
6926 	//
6927 	// Loop over the nodes connected to the Receiver in order
6928 	// to attach each one the real source node/param.
6929 	// During the loop, don't delete arcs, just gather them up
6930 	// for later deletion.
6931 	//
6932 	List* orig_out = (List*)rcvr->getOutputArks(1);
6933 	int arc_count = 0;
6934 	if (orig_out) arc_count = orig_out->getSize();
6935 	int i;
6936 	List delete_arcs;
6937 	for (i=1; i<=arc_count; i++) {
6938 	    Ark* rcvr_arc =(Ark*)orig_out->getElement(i);
6939 	    int out_pno = 0;
6940 	    Node* dest = rcvr_arc->getDestinationNode(out_pno);
6941 	    const char* dest_page = dest->getGroupName(gmgr_sym);
6942 	    //
6943 	    // If the page group of ultimate source is the same as the
6944 	    // page group for dest, then we can reconnect.
6945 	    //
6946 	    boolean same_page = FALSE;
6947 	    if ((dest_page == NUL(char*)) && (src_page == NUL(char*))) {
6948 		same_page = TRUE;
6949 	    } else if ((dest_page) && (src_page) && (EqualString(dest_page,src_page))) {
6950 		same_page = TRUE;
6951 	    }
6952 	    if (same_page)
6953 		delete_arcs.appendElement((void*)rcvr_arc);
6954 	}
6955 
6956 	//
6957 	// Go back and delete arcs now.
6958 	//
6959 	ListIterator it(delete_arcs);
6960 	Ark* a;
6961 	while ( (a=(Ark*)it.getNext()) ) {
6962 	    int out_pno = 0;
6963 	    Node* dest = a->getDestinationNode(out_pno);
6964 	    //Node* src = a->getSourceNode(in_pno);
6965 	    delete a;
6966 	    ASSERT (ultimate_src->isA(ClassTransmitterNode) == FALSE);
6967 	    ASSERT (dest->isA(ClassReceiverNode) == FALSE);
6968 	    Ark* new_arc = new Ark (ultimate_src, pno, dest, out_pno);
6969 	    if (this->editor)
6970 		this->editor->notifyArk(new_arc);
6971 	}
6972 
6973 	//
6974 	// If the Receiver has no more arcs, then delete it too.
6975 	//
6976 	orig_out = (List*)rcvr->getOutputArks(1);
6977 	if ((orig_out==NUL(List*)) || (orig_out->getSize() == 0)) {
6978 	    const char* label = rcvr->getLabelString();
6979 	    erased_rcvrs.addDefinition(label, (void*)1111);
6980 	    nodes_to_delete.appendElement(rcvr);
6981 	}
6982     }
6983     if (nodes_to_delete.getSize() > 0) {
6984 	if (this->editor)
6985 	    this->editor->removeNodes(&nodes_to_delete);
6986 	else {
6987 	    ListIterator it(nodes_to_delete);
6988 	    Node* n;
6989 	    while ( (n=(Node*)it.getNext()) ) this->deleteNode(n);
6990 	}
6991 	nodes_to_delete.clear();
6992     }
6993 
6994     //
6995     // For each label in the erasure dictionary, check corresponding
6996     // transmitters.  If we have reduced any transmitter's receiver count
6997     // to 0, then erase the transmitter also.
6998     //
6999     int i = 1;
7000     int size = erased_rcvrs.getSize();
7001     List* tmits = NUL(List*);
7002     if (size > 0)
7003 	tmits = this->makeClassifiedNodeList(ClassTransmitterNode, FALSE);
7004     if (tmits) {
7005 	while (i<=size) {
7006 	    const char* key = erased_rcvrs.getStringKey(i);
7007 	    it.setList(*tmits);
7008 	    Node* tmit;
7009 	    while ( (tmit = (Node*)it.getNext()) ) {
7010 		const char* label = tmit->getLabelString();
7011 		if (EqualString(label, key)) {
7012 		    List* orig = (List*)tmit->getOutputArks(1);
7013 		    if ((!orig) || (orig->getSize() == 0))
7014 			nodes_to_delete.appendElement(tmit);
7015 		}
7016 	    }
7017 
7018 	    i++;
7019 	}
7020 	delete tmits;
7021     }
7022 
7023     if (nodes_to_delete.getSize() > 0) {
7024 	if (this->editor)
7025 	    this->editor->removeNodes(&nodes_to_delete);
7026 	else {
7027 	    ListIterator it(nodes_to_delete);
7028 	    Node* n;
7029 	    while ( (n=(Node*)it.getNext()) ) this->deleteNode(n);
7030 	}
7031 	nodes_to_delete.clear();
7032     }
7033 
7034     return TRUE;
7035 }
7036 
7037