// ********************************************************************** // // Copyright (c) 2001 // Mutable Realms, Inc. // Huntsville, AL, USA // // All Rights Reserved // // ********************************************************************** #include #include #include #include #ifdef HAVE_READLINE # include # include #endif using namespace std; using namespace Ice; using namespace IceStorm; extern FILE* yyin; namespace IceStorm { Parser* parser; } ParserPtr Parser::createParser(const CommunicatorPtr& communicator, const TopicManagerPrx& admin) { return new Parser(communicator, admin); } void Parser::usage() { cout << "help Print this message.\n" "exit, quit Exit this program.\n" "create TOPICS Add TOPICS.\n" "destroy TOPICS Remove TOPICS.\n" "link FROM TO COST Link FROM to TO with the given COST.\n" "unlink FROM TO Unlink TO from FROM.\n" "graph DATA COST Construct the link graph as described in DATA with COST\n" "list [TOPICS] Display information on TOPICS or all topics.\n" "shutdown Shut the IceStorm server down.\n"; } void Parser::create(const list& args) { try { for(list::const_iterator i = args.begin(); i != args.end() ; ++i) { _admin->create(*i); } } catch(const Exception& ex) { ostringstream s; s << ex; error(s.str()); } } void Parser::destroy(const list& args) { try { for(list::const_iterator i = args.begin(); i != args.end() ; ++i) { TopicPrx topic = _admin->retrieve(*i); topic->destroy(); } } catch(const Exception& ex) { ostringstream s; s << ex; error(s.str()); } } void Parser::link(const list& _args) { list args = _args; if(args.size() != 3) { error("`link' requires exactly three arguments (type `help' for more info)"); return; } try { TopicPrx fromTopic; TopicPrx toTopic; try { fromTopic = _admin->retrieve(args.front()); } catch(const IceStorm::NoSuchTopic&) { ostringstream s; s << args.front() << ": topic doesn't exist"; error(s.str()); return; } args.pop_front(); try { toTopic = _admin->retrieve(args.front()); } catch(const IceStorm::NoSuchTopic&) { ostringstream s; s << args.front() << ": topic doesn't exist"; error(s.str()); return; } args.pop_front(); Ice::Int cost = atoi(args.front().c_str()); fromTopic->link(toTopic, cost); } catch(const Exception& ex) { ostringstream s; s << ex; error(s.str()); } } void Parser::unlink(const list& _args) { list args = _args; if(args.size() != 2) { error("`unlink' requires exactly two arguments (type `help' for more info)"); return; } try { TopicPrx fromTopic; TopicPrx toTopic; try { fromTopic = _admin->retrieve(args.front()); } catch(const IceStorm::NoSuchTopic&) { ostringstream s; s << args.front() << ": topic doesn't exist"; error(s.str()); return; } args.pop_front(); try { toTopic = _admin->retrieve(args.front()); } catch(const IceStorm::NoSuchTopic&) { ostringstream s; s << args.front() << ": topic doesn't exist"; error(s.str()); return; } fromTopic->unlink(toTopic); } catch(const Exception& ex) { ostringstream s; s << ex; error(s.str()); } } void Parser::dolist(const list& _args) { list args = _args; try { if(args.size() == 0) { TopicDict d = _admin->retrieveAll(); if(!d.empty()) { for(TopicDict::iterator i = d.begin(); i != d.end(); ++i) { if(i != d.begin()) { cout << ", "; } cout << i->first; } cout << endl; } } else { while(args.size() != 0) { string name = args.front(); args.pop_front(); cout << name << endl; try { TopicPrx topic = _admin->retrieve(name); LinkInfoSeq links = topic->getLinkInfoSeq(); for(LinkInfoSeq::const_iterator p = links.begin(); p != links.end(); ++p) { cout << "\t" << (*p).name << " with cost " << (*p).cost << endl; } } catch(const NoSuchTopic&) { cout << "\tNo such topic" << endl; } } } } catch(const Exception& ex) { ostringstream s; s << ex; error(s.str()); } } void Parser::graph(const list& _args) { list args = _args; if(args.size() != 2) { error("`graph' requires exactly two arguments (type `help' for more info)"); return; } string file = args.front(); args.pop_front(); int maxCost = atoi(args.front().c_str()); if(maxCost == 0) { error("`graph': cost must be a positive number"); return; } try { WeightedGraph graph; if(!graph.parse(file)) { cerr << file << ": parse failed" << endl; return; } // // Compute the new edge set. // vector edges; graph.compute(edges, maxCost); graph.swap(edges); // // Ensure each vertex is present. // vector vertices = graph.getVertices(); TopicDict d = _admin->retrieveAll(); vector::const_iterator p; for(p = vertices.begin(); p != vertices.end(); ++p) { if(d.find(*p) == d.end()) { cout << *p << ": referenced topic not found" << endl; return; } } int links = 0; int unlinks = 0; // // Get the edge set for reach vertex. // for(p = vertices.begin(); p != vertices.end(); ++p) { TopicPrx topic = d[*p]; assert(topic); LinkInfoSeq seq = topic->getLinkInfoSeq(); vector > edges = graph.getEdgesFor(*p); for(vector >::const_iterator q = edges.begin(); q != edges.end(); ++q) { bool link = true; for(LinkInfoSeq::iterator r = seq.begin(); r != seq.end(); ++r) { // // Found the link element. // if((*r).name == (*q).first) { // // If the cost is the same, then there is // nothing to do. // if((*r).cost == (*q).second) { link = false; } seq.erase(r); break; } } // // Else, need to rebind the link. // if(link) { TopicPrx target = d[(*q).first]; ++links; topic->link(target, (*q).second); } } // // The remainder of the links are obsolete. // for(LinkInfoSeq::const_iterator r = seq.begin(); r != seq.end(); ++r) { ++unlinks; topic->unlink((*r).topic); } } cout << "graph: " << links << " new or changed links. " << unlinks << " unlinks." << endl; } catch(const Exception& ex) { ostringstream s; s << ex; error(s.str()); } } void Parser::shutdown() { try { _admin->shutdown(); } catch(const Exception& ex) { ostringstream s; s << ex; error(s.str()); } } void Parser::getInput(char* buf, int& result, int maxSize) { if(!_commands.empty()) { if(_commands == ";") { result = 0; } else { #if defined(_MSC_VER) && !defined(_STLP_MSVC) // COMPILERBUG: Stupid Visual C++ defines min and max as macros result = _MIN(maxSize, static_cast(_commands.length())); #else result = min(maxSize, static_cast(_commands.length())); #endif strncpy(buf, _commands.c_str(), result); _commands.erase(0, result); if(_commands.empty()) { _commands = ";"; } } } else if(isatty(fileno(yyin))) { #ifdef HAVE_READLINE char* line = readline(parser->getPrompt()); if(!line) { result = 0; } else { if(*line) { add_history(line); } result = strlen(line) + 1; if(result > maxSize) { free(line); error("input line too long"); result = 0; } else { strcpy(buf, line); strcat(buf, "\n"); free(line); } } #else cout << parser->getPrompt() << flush; string line; while(true) { char c = static_cast(getc(yyin)); if(c == EOF) { if(line.size()) { line += '\n'; } break; } line += c; if(c == '\n') { break; } } result = line.length(); if(result > maxSize) { error("input line too long"); buf[0] = EOF; result = 1; } else { strcpy(buf, line.c_str()); } #endif } else { if(((result = fread(buf, 1, maxSize, yyin)) == 0) && ferror(yyin)) { error("input in flex scanner failed"); buf[0] = EOF; result = 1; } } } void Parser::nextLine() { _currentLine++; } void Parser::continueLine() { _continue = true; } char* Parser::getPrompt() { assert(_commands.empty() && isatty(fileno(yyin))); if(_continue) { _continue = false; return "(cont) "; } else { return ">>> "; } } void Parser::scanPosition(const char* s) { string line(s); string::size_type idx; idx = line.find("line"); if(idx != string::npos) { line.erase(0, idx + 4); } idx = line.find_first_not_of(" \t\r#"); if(idx != string::npos) { line.erase(0, idx); } _currentLine = atoi(line.c_str()) - 1; idx = line.find_first_of(" \t\r"); if(idx != string::npos) { line.erase(0, idx); } idx = line.find_first_not_of(" \t\r\""); if(idx != string::npos) { line.erase(0, idx); idx = line.find_first_of(" \t\r\""); if(idx != string::npos) { _currentFile = line.substr(0, idx); line.erase(0, idx + 1); } else { _currentFile = line; } } } void Parser::error(const char* s) { if(_commands.empty() && !isatty(fileno(yyin))) { cerr << _currentFile << ':' << _currentLine << ": " << s << endl; } else { cerr << "error: " << s << endl; } _errors++; } void Parser::error(const string& s) { error(s.c_str()); } void Parser::warning(const char* s) { if(_commands.empty() && !isatty(fileno(yyin))) { cerr << _currentFile << ':' << _currentLine << ": warning: " << s << endl; } else { cerr << "warning: " << s << endl; } } void Parser::warning(const string& s) { warning(s.c_str()); } int Parser::parse(FILE* file, bool debug) { extern int yydebug; yydebug = debug ? 1 : 0; assert(!parser); parser = this; _errors = 0; _commands.empty(); yyin = file; assert(yyin); _currentFile = ""; _currentLine = 0; _continue = false; nextLine(); int status = yyparse(); if(_errors) { status = EXIT_FAILURE; } parser = 0; return status; } int Parser::parse(const std::string& commands, bool debug) { extern int yydebug; yydebug = debug ? 1 : 0; assert(!parser); parser = this; _errors = 0; _commands = commands; assert(!_commands.empty()); yyin = 0; _currentFile = ""; _currentLine = 0; _continue = false; nextLine(); int status = yyparse(); if(_errors) { status = EXIT_FAILURE; } parser = 0; return status; } Parser::Parser(const CommunicatorPtr& communicator, const TopicManagerPrx& admin) : _communicator(communicator), _admin(admin) { }