/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include #include "UIConfig.h" #include "defines.h" #include "NodeDefinition.h" #include "Node.h" #include "ParameterDefinition.h" #include "Parameter.h" #include "Dictionary.h" #include "DictionaryIterator.h" #include "Network.h" #include "SIAllocatorDictionary.h" #include "CDBAllocatorDictionary.h" #include "ErrorDialogManager.h" // // This is the dictionary that contains all Node (and derived) class // definitions. Looking up a node by name returns a pointer to a // NodeDefinition; // Dictionary *theNodeDefinitionDictionary = new Dictionary; NodeDefinition::NodeDefinition() { this-> nodeInstanceNumbers = 0; this->description = NUL(char*); this->input_repeats = this->output_repeats = 0; this->writeableCacheability = TRUE; this->defaultCacheability = ModuleFullyCached; this->mdf_flags = 0; this->loadFile = NULL; this->outboardHost = NULL; this->outboardCommand = NULL; this->userTool = TRUE; this->uiLoadedOnly = FALSE; } NodeDefinition::~NodeDefinition() { // // Delete the input/output definitions // ParameterDefinition *pd; ListIterator iterator(this->inputDefs); while (pd = (ParameterDefinition*)iterator.getNext()) delete pd; iterator.setList(this->outputDefs); while (pd = (ParameterDefinition*)iterator.getNext()) delete pd; if (this->outboardHost) delete this->outboardHost; if (this->outboardCommand) delete this->outboardCommand; if (this->loadFile) delete this->loadFile; if (this->description) delete (void*)this->description; // // If this node definition was installed in the Node definition // dictionary, then remove it. // Note that the constructor does NOT install this NodeDefinition in // theNodeDefinitionDictionary. It is assumed that this happens elsewhere, // probably for no good reason. // NodeDefinition *nd = (NodeDefinition*) theNodeDefinitionDictionary->findDefinition(this->getNameSymbol()); if (nd == this) theNodeDefinitionDictionary->removeDefinition(this->getNameSymbol()); } Node *NodeDefinition::newNode(Network *net, int inst) { Node *m = new Node(this, net, inst); return m; } NodeDefinition *NodeDefinition::AllocateDefinition() { return new NodeDefinition; } /////////////////////////////////////////////////////////////////////////////// // Get the Nth Input or Output ParameterDefinition. // n is indexed from 1. If n is greater than the number of input/output // defintions then it is a repeatable parameter, in which case we // must account for this to find the correct definition. // ParameterDefinition *NodeDefinition::getInputDefinition(int n) { ASSERT(n > 0); int cnt = this->getInputCount(); if (n > cnt) { int repeats = this->input_repeats; ASSERT(repeats > 0); if (repeats == 1) { n = cnt; } else { int num = n - cnt; num = (((n-1) - cnt) % repeats) + 1; n = cnt - repeats + num ; ASSERT(n > cnt - repeats); ASSERT(n <= cnt); } } return (ParameterDefinition*)this->inputDefs.getElement(n); } // // Get the n'th output parameter definition. // n is indexed from 1. // ParameterDefinition *NodeDefinition::getOutputDefinition(int n) { ASSERT(n > 0); int cnt = this->getOutputCount(); if (n > cnt) { int repeats = this->output_repeats; ASSERT(repeats > 0); if (repeats == 1) { n = cnt; } else { int num = n - cnt; num = (((n-1) - cnt) % repeats) + 1; n = cnt - repeats + num ; ASSERT(n > cnt - repeats); ASSERT(n <= cnt); } } return (ParameterDefinition*)this->outputDefs.getElement(n); } Node *NodeDefinition::createNewNode(Network *net, int inst) { if (!this->isAllowedInMacro() && net->isMacro()) { ErrorMessage("The %s node is not allowed in a macro.", this->getNameString()); return NULL; } Node *n = this->newNode(net, inst); if (n) { // // If initialization of the node fails delete the node and return NULL. // If initialize() fails, it is assumed that it issued an appropriate // error message, so we don't give one here. // if (!n->initialize()) { delete n; return NULL; } } return n; } boolean NodeDefinition::isDerivedFromMacro() { return FALSE; } // // Called once per new class (actually called on every new instance, but // we assume we only have one instance of each node defintion in the // whole system) after parsing an MDF record for this node. // void NodeDefinition::completeDefinition() { if (theSIAllocatorDictionary) { SIAllocator sia = this->getSIAllocator(); if (sia) theSIAllocatorDictionary->addAllocator(this->getNameString(), sia); } if (theCDBAllocatorDictionary) { CDBAllocator cdba = this->getCDBAllocator(); if (cdba) theCDBAllocatorDictionary->addAllocator(this->getNameString(), cdba); } this->finishDefinition(); } SIAllocator NodeDefinition::getSIAllocator() { // Causes the default definition in the SIAllocatorDictionary to be used. return NULL; } CDBAllocator NodeDefinition::getCDBAllocator() { // Causes the default definition in the CDBAllocatorDictionary to be used. return NULL; } // // Get a new parameter for the node that corresponds to this node definition. // Parameter *NodeDefinition::newParameter(ParameterDefinition *pd, Node *n, int index) { return new Parameter(pd); } // // Returns the name executive module that is called to do the work // for this type of node. // Be default, that name is always just the name of the Node. // const char *NodeDefinition::getExecModuleNameString() { return this->getNameString(); } // // Reset all the NodeDefinitions in the given dictionary to // have the next instance number generated by 1. // void NodeDefinition::ResetInstanceNumbers(Dictionary *dict) { DictionaryIterator di(*dict); NodeDefinition *nd; while (nd = (NodeDefinition*) di.getNextDefinition()) nd->setNextInstance(1); } // // Get the MDF record for this Node definition. // The returned string must be delete by the caller. // char *NodeDefinition::getMDFString() { char *header = this->getMDFHeaderString(); char *inputs = this->getMDFParametersString(TRUE); char *outputs = this->getMDFParametersString(FALSE); ASSERT(header); char *mdf = new char [STRLEN(header) + STRLEN(inputs) + STRLEN(outputs) + 2]; sprintf(mdf, "%s%s%s", header, (inputs ? inputs : ""), (outputs ? outputs : "")); delete header; if (inputs) delete inputs; if (outputs) delete outputs; return mdf; } // // Get the MDF header (stuff before the INPUT/OUTPUT statements) for this // NodeDefinition. // The returned string must be delete by the caller. // char *NodeDefinition::getMDFHeaderString() { char category[256]; char description[256]; char io_board[256]; char flags[256]; if (this->getCategoryString()) { sprintf(category,"CATEGORY %s\n", this->getCategoryString()); } else { category[0] = '\0'; } if (this->getDescription()) { sprintf(description,"DESCRIPTION %s\n", this->getDescription()); } else { description[0] = '\0'; } if (this->isOutboard()) { const char *host = this->getDefaultOutboardHost(); sprintf(io_board,"OUTBOARD \"%s\" ; %s\n", this->getOutboardCommand(), host ? host : ""); } else if (this->isDynamicallyLoaded()) { sprintf(io_board,"LOADABLE %s\n", this->getDynamicLoadFile()); } else { io_board[0] = '\0'; } if (this->mdf_flags) { sprintf(flags,"FLAGS%s%s%s%s%s%s%s%s\n", (this->isMDFFlagERR_CONT() ? " ERR_CONT" : ""), (this->isMDFFlagSWITCH() ? " SWITCH" : ""), (this->isMDFFlagPIN() ? " PIN" : ""), (this->isMDFFlagLOOP() ? " LOOP" : ""), (this->isMDFFlagSIDE_EFFECT() ? " SIDE_EFFECT" : ""), (this->isMDFFlagPERSISTENT() ? " PERSISTENT" : ""), (this->isMDFFlagASYNCHRONOUS() ? " ASYNC" : ""), (this->isMDFFlagREACH() ? " REACH" : ""), (this->isMDFFlagREROUTABLE() ? " REROUTABLE" : "")); } else { flags[0] = '\0'; } char *header = new char[128 + STRLEN(category) + STRLEN(description) + STRLEN(io_board) + STRLEN(flags)]; sprintf(header,"MODULE %s\n" "%s" "%s" "%s" "%s", this->getNameString(), category, description, io_board, flags); return header; } // // Get the list of INPUT/OUTPUT lines in the MDF and the REPEAT if any // The returned string must be delete by the caller. // char *NodeDefinition::getMDFParametersString(boolean inputs) { #define CHUNK 256 char *params = NULL; int currend = 0, maxlen = 0; ListIterator li; ParameterDefinition *pd; if (inputs) li.setList(this->inputDefs); else li.setList(this->outputDefs); while (pd = (ParameterDefinition*)li.getNext()) { char *line = pd->getMDFString(); int linelen = STRLEN(line) + 1; if (linelen + currend > maxlen) { maxlen = ( CHUNK > linelen ? CHUNK : linelen) + currend; params = (char*)REALLOC(params, maxlen * sizeof(char)); if (currend == 0) // The first time *params = '\0'; } strcat(¶ms[currend], line); currend += linelen - 1; delete line; } if (inputs && this->isInputRepeatable()) { if (maxlen - currend < 32) params = (char*)REALLOC(params, (32 + currend) * sizeof(char)); sprintf(¶ms[currend],"REPEAT %d\n",this->getInputRepeatCount()); } else if (!inputs && this->isOutputRepeatable()) { if (maxlen - currend < 32) params = (char*)REALLOC(params, (32 + currend) * sizeof(char)); sprintf(¶ms[currend],"REPEAT %d\n",this->getOutputRepeatCount()); } return params; } #define MDF_SWITCH 0x01 #define MDF_ERR_CONT 0x02 #define MDF_PIN 0x04 #define MDF_SIDE_EFFECT 0x08 #define MDF_PERSISTENT 0x10 #define MDF_ASYNCHRONOUS 0x20 #define MDF_REROUTABLE 0x40 #define MDF_REACH 0x80 #define MDF_LOOP 0x100 void NodeDefinition::setMDFFlag(boolean val, long flag) { if (val) this->mdf_flags |= flag; else this->mdf_flags &= ~flag; } void NodeDefinition::setMDFFlagERR_CONT(boolean val) { this->setMDFFlag(val, MDF_ERR_CONT); } boolean NodeDefinition::isMDFFlagERR_CONT() { return (this->mdf_flags & MDF_ERR_CONT) ? TRUE : FALSE ; } void NodeDefinition::setMDFFlagSWITCH(boolean val ) { this->setMDFFlag(val, MDF_SWITCH); } boolean NodeDefinition::isMDFFlagSWITCH() { return (this->mdf_flags & MDF_SWITCH) ? TRUE : FALSE ; } void NodeDefinition::setMDFFlagPIN(boolean val ) { this->setMDFFlag(val, MDF_PIN); } boolean NodeDefinition::isMDFFlagPIN() { return (this->mdf_flags & MDF_PIN) ? TRUE : FALSE ; } void NodeDefinition::setMDFFlagLOOP(boolean val ) { this->setMDFFlag(val, MDF_LOOP); } boolean NodeDefinition::isMDFFlagLOOP() { return (this->mdf_flags & MDF_LOOP) ? TRUE : FALSE ; } void NodeDefinition::setMDFFlagSIDE_EFFECT(boolean val ) { this->setMDFFlag(val, MDF_SIDE_EFFECT); } boolean NodeDefinition::isMDFFlagSIDE_EFFECT() { return (this->mdf_flags & MDF_SIDE_EFFECT) ? TRUE : FALSE ; } void NodeDefinition::setMDFFlagPERSISTENT(boolean val ) { this->setMDFFlag(val, MDF_PERSISTENT); } boolean NodeDefinition::isMDFFlagPERSISTENT() { return (this->mdf_flags & MDF_PERSISTENT) ? TRUE : FALSE ; } void NodeDefinition::setMDFFlagASYNCHRONOUS(boolean val ) { this->setMDFFlag(val, MDF_ASYNCHRONOUS); } boolean NodeDefinition::isMDFFlagASYNCHRONOUS() { return (this->mdf_flags & MDF_ASYNCHRONOUS) ? TRUE : FALSE ; } void NodeDefinition::setMDFFlagREROUTABLE(boolean val ) { this->setMDFFlag(val, MDF_REROUTABLE); } boolean NodeDefinition::isMDFFlagREROUTABLE() { return (this->mdf_flags & MDF_REROUTABLE) ? TRUE : FALSE ; } void NodeDefinition::setMDFFlagREACH(boolean val ) { this->setMDFFlag(val, MDF_REACH); } boolean NodeDefinition::isMDFFlagREACH() { return (this->mdf_flags & MDF_REACH) ? TRUE : FALSE ; } void NodeDefinition::setDefaultOutboardHost(const char *host) { if (this->outboardHost) delete this->outboardHost; this->outboardHost = DuplicateString(host); } boolean NodeDefinition::isOutboard() { return (this->outboardCommand != NULL); } void NodeDefinition::setOutboardCommand(const char *command) { if (this->outboardCommand) delete this->outboardCommand; if (this->loadFile) { delete this->loadFile; this->loadFile = NULL; } this->outboardCommand = DuplicateString(command); } boolean NodeDefinition::isDynamicallyLoaded() { return (this->loadFile != NULL); } const char *NodeDefinition::getDynamicLoadFile() { return this->loadFile; } void NodeDefinition::setDynamicLoadFile(const char *file) { if (this->loadFile) delete this->loadFile; // // I tool can be either outboard or inboard (static) or inboard // (dynamic), but not both. // if (this->outboardCommand) { delete this->outboardCommand; this->outboardCommand = NULL; } this->loadFile = DuplicateString(file); } void NodeDefinition::setDescription(const char *d) { if (this->description) delete this->description; this->description = DuplicateString(d); } // // Add a selectable value for the n'th input. // boolean NodeDefinition::addInputValueOption(int n, const char *value) { ParameterDefinition *pd = this->getInputDefinition(n); if (pd) return pd->addValueOption(value); return FALSE; } void NodeDefinition::setUILoadedOnly() { this->uiLoadedOnly = TRUE; } boolean NodeDefinition::isUILoadedOnly() { return this->uiLoadedOnly; } #if 0 // This is in Node.C // // Get the selectable values for the n'th input. // const char * const *NodeDefinition::getInputValueOptions(int n) { ParameterDefinition *pd = this->getInputDefinition(n); if (pd) return pd->getValueOptions(options); if (options) *options = NULL; return 0; } #endif