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 ¶meter);
2644
2645 if (parsed_items != 5) {
2646 parsed_items =
2647 sscanf(name,
2648 "%[^_]_%d_%[^_]_%d",
2649 module,
2650 &instance,
2651 type,
2652 ¶meter);
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 ¶meter);
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 ¶meter);
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