#include #include #include #include "TclUtils/SharedParameterSet.hh" #include "TclUtils/TclPrompt.hh" #include "TclUtils/ModuleRegistry.hh" #include "TclUtils/TclInterpManager.hh" #include "FrameUtil/AbsInterp.hh" #include "rcp/RCPValue.hpp" #include "rcp/Manager.hpp" #define CONFIG_SCRIPT_NAME std::string("cOnFiGuRatonScrIpT") SharedParameterSet::SharedParameterSet(const char* const theName, const char* const descr, const char* const className, const char* const arrName) : TclParameterSet(), _description(descr), _registerArray(arrName), _rcpid() { // Set up the Tcl handle for this object. The command name // will differ from "theName" in case "theName" is an empty string. Tcl_Interp *interp = modInterp(); if (setupTclHandle(interp, theName, className, false) != TCL_OK) { std::cerr << "ERROR in SharedParameterSet constructor: " << "can't register Tcl command \"" << theName << "\".\n" << "Check that this name is different " << "from existing Tcl keywords. Aborting." << std::endl; abort(); } // The object must have a new name if (ModuleRegistry::instance()->exists(getTclHandle())) { std::cerr << "ERROR in SharedParameterSet constructor: " << "can't create a new object with name \"" << getTclHandle() << "\".\n" << "An object with this name already exists. Aborting." << std::endl; abort(); } // Create an array element with the name of the object if (_addArrayElement(interp, arrName, getTclHandle()) != TCL_OK) { std::cerr << "ERROR in SharedParameterSet constructor: " << "can't create element \"" << getTclHandle() << "\" in the array \"" << arrName << "\". Aborting." << std::endl; abort(); } // Register the command with the framework. We've done all we // can to avoid name collisions, but the name can still collide // with an existing framework command, and the framework will // never notice... Just be careful choosing your object names. _handler = new FrameworkCommand(getTclHandle(), this); // Register the name ModuleRegistry::instance()->add(getTclHandle()); } SharedParameterSet::~SharedParameterSet() { ModuleRegistry::instance()->remove(getTclHandle()); delete _handler; _removeArrayElement(modInterp(), _registerArray.c_str(), getTclHandle()); } SharedParameterSet::FrameworkCommand::FrameworkCommand( const char* const commandName, SharedParameterSet *module) : _name(commandName), _module(module) { AbsInterp::instance()->createCommand(commandName, this); } SharedParameterSet::FrameworkCommand::~FrameworkCommand() { AbsInterp::instance()->deleteCommand(_name); } int SharedParameterSet::FrameworkCommand::handle(int argc, char* argv[]) { Tcl_Interp *interp = _module->modInterp(); Tcl_ResetResult(interp); int status = _module->parseCommand(interp, argc-1, argv+1); // Figure out if we are using an interactive mode. // Print the result if this is so. if (isatty(0)) { #if (TCL_MAJOR_VERSION > 7) char *result = Tcl_GetStringResult(interp); #else char *result = interp->result; #endif if (*result) std::cout << result << std::endl; } if (status == TCL_OK) return AbsInterp::OK; else return AbsInterp::ERROR; } int SharedParameterSet::parseCommand(Tcl_Interp * const interp, int argc, char *argv[]) { if (argc > 0) { if (strcmp(argv[0], "prompt") == 0) { if (argc == 1) { std::string prompt1 = getTclHandle(); prompt1 += "% "; TclPrompt p(interp, prompt1.c_str()); if (p.status() == TclPrompt::STOP) AbsInterp::instance()->simulateInput("uplevel #0 exit"); } else if (argc == 2) { TclPrompt p(interp, argv[1]); if (p.status() == TclPrompt::STOP) AbsInterp::instance()->simulateInput("uplevel #0 exit"); } else if (argc == 3) { TclPrompt p(interp, argv[1], argv[2]); if (p.status() == TclPrompt::STOP) AbsInterp::instance()->simulateInput("uplevel #0 exit"); } else { Tcl_SetResult(interp, "wrong # of arguments", TCL_VOLATILE); return TCL_ERROR; } return TCL_OK; } else if (strcmp(argv[0], "rcpdb") == 0) { if (argc == 2) { if (strcmp(argv[1], "save") == 0) { edm::RCPID rcpid(getRCPID()); if (rcpid.isValid()) { Tcl_SetResult(interp, const_cast( _rcpidString(rcpid).c_str()), TCL_VOLATILE); return TCL_OK; } else { Tcl_AppendResult(interp, "failed to obtain rcp id for object ", getTclHandle(), 0); return TCL_ERROR; } } else if (strcmp(argv[1], "restore") == 0) { if (restoreFromRCPdb()) { Tcl_AppendResult(interp, "failed to restore object ", getTclHandle(), " state from RCP database", 0); return TCL_ERROR; } return TCL_OK; } else { Tcl_AppendResult(interp, "Wrong rcpdb action \"", argv[1], "\". Allowed actions are " "\"save\" and \"restore\".", 0); return TCL_ERROR; } } else if (argc == 3) { if (strcmp(argv[1], "save") == 0) { // Wrong # of args } else if (strcmp(argv[1], "restore") == 0) { edm::RCPID rcpid; if (_parseRCPid(interp, argv[2], &rcpid) != TCL_OK) return TCL_ERROR; if (restoreFromRCPdb(rcpid)) { Tcl_AppendResult(interp, "failed to restore object ", getTclHandle(), " state using RCP id {", argv[2], "}", 0); return TCL_ERROR; } return TCL_OK; } else { Tcl_AppendResult(interp, "Wrong rcpdb action \"", argv[1], "\". Allowed actions are " "\"save\" and \"restore\".", 0); return TCL_ERROR; } } Tcl_SetResult(interp, "wrong # of arguments", TCL_VOLATILE); return TCL_ERROR; } else if (strcmp(argv[0], "describe") == 0) { if (argc == 1) { Tcl_SetResult(interp, const_cast(_description.c_str()), TCL_VOLATILE); return TCL_OK; } else { Tcl_SetResult(interp, "wrong # of arguments", TCL_VOLATILE); return TCL_ERROR; } } else if (strcmp(argv[0], "eval") == 0) { if (argc == 1) { Tcl_SetResult(interp, "wrong # of arguments", TCL_VOLATILE); return TCL_ERROR; } else { char *script = Tcl_Concat(argc-1, argv+1); int status = Tcl_Eval(interp, script); Tcl_Free(script); return status; } } else if (strcmp(argv[0], "methods") == 0 && argc == 1) { Tcl_AppendElement(interp, "describe"); Tcl_AppendElement(interp, "eval"); Tcl_AppendElement(interp, "prompt"); Tcl_AppendElement(interp, "rcpdb"); } else if (strcmp(argv[0], "help") == 0) { if (argc == 1) { Tcl_AppendElement(interp, "describe"); Tcl_AppendElement(interp, "eval"); Tcl_AppendElement(interp, "prompt"); Tcl_AppendElement(interp, "rcpdb"); } else if (argc == 2) { if (strcmp(argv[1], "describe") == 0) { Tcl_AppendResult( interp, "\n* Usage: ", getTclHandle(), " ", argv[1], "\nReturns module description.\n", 0); return TCL_OK; } else if (strcmp(argv[1], "rcpdb") == 0) { Tcl_AppendResult( interp, "\n* Usage: ", getTclHandle(), " rcpdb save", "\nSaves object state in the RCP database " "and returns RCP id as a Tcl list.\n", 0); Tcl_AppendResult( interp, "\n* Usage: ", getTclHandle(), " rcpdb restore", "\nRestores object state from " "the latest configuration in the RCP database.\n", 0); Tcl_AppendResult( interp, "\n* Usage: ", getTclHandle(), " rcpdb restore rcpid", "\nRestores object state given " "its RCP id as a Tcl list.\n", 0); return TCL_OK; } else if (strcmp(argv[1], "eval") == 0) { Tcl_AppendResult( interp, "\n* Usage: ", getTclHandle(), " ", argv[1], " arg ?arg ...?", "\nEvaluates a Tcl script in the interpreter ", "associated with the module\nin the same ", "fashion as the Tcl \"eval\" command.\n", 0); return TCL_OK; } else if (strcmp(argv[1], "prompt") == 0) { Tcl_AppendResult( interp, "\n* Usage: ", getTclHandle(), " ", argv[1], " ?propmt1? ?prompt2?", "\nEnters interactive mode and evaluates user", " input using the Tcl interpreter\n", "associated with the ", getTclHandle(), " module. Optional arguments prompt1 and\n", "prompt2 specify the input prompts for", " complete and incomplete commands.\n", 0); return TCL_OK; } } } } return TclParameterSet::parseCommand(interp, argc, argv); } Tcl_Interp * SharedParameterSet::modInterp(void) { // Returns the shared interpreter, preserving the state of TclInterpManager TclInterpManager *manager = TclInterpManager::instance(); bool shared = manager->isShared(); if (!shared) manager->setShared(true); Tcl_Interp *interp = manager->getInterp(); if (!shared) manager->setShared(false); return interp; } int SharedParameterSet::_addArrayElement(Tcl_Interp * interp, const char* const arrName, const char* const element) { char *newValue = "1"; if (Tcl_SetVar2(interp, const_cast(arrName), const_cast(element), newValue, TCL_GLOBAL_ONLY)) return TCL_OK; else return TCL_ERROR; } int SharedParameterSet::_removeArrayElement(Tcl_Interp * interp, const char* const arrName, const char* const element) { return Tcl_UnsetVar2(interp, const_cast(arrName), const_cast(element), TCL_GLOBAL_ONLY); } const edm::RCPID SharedParameterSet::getRCPID() { if (!_rcpid.isValid()) { std::string script("__rcpdb_config {"); script += getTclHandle(); script += "}"; int status = Tcl_GlobalEval(modInterp(), const_cast(script.c_str())); assert(status == TCL_OK); #if (TCL_MAJOR_VERSION > 7) const std::string result(Tcl_GetStringResult(modInterp())); #else const std::string result(modInterp()->result); #endif Tcl_ResetResult(modInterp()); rcp::RCPValue rcpV; rcpV.add(CONFIG_SCRIPT_NAME, result); rcp::Manager* pman = rcp::Manager::instance(); std::string pkgName(getTclClassName()); std::string objName(getTclHandle()); if (pman->complete(rcpV, pkgName, objName)) assert(rcpV.myRCPID().isValid()); else assert(!rcpV.myRCPID().isValid()); _rcpid = rcpV.myRCPID(); } return _rcpid; } int SharedParameterSet::restoreFromRCPdb(const edm::RCPID& rcpid) { if (_rcpid.isValid()) if (_rcpid == rcpid) return 0; rcp::RCPValue rcpV; if (!rcp::Manager::instance()->extract(rcpid, rcpV)) return 1; if (!rcpV.containsString(CONFIG_SCRIPT_NAME)) return 2; int status = Tcl_GlobalEval(modInterp(), const_cast( rcpV.getString(CONFIG_SCRIPT_NAME).c_str())); assert(status == TCL_OK); Tcl_ResetResult(modInterp()); assert(rcpid.isValid()); _rcpid = rcpid; return 0; } int SharedParameterSet::restoreFromRCPdb(void) { std::string pkgName(getTclClassName()); std::string objName(getTclHandle()); rcp::RCPValue rcpV; if (!rcp::Manager::instance()->extract(pkgName, objName, rcpV)) return 1; if (!rcpV.containsString(CONFIG_SCRIPT_NAME)) return 2; int status = Tcl_GlobalEval(modInterp(), const_cast( rcpV.getString(CONFIG_SCRIPT_NAME).c_str())); assert(status == TCL_OK); Tcl_ResetResult(modInterp()); assert(rcpV.myRCPID().isValid()); _rcpid = rcpV.myRCPID(); return 0; } int SharedParameterSet::_parseRCPid(Tcl_Interp * interp, const char *str, edm::RCPID* rcpid) { rcp::SequenceNumber sn; rcp::RCPDatabaseID db; int argc, isn, idb; char **argv; std::string tmp(str); if (Tcl_SplitList(interp, const_cast(tmp.c_str()), &argc, &argv) != TCL_OK) return TCL_ERROR; if (argc != 2) { Tcl_SetResult(interp, "bad RCP id", TCL_VOLATILE); goto fail; } if (Tcl_GetInt(interp, argv[0], &idb) != TCL_OK) goto fail; if (Tcl_GetInt(interp, argv[1], &isn) != TCL_OK) goto fail; sn = isn; db = idb; *rcpid = edm::RCPID(sn, db); Tcl_Free((char *)argv); return TCL_OK; fail: Tcl_Free((char *)argv); return TCL_ERROR; } std::string SharedParameterSet::_rcpidString(const edm::RCPID& rcpid) { char buf[32]; Tcl_DString s; Tcl_DStringInit(&s); sprintf(buf, "%d", rcpid.dbID()); Tcl_DStringAppendElement(&s, buf); sprintf(buf, "%d", rcpid.seq()); Tcl_DStringAppendElement(&s, buf); std::string result(Tcl_DStringValue(&s)); Tcl_DStringFree(&s); return result; }