$search
00001 #ifndef NO_GPL 00002 /*************************************************************************** 00003 tag: Peter Soetens Thu Jul 3 15:31:34 CEST 2008 TaskBrowser.cpp 00004 00005 TaskBrowser.cpp - description 00006 ------------------- 00007 begin : Thu July 03 2008 00008 copyright : (C) 2008 Peter Soetens 00009 email : peter.soetens@fmtc.be 00010 00011 *************************************************************************** 00012 * * 00013 * This program is free software; you can redistribute it and/or modify * 00014 * it under the terms of the GNU General Public License as published by * 00015 * the Free Software Foundation; either version 2 of the License, or * 00016 * (at your option) any later version. * 00017 * * 00018 * This program is distributed in the hope that it will be useful, * 00019 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 00021 * General Public License for more details. * 00022 * * 00023 * You should have received a copy of the GNU General Public * 00024 * License along with this program; if not, write to the Free Software * 00025 * Foundation, Inc., 59 Temple Place, * 00026 * Suite 330, Boston, MA 02111-1307 USA * 00027 ***************************************************************************/ 00028 #else 00029 /*************************************************************************** 00030 tag: Peter Soetens Tue Dec 21 22:43:07 CET 2004 TaskBrowser.cxx 00031 00032 TaskBrowser.cxx - description 00033 ------------------- 00034 begin : Tue December 21 2004 00035 copyright : (C) 2004 Peter Soetens 00036 email : peter.soetens@mech.kuleuven.ac.be 00037 00038 *************************************************************************** 00039 * This library is free software; you can redistribute it and/or * 00040 * modify it under the terms of the GNU Lesser General Public * 00041 * License as published by the Free Software Foundation; either * 00042 * version 2.1 of the License, or (at your option) any later version. * 00043 * * 00044 * This library is distributed in the hope that it will be useful, * 00045 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00046 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 00047 * Lesser General Public License for more details. * 00048 * * 00049 * You should have received a copy of the GNU Lesser General Public * 00050 * License along with this library; if not, write to the Free Software * 00051 * Foundation, Inc., 59 Temple Place, * 00052 * Suite 330, Boston, MA 02111-1307 USA * 00053 * * 00054 ***************************************************************************/ 00055 #endif 00056 00057 00058 #include <rtt/Logger.hpp> 00059 #include <rtt/extras/MultiVector.hpp> 00060 #include <rtt/types/TypeStream.hpp> 00061 #include <rtt/types/Types.hpp> 00062 #include "TaskBrowser.hpp" 00063 00064 #include <rtt/scripting/TryCommand.hpp> 00065 #include <rtt/TaskContext.hpp> 00066 #include <rtt/plugin/PluginLoader.hpp> 00067 #include <rtt/scripting/parser-debug.hpp> 00068 #include <rtt/scripting/Parser.hpp> 00069 #include <rtt/scripting/parse_exception.hpp> 00070 #include <rtt/scripting/PeerParser.hpp> 00071 #include <rtt/scripting/Scripting.hpp> 00072 #include <rtt/plugin/PluginLoader.hpp> 00073 #include <rtt/internal/GlobalService.hpp> 00074 #include <rtt/types/GlobalsRepository.hpp> 00075 #include <boost/algorithm/string.hpp> 00076 00077 #include <iostream> 00078 #include <fstream> 00079 #include <sstream> 00080 #include <iomanip> 00081 #include <deque> 00082 #include <stdio.h> 00083 #include <algorithm> 00084 00085 #if defined(HAS_READLINE) && !defined(NO_GPL) 00086 # define USE_READLINE 00087 #endif 00088 #if defined(HAS_EDITLINE) 00089 // we use the readline bc wrapper: 00090 # define USE_READLINE 00091 # define USE_EDITLINE 00092 #endif 00093 // only use signals if posix, and pure readline 00094 # if defined(_POSIX_VERSION) && defined(HAS_READLINE) && !defined(HAS_EDITLINE) 00095 # define USE_SIGNALS 1 00096 # endif 00097 00098 00099 #ifdef USE_READLINE 00100 # ifdef USE_EDITLINE 00101 # include <editline/readline.h> 00102 # include <editline/history.h> 00103 # else 00104 # include <readline/readline.h> 00105 # include <readline/history.h> 00106 # endif 00107 #endif 00108 #include <boost/bind.hpp> 00109 #include <boost/lambda/lambda.hpp> 00110 00111 #ifdef USE_SIGNALS 00112 #include <signal.h> 00113 #endif 00114 00115 // we need to declare it since Xenomai does not declare it in any header 00116 #if defined(USE_SIGNALS) && defined(OROCOS_TARGET_XENOMAI) && CONFIG_XENO_VERSION_MAJOR == 2 && CONFIG_XENO_VERSION_MINOR >= 5 00117 extern "C" 00118 int xeno_sigwinch_handler(int sig, siginfo_t *si, void *ctxt); 00119 #endif 00120 namespace OCL 00121 { 00122 using namespace boost; 00123 using namespace std; 00124 using namespace RTT; 00125 using namespace RTT::detail; 00126 #ifdef USE_READLINE 00127 std::vector<std::string> TaskBrowser::candidates; 00128 std::vector<std::string> TaskBrowser::completes; 00129 std::vector<std::string>::iterator TaskBrowser::complete_iter; 00130 std::string TaskBrowser::component; 00131 std::string TaskBrowser::component_found; 00132 std::string TaskBrowser::peerpath; 00133 std::string TaskBrowser::text; 00134 #endif 00135 RTT::TaskContext* TaskBrowser::taskcontext = 0; 00136 Service::shared_ptr TaskBrowser::taskobject; 00137 RTT::TaskContext* TaskBrowser::peer = 0; 00138 RTT::TaskContext* TaskBrowser::tb = 0; 00139 RTT::TaskContext* TaskBrowser::context = 0; 00140 00141 using boost::bind; 00142 using namespace RTT; 00143 using namespace std; 00144 00145 string TaskBrowser::red; 00146 string TaskBrowser::green; 00147 string TaskBrowser::blue; 00148 std::deque<TaskContext*> taskHistory; 00149 std::string TaskBrowser::prompt("> "); 00150 std::string TaskBrowser::coloron; 00151 std::string TaskBrowser::underline; 00152 std::string TaskBrowser::coloroff; 00153 00154 00158 static std::ostream& 00159 nl(std::ostream& __os) 00160 { return __os.put(__os.widen('\n')); } 00161 00162 // All readline specific functions 00163 #if defined(USE_READLINE) 00164 00165 // Signal code only on Posix: 00166 #if defined(USE_SIGNALS) 00167 00168 void TaskBrowser::rl_sigwinch_handler(int sig, siginfo_t *si, void *ctxt) { 00169 #if defined(OROCOS_TARGET_XENOMAI) && CONFIG_XENO_VERSION_MAJOR == 2 && CONFIG_XENO_VERSION_MINOR >= 5 00170 if (xeno_sigwinch_handler(sig, si, ctxt) == 0) 00171 #endif 00172 rl_resize_terminal(); 00173 } 00174 #endif // USE_SIGNALS 00175 00176 char *TaskBrowser::rl_gets () 00177 { 00178 /* If the buffer has already been allocated, 00179 return the memory to the free pool. */ 00180 if (line_read) 00181 { 00182 #ifdef _WIN32 00183 00194 free(line_read); 00195 #else 00196 free (line_read); 00197 #endif 00198 line_read = 0; 00199 } 00200 00201 /* Get a line from the user. */ 00202 std::string p; 00203 if ( !macrorecording ) { 00204 p = prompt; 00205 } else { 00206 p = "> "; 00207 } 00208 #if defined(USE_SIGNALS) 00209 00210 if (rl_set_signals() != 0) 00211 cerr << "Error setting signals !" <<endl; 00212 #endif 00213 line_read = readline ( p.c_str() ); 00214 00215 /* If the line has any text in it, 00216 save it on the history. */ 00217 if (line_read && *line_read) { 00218 // do not store "quit" 00219 string s = line_read; 00220 if (s != "quit" && ! ( history_get( where_history() ) && s == string(history_get( where_history() )->line) ) ) { 00221 // cout << "Where: " << where_history() << " history_get: " << ( history_get( where_history() ) ? history_get( where_history() )->line : "(null)") << endl; 00222 // cout << "History: " << (current_history() ? (const char*) current_history()->line : "(null)") << endl; 00223 add_history (line_read); 00224 } 00225 } 00226 return (line_read); 00227 } 00228 00229 char* TaskBrowser::dupstr( const char *s ) 00230 { 00231 char * rv; 00232 // must be C-style : 00233 rv = (char*) malloc( strlen( s ) + 1 ); 00234 strncpy( rv, s, strlen(s) + 1 ); 00235 return rv; 00236 } 00237 00238 char *TaskBrowser::command_generator( const char *_text, int state ) 00239 { 00240 // first time called. 00241 if ( !state ) 00242 { 00243 // make a copy : 00244 text = _text; 00245 // rebuild a completion list 00246 completes.clear(); 00247 find_completes(); 00248 complete_iter = completes.begin(); 00249 } 00250 else 00251 ++complete_iter; 00252 00253 // return zero if nothing more is found 00254 if ( complete_iter == completes.end() ) 00255 return 0; 00256 // return the next completion option 00257 return dupstr( complete_iter->c_str() ); // RL requires malloc ! 00258 } 00259 00264 void TaskBrowser::find_completes() { 00265 std::string::size_type pos; 00266 std::string::size_type startpos; 00267 std::string line( rl_line_buffer, rl_point ); 00268 00269 // complete on 'cd' or 'ls' : 00270 if ( line.find(std::string("cd ")) == 0 || line.find(std::string("ls ")) == 0) { 00271 //cerr <<endl<< "switch to :" << text<<endl; 00272 // pos = text.rfind("."); 00273 pos = line.find(" "); // pos+1 is first peername 00274 startpos = line.find_last_of(". "); // find last peer 00275 //cerr <<"startpos :"<<startpos<<endl; 00276 // start searching from component. 00277 peer = taskcontext; 00278 if ( pos+1 != line.length() ) // bounds check 00279 peer = findPeer( line.substr(pos+1) ); 00280 00281 if (!peer) 00282 return; 00283 //std::string peername = text.substring( pos+1, std::string::npos ); 00284 RTT::TaskContext::PeerList v = peer->getPeerList(); 00285 for (RTT::TaskContext::PeerList::iterator i = v.begin(); i != v.end(); ++i) { 00286 std::string path; 00287 if ( !( pos+1 > startpos) ) 00288 path = line.substr(pos+1, startpos - pos); 00289 //cerr << "path :"<<path<<endl; 00290 if ( *i == line.substr(startpos+1) ) 00291 completes.push_back( path + *i + "."); 00292 else 00293 if ( startpos == std::string::npos || startpos+1 == line.length() || i->find( line.substr(startpos+1)) == 0 ) 00294 completes.push_back( path + *i ); 00295 } 00296 // Stop here if 'cd' 00297 if (line.find(std::string("cd ")) == 0) 00298 return; 00299 // Add objects for 'ls'. 00300 v = peer->provides()->getProviderNames(); 00301 for (RTT::TaskContext::PeerList::iterator i = v.begin(); i != v.end(); ++i) { 00302 std::string path; 00303 if ( !( pos+1 > startpos) ) 00304 path = line.substr(pos+1, startpos - pos); 00305 //cerr << "path :"<<path<<endl; 00306 if ( *i == line.substr(startpos+1) ) 00307 completes.push_back( path + *i + "."); 00308 else 00309 if ( startpos == std::string::npos || startpos+1 == line.length() || i->find( line.substr(startpos+1)) == 0 ) 00310 completes.push_back( path + *i ); 00311 } 00312 return; // do not add component names. 00313 } 00314 00315 // TaskBrowser commands : 00316 if ( line.find(std::string(".")) == 0 ) { 00317 // first make a list of all sensible completions. 00318 std::vector<std::string> tbcoms; 00319 tbcoms.push_back(".loadProgram "); 00320 tbcoms.push_back(".unloadProgram "); 00321 tbcoms.push_back(".loadStateMachine "); 00322 tbcoms.push_back(".unloadStateMachine "); 00323 tbcoms.push_back(".light"); 00324 tbcoms.push_back(".dark"); 00325 tbcoms.push_back(".hex"); 00326 tbcoms.push_back(".nohex"); 00327 tbcoms.push_back(".nocolors"); 00328 tbcoms.push_back(".connect"); 00329 tbcoms.push_back(".record"); 00330 tbcoms.push_back(".end"); 00331 tbcoms.push_back(".cancel"); 00332 tbcoms.push_back(".provide"); 00333 tbcoms.push_back(".services"); 00334 tbcoms.push_back(".typekits"); 00335 tbcoms.push_back(".types"); 00336 00337 // then see which one matches the already typed line : 00338 for( std::vector<std::string>::iterator it = tbcoms.begin(); 00339 it != tbcoms.end(); 00340 ++it) 00341 if ( it->find(line) == 0 ) 00342 completes.push_back( *it ); // if partial match, add. 00343 return; 00344 } 00345 00346 if ( line.find(std::string("list ")) == 0 00347 || line.find(std::string("trace ")) == 0 00348 || line.find(std::string("untrace ")) == 0) { 00349 stringstream ss( line.c_str() ); // copy line into ss. 00350 string lcommand; 00351 ss >> lcommand; 00352 lcommand += ' '; 00353 std::vector<std::string> progs; 00354 00355 if ( context->provides()->hasService("scripting") ) { 00356 // THIS: 00357 progs = context->getProvider<Scripting>("scripting")->getProgramList(); 00358 // then see which one matches the already typed line : 00359 for( std::vector<std::string>::iterator it = progs.begin(); 00360 it != progs.end(); 00361 ++it) { 00362 string res = lcommand + *it; 00363 if ( res.find(line) == 0 ) 00364 completes.push_back( *it ); // if partial match, add. 00365 } 00366 progs = context->getProvider<Scripting>("scripting")->getStateMachineList(); 00367 for( std::vector<std::string>::iterator it = progs.begin(); 00368 it != progs.end(); 00369 ++it) { 00370 string res = lcommand + *it; 00371 if ( res.find(line) == 0 ) 00372 completes.push_back( *it ); // if partial match, add. 00373 } 00374 } 00375 return; 00376 } 00377 00378 startpos = text.find_last_of(",( "); 00379 if ( startpos == std::string::npos ) 00380 startpos = 0; // if none is found, start at beginning 00381 00382 // complete on peers and objects, and find the peer the user wants completion for 00383 find_peers(startpos); 00384 // now proceed with 'this->peer' as TC, 00385 // this->taskobject as TO and 00386 // this->component as object and 00387 // this->peerpath as the text leading up to 'this->component'. 00388 00389 // store the partial compname or peername 00390 std::string comp = component; 00391 00392 00393 // NEXT: use taskobject to complete commands, events, methods, attrs 00394 // based on 'component' (find trick). 00395 // if taskobject == peer, also complete properties 00396 find_ops(); 00397 00398 // TODO: concat two cases below as text.find("cd")... 00399 // check if the user is tabbing on an empty command, then add the console commands : 00400 if ( line.empty() ) { 00401 completes.push_back("cd "); 00402 completes.push_back("cd .."); 00403 completes.push_back("ls"); 00404 completes.push_back("help"); 00405 completes.push_back("quit"); 00406 completes.push_back("list"); 00407 completes.push_back("trace"); 00408 completes.push_back("untrace"); 00409 if (taskcontext == context) 00410 completes.push_back("leave"); 00411 else 00412 completes.push_back("enter"); 00413 // go on below to add components and tasks as well. 00414 } 00415 00416 // only try this if text is not empty. 00417 if ( !text.empty() ) { 00418 if ( std::string( "cd " ).find(text) == 0 ) 00419 completes.push_back("cd "); 00420 if ( std::string( "ls" ).find(text) == 0 ) 00421 completes.push_back("ls"); 00422 if ( std::string( "cd .." ).find(text) == 0 ) 00423 completes.push_back("cd .."); 00424 if ( std::string( "help" ).find(text) == 0 ) 00425 completes.push_back("help"); 00426 if ( std::string( "quit" ).find(text) == 0 ) 00427 completes.push_back("quit"); 00428 if ( std::string( "list " ).find(text) == 0 ) 00429 completes.push_back("list "); 00430 if ( std::string( "trace " ).find(text) == 0 ) 00431 completes.push_back("trace "); 00432 if ( std::string( "untrace " ).find(text) == 0 ) 00433 completes.push_back("untrace "); 00434 00435 if (taskcontext == context && string("leave").find(text) == 0) 00436 completes.push_back("leave"); 00437 00438 if (context == tb && string("enter").find(text) == 0) 00439 completes.push_back("enter"); 00440 } 00441 } 00442 00443 void TaskBrowser::find_ops() 00444 { 00445 // the last (incomplete) text is stored in 'component'. 00446 // all attributes : 00447 std::vector<std::string> attrs; 00448 attrs = taskobject->getAttributeNames(); 00449 for (std::vector<std::string>::iterator i = attrs.begin(); i!= attrs.end(); ++i ) { 00450 if ( i->find( component ) == 0 ) 00451 completes.push_back( peerpath + *i ); 00452 } 00453 // all properties if RTT::TaskContext/Service: 00454 std::vector<std::string> props; 00455 taskobject->properties()->list(props); 00456 for (std::vector<std::string>::iterator i = props.begin(); i!= props.end(); ++i ) { 00457 if ( i->find( component ) == 0 ) { 00458 completes.push_back( peerpath + *i ); 00459 } 00460 } 00461 00462 // methods: 00463 vector<string> comps = taskobject->getNames(); 00464 for (std::vector<std::string>::iterator i = comps.begin(); i!= comps.end(); ++i ) { 00465 if ( i->find( component ) == 0 ) 00466 completes.push_back( peerpath + *i ); 00467 } 00468 00469 // types: 00470 comps = Types()->getDottedTypes(); 00471 for (std::vector<std::string>::iterator i = comps.begin(); i!= comps.end(); ++i ) { 00472 if ( peerpath.empty() && i->find( component ) == 0 ) 00473 completes.push_back( *i ); 00474 } 00475 00476 // Global Attributes: 00477 comps = GlobalsRepository::Instance()->getAttributeNames(); 00478 for (std::vector<std::string>::iterator i = comps.begin(); i!= comps.end(); ++i ) { 00479 if ( peerpath.empty() && i->find( component ) == 0 ) 00480 completes.push_back( *i ); 00481 } 00482 00483 // Global methods: 00484 if ( taskobject == peer->provides() && peer == context) { 00485 comps = GlobalService::Instance()->getNames(); 00486 for (std::vector<std::string>::iterator i = comps.begin(); i!= comps.end(); ++i ) { 00487 if ( i->find( component ) == 0 ) 00488 completes.push_back( peerpath + *i ); 00489 } 00490 } 00491 00492 // complete on types: 00493 bool try_deeper = false; 00494 try { 00495 Parser parser; 00496 DataSourceBase::shared_ptr result = parser.parseExpression( peerpath + component_found, context ); 00497 if (result && !component.empty() ) { 00498 vector<string> members = result->getMemberNames(); 00499 for (std::vector<std::string>::iterator i = members.begin(); i!= members.end(); ++i ) { 00500 if ( string( component_found + "." + *i ).find( component ) == 0 ) 00501 completes.push_back( peerpath + component_found + "." + *i ); 00502 if ( component_found + "." + *i == component ) 00503 try_deeper = true; 00504 } 00505 } 00506 } catch(...) {} 00507 // this is a hack to initiate a complete on a valid expression that might have members. 00508 // the completer above would only return the expression itself, while this one tries to 00509 // go a level deeper again. 00510 if (try_deeper) { 00511 try { 00512 Parser parser; 00513 DataSourceBase::shared_ptr result = parser.parseExpression( peerpath + component, context ); 00514 if (result && !component.empty() ) { 00515 vector<string> members = result->getMemberNames(); 00516 for (std::vector<std::string>::iterator i = members.begin(); i!= members.end(); ++i ) { 00517 if (component_found + "." != component ) // catch corner case. 00518 completes.push_back( peerpath + component + "." + *i ); 00519 } 00520 } 00521 } catch(...) {} 00522 } 00523 } 00524 00525 void TaskBrowser::find_peers( std::string::size_type startpos ) 00526 { 00527 peerpath.clear(); 00528 peer = context; 00529 taskobject = context->provides(); 00530 00531 std::string to_parse = text.substr(startpos); 00532 startpos = 0; 00533 std::string::size_type endpos = 0; 00534 // Traverse the entered peer-list 00535 component.clear(); 00536 peerpath.clear(); 00537 // This loop separates the peer/service from the member/method 00538 while (endpos != std::string::npos ) 00539 { 00540 bool itemfound = false; 00541 endpos = to_parse.find("."); 00542 if ( endpos == startpos ) { 00543 component.clear(); 00544 break; 00545 } 00546 std::string item = to_parse.substr(startpos, endpos); 00547 00548 if ( taskobject->hasService( item ) ) { 00549 taskobject = peer->provides(item); 00550 itemfound = true; 00551 } else 00552 if ( peer->hasPeer( item ) ) { 00553 peer = peer->getPeer( item ); 00554 taskobject = peer->provides(); 00555 itemfound = true; 00556 } else if ( GlobalService::Instance()->hasService(item) ) { 00557 taskobject = GlobalService::Instance()->provides(item); 00558 itemfound = true; 00559 } 00560 if ( itemfound ) { // if "." found and correct path 00561 peerpath += to_parse.substr(startpos, endpos) + "."; 00562 if ( endpos != std::string::npos ) 00563 to_parse = to_parse.substr(endpos + 1); 00564 else 00565 to_parse.clear(); 00566 startpos = 0; 00567 } 00568 else { 00569 // no match: typo or member name 00570 // store the text until the last dot: 00571 component_found = to_parse.substr(startpos, to_parse.rfind(".")); 00572 // store the complete text 00573 component = to_parse.substr(startpos, std::string::npos); 00574 break; 00575 } 00576 } 00577 00578 // now we got the peer and taskobject pointers, 00579 // the completed path in peerpath 00580 // the last partial path in component 00581 // cout << "text: '" << text <<"'"<<endl; 00582 // cout << "to_parse: '" << text <<"'"<<endl; 00583 // cout << "Peerpath: '" << peerpath <<"'"<<endl; 00584 // cout <<endl<< "Component: '" << component <<"'"<<endl; 00585 // cout << "Component_found: '" << component_found <<"'"<<endl; 00586 00587 RTT::TaskContext::PeerList v; 00588 if ( taskobject == peer->provides() ) { 00589 // add peer's completes: 00590 v = peer->getPeerList(); 00591 for (RTT::TaskContext::PeerList::iterator i = v.begin(); i != v.end(); ++i) { 00592 if ( i->find( component ) == 0 ) { // only add if match 00593 completes.push_back( peerpath + *i ); 00594 completes.push_back( peerpath + *i + "." ); 00595 //cerr << "added " << peerpath+*i+"."<<endl; 00596 } 00597 } 00598 } 00599 // add taskobject's completes: 00600 v = taskobject->getProviderNames(); 00601 for (RTT::TaskContext::PeerList::iterator i = v.begin(); i != v.end(); ++i) { 00602 if ( i->find( component ) == 0 ) { // only add if match 00603 completes.push_back( peerpath + *i ); 00604 if ( *i != "this" ) // "this." confuses our parsing lateron 00605 completes.push_back( peerpath + *i + "." ); 00606 //cerr << "added " << peerpath+*i+"."<<endl; 00607 } 00608 } 00609 // add global service completes: 00610 if ( peer == context && taskobject == peer->provides() ) { 00611 v = GlobalService::Instance()->getProviderNames(); 00612 for (RTT::TaskContext::PeerList::iterator i = v.begin(); i != v.end(); ++i) { 00613 if ( i->find( component ) == 0 ) { // only add if match 00614 completes.push_back( peerpath + *i ); 00615 if ( *i != "this" ) // "this." confuses our parsing lateron 00616 completes.push_back( peerpath + *i + "." ); 00617 //cerr << "added " << peerpath+*i+"."<<endl; 00618 } 00619 } 00620 } 00621 return; 00622 } 00623 00624 char ** TaskBrowser::orocos_hmi_completion ( const char *text, int start, int end ) 00625 { 00626 char **matches; 00627 matches = ( char ** ) 0; 00628 00629 matches = rl_completion_matches ( text, &TaskBrowser::command_generator ); 00630 00631 return ( matches ); 00632 } 00633 #endif // USE_READLINE 00634 00635 TaskBrowser::TaskBrowser( RTT::TaskContext* _c ) 00636 : RTT::TaskContext("TaskBrowser"), 00637 debug(0), 00638 line_read(0), 00639 lastc(0), storedname(""), storedline(-1), 00640 usehex(false), 00641 macrorecording(false) 00642 { 00643 tb = this; 00644 context = tb; 00645 this->switchTaskContext(_c); 00646 #ifdef USE_READLINE 00647 // we always catch sigwinch ourselves, in order to pass it on to Xenomai if necessary. 00648 #ifdef USE_SIGNALS 00649 rl_catch_sigwinch = 0; 00650 #endif 00651 rl_completion_append_character = '\0'; // avoid adding spaces 00652 rl_attempted_completion_function = &TaskBrowser::orocos_hmi_completion; 00653 00654 if ( read_history(".tb_history") != 0 ) { 00655 read_history("~/.tb_history"); 00656 } 00657 #ifdef USE_SIGNALS 00658 struct sigaction sa; 00659 sa.sa_sigaction = &TaskBrowser::rl_sigwinch_handler; 00660 sa.sa_flags = SA_SIGINFO | SA_RESTART; 00661 sigemptyset( &sa.sa_mask ); 00662 sigaction(SIGWINCH, &sa, 0); 00663 #endif // USE_SIGNALS 00664 #endif // USE_READLINE 00665 00666 this->setColorTheme( darkbg ); 00667 this->enterTask(); 00668 } 00669 00670 TaskBrowser::~TaskBrowser() { 00671 #ifdef USE_READLINE 00672 if (line_read) 00673 { 00674 free (line_read); 00675 } 00676 if ( write_history(".tb_history") != 0 ) { 00677 write_history("~/.tb_history"); 00678 } 00679 #endif 00680 } 00681 00685 char getTaskStatusChar(RTT::TaskContext* t) 00686 { 00687 if (t->inFatalError()) 00688 return 'F'; 00689 if (t->inRunTimeError()) 00690 return 'E'; 00691 if (t->inException()) 00692 return 'X'; 00693 if (t->isRunning() ) 00694 return 'R'; // Running 00695 if (t->isConfigured() ) 00696 return 'S'; // Stopped 00697 return 'U'; // Unconfigured/Preoperational 00698 } 00699 00700 char getStateMachineStatusChar(RTT::TaskContext* t, string progname) 00701 { 00702 string ps = t->getProvider<Scripting>("scripting")->getStateMachineStatusStr(progname); 00703 return toupper(ps[0]); 00704 } 00705 00706 char getProgramStatusChar(RTT::TaskContext* t, string progname) 00707 { 00708 string ps = t->getProvider<Scripting>("scripting")->getProgramStatusStr(progname); 00709 return toupper(ps[0]); 00710 } 00711 00712 void str_trim(string& str, char to_trim) 00713 { 00714 string::size_type pos1 = str.find_first_not_of(to_trim); 00715 string::size_type pos2 = str.find_last_not_of(to_trim); 00716 str = str.substr(pos1 == string::npos ? 0 : pos1, 00717 pos2 == string::npos ? str.length() - 1 : pos2 - pos1 + 1); 00718 } 00719 00720 00725 void TaskBrowser::loop() 00726 { 00727 #ifdef USE_SIGNALS 00728 // Let readline intercept relevant signals 00729 if(rl_catch_signals == 0) 00730 cerr << "Error: not catching signals !"<<endl; 00731 if (rl_set_signals() != 0) 00732 cerr << "Error setting signals !" <<endl; 00733 #endif 00734 cout << nl<< 00735 coloron << 00736 " This console reader allows you to browse and manipulate TaskContexts."<<nl<< 00737 " You can type in an operation, expression, create or change variables."<<nl; 00738 cout <<" (type '"<<underline<<"help"<<coloroff<<coloron<<"' for instructions and '" 00739 <<underline<<"ls"<<coloroff<<coloron<<"' for context info)"<<nl<<nl; 00740 #ifdef USE_READLINE 00741 cout << " TAB completion and HISTORY is available ('bash' like)" <<nl<<nl; 00742 #else 00743 cout << " TAB completion and history is NOT available (LGPL-version)" <<nl<<nl; 00744 #endif 00745 cout << " Use '"<<underline<<"Ctrl-D"<<coloroff<<coloron<<"' or type '"<<underline<<"quit"<<coloroff<<coloron<<"' to exit this program." <<coloroff<<nl<<nl; 00746 00747 while (1) { 00748 try { 00749 if (!macrorecording) { 00750 if ( context == tb ) 00751 cout << green << " Watching " <<coloroff; 00752 00753 char state = getTaskStatusChar(taskcontext); 00754 00755 // sets prompt for readline: 00756 // prompt = green + taskcontext->getName() + coloroff + "[" + state + "]> "; 00757 prompt = taskcontext->getName() + " [" + state + "]> "; 00758 // This 'endl' is important because it flushes the whole output to screen of all 00759 // processing that previously happened, which was using 'nl'. 00760 cout.flush(); 00761 00762 // print traces. 00763 for (PTrace::iterator it = ptraces.begin(); it != ptraces.end(); ++it) { 00764 RTT::TaskContext* progpeer = it->first.first; 00765 int line = progpeer->getProvider<Scripting>("scripting")->getProgramLine(it->first.second); 00766 if ( line != it->second ) { 00767 it->second = line; 00768 printProgram( it->first.second, -1, progpeer ); 00769 } 00770 } 00771 00772 for (PTrace::iterator it = straces.begin(); it != straces.end(); ++it) { 00773 RTT::TaskContext* progpeer = it->first.first; 00774 int line = progpeer->getProvider<Scripting>("scripting")->getStateMachineLine(it->first.second); 00775 if ( line != it->second ) { 00776 it->second = line; 00777 printProgram( it->first.second, -1, progpeer ); 00778 } 00779 } 00780 } 00781 // Check port status: 00782 checkPorts(); 00783 std::string command; 00784 // When using rxvt on windows, the process will receive signals when the arrow keys are used 00785 // during input. We compile with /EHa to catch these signals and don't print anything. 00786 try { 00787 #ifdef USE_READLINE 00788 const char* const commandStr = rl_gets(); 00789 // quit on EOF (Ctrl-D) 00790 command = commandStr ? commandStr : "quit"; // copy over to string 00791 #else 00792 cout << prompt; 00793 getline(cin,command); 00794 if (!cin) // Ctrl-D 00795 command = "quit"; 00796 #endif 00797 } catch(std::exception& e) { 00798 cerr << "The command line reader throwed a std::exception: '"<< e.what()<<"'."<<endl; 00799 } catch (...) { 00800 cerr << "The command line reader throwed an exception." <<endlog(); 00801 } 00802 str_trim( command, ' '); 00803 cout << coloroff; 00804 if ( command == "quit" ) { 00805 // Intercept no Ctrl-C 00806 cout << endl; 00807 return; 00808 } else if ( command == "help") { 00809 printHelp(); 00810 } else if ( command.find("help ") == 0) { 00811 printHelp( command.substr(command.rfind(' '))); 00812 } else if ( command == "#debug") { 00813 debug = !debug; 00814 } else if ( command.find("list ") == 0 || command == "list" ) { 00815 browserAction(command); 00816 } else if ( command.find("trace ") == 0 || command == "trace" ) { 00817 browserAction(command); 00818 } else if ( command.find("untrace ") == 0 || command == "untrace" ) { 00819 browserAction(command); 00820 } else if ( command.find("ls") == 0 ) { 00821 std::string::size_type pos = command.find("ls")+2; 00822 command = std::string(command, pos, command.length()); 00823 printInfo( command ); 00824 } else if ( command == "" ) { // nop 00825 } else if ( command.find("cd ..") == 0 ) { 00826 this->switchBack( ); 00827 } else if ( command.find("enter") == 0 ) { 00828 this->enterTask(); 00829 } else if ( command.find("leave") == 0 ) { 00830 this->leaveTask(); 00831 } else if ( command.find("cd ") == 0 ) { 00832 std::string::size_type pos = command.find("cd")+2; 00833 command = std::string(command, pos, command.length()); 00834 this->switchTaskContext( command ); 00835 } else if ( command.find(".") == 0 ) { 00836 command = std::string(command, 1, command.length()); 00837 this->browserAction( command ); 00838 } else if ( macrorecording) { 00839 macrotext += command +'\n'; 00840 } else { 00841 try { 00842 this->evalCommand( command ); 00843 } catch(std::exception& e) { 00844 cerr << "The command '"<<command<<"' caused a std::exception: '"<< e.what()<<"' and could not be completed."<<endl; 00845 } catch(...){ 00846 cerr << "The command '"<<command<<"' caused an unknown exception and could not be completed."<<endl; 00847 } 00848 // a command was typed... clear storedline such that a next 'list' 00849 // shows the 'IP' again. 00850 storedline = -1; 00851 } 00852 //cout <<endl; 00853 } catch(std::exception& e) { 00854 cerr << "Warning: The command caused a std::exception: '"<< e.what()<<"' in the TaskBrowser's loop() function."<<endl; 00855 } catch(...) { 00856 cerr << "Warning: The command caused an exception in the TaskBrowser's loop() function." << endl; 00857 } 00858 } 00859 } 00860 00861 void TaskBrowser::enterTask() 00862 { 00863 if ( context == taskcontext ) { 00864 log(Info) <<"Already in Task "<< taskcontext->getName()<<endlog(); 00865 return; 00866 } 00867 context = taskcontext; 00868 log(Info) <<"Entering Task "<< taskcontext->getName()<<endlog(); 00869 } 00870 00871 void TaskBrowser::leaveTask() 00872 { 00873 if ( context == tb ) { 00874 log(Info) <<"Already watching Task "<< taskcontext->getName()<<endlog(); 00875 return; 00876 } 00877 context = tb; 00878 log(Info) <<"Watching Task "<< taskcontext->getName()<<endlog(); 00879 } 00880 00881 void TaskBrowser::recordMacro(std::string name) 00882 { 00883 if (macrorecording) { 00884 log(Error)<< "Macro already active." <<endlog(); 00885 return; 00886 } 00887 if (context->provides()->hasService("scripting") == false) { 00888 log(Error)<< "Can not create a macro in a TaskContext without scripting service." <<endlog(); 00889 return; 00890 } 00891 if ( name.empty() ) { 00892 cerr << "Please specify a macro name." <<endl; 00893 return; 00894 } else { 00895 cout << "Recording macro "<< name <<endl; 00896 cout << "Use program scripting syntax (do, set,...) !" << endl <<endl; 00897 cout << "export function "<< name<<" {"<<endl; 00898 } 00899 macrorecording = true; 00900 macroname = name; 00901 } 00902 00903 void TaskBrowser::cancelMacro() { 00904 if (!macrorecording) { 00905 log(Warning)<< "Macro recording was not active." <<endlog(); 00906 return; 00907 } 00908 cout << "Canceling macro "<< macroname <<endl; 00909 macrorecording = false; 00910 macrotext.clear(); 00911 } 00912 00913 void TaskBrowser::endMacro() { 00914 if (!macrorecording) { 00915 log(Warning)<< "Macro recording was not active." <<endlog(); 00916 return; 00917 } 00918 string fname = macroname + ".ops"; 00919 macrorecording = false; 00920 cout << "}" <<endl; 00921 cout << "Saving file "<< fname <<endl; 00922 ofstream macrofile( fname.c_str() ); 00923 macrofile << "/* TaskBrowser macro '"<<macroname<<"' */" <<endl<<endl; 00924 macrofile << "export function "<<macroname<<" {"<<endl; 00925 macrofile << macrotext.c_str(); 00926 macrofile << "}"<<endl; 00927 macrotext.clear(); 00928 00929 cout << "Loading file "<< fname <<endl; 00930 context->getProvider<Scripting>("Scripting")->loadPrograms(fname); 00931 } 00932 00933 void TaskBrowser::switchBack() 00934 { 00935 if ( taskHistory.size() == 0) 00936 return; 00937 00938 this->switchTaskContext( taskHistory.front(), false ); // store==false 00939 lastc = 0; 00940 taskHistory.pop_front(); 00941 } 00942 00943 void TaskBrowser::checkPorts() 00944 { 00945 // check periodically if the taskcontext did not change its ports. 00946 00947 DataFlowInterface::Ports ports; 00948 ports = this->ports()->getPorts(); 00949 for( DataFlowInterface::Ports::iterator i=ports.begin(); i != ports.end(); ++i) { 00950 // If our port is no longer connected, try to reconnect. 00951 base::PortInterface* p = *i; 00952 base::PortInterface* tcp = taskcontext->ports()->getPort( p->getName() ); 00953 if ( p->connected() == false || tcp == 0 || tcp->connected() == false) { 00954 this->ports()->removePort( p->getName() ); 00955 delete p; 00956 } 00957 } 00958 } 00959 00960 void TaskBrowser::setColorTheme(ColorTheme t) 00961 { 00962 // background color palettes: 00963 const char* dbg = "\033[01;"; 00964 const char* wbg = "\033[02;"; 00965 // colors in palettes: 00966 const char* r = "31m"; 00967 const char* g = "32m"; 00968 const char* b = "34m"; 00969 const char* con = "31m"; 00970 const char* coff = "\33[0m"; 00971 const char* und = "\33[4m"; 00972 00973 switch (t) 00974 { 00975 case nocolors: 00976 green.clear(); 00977 red.clear(); 00978 blue.clear(); 00979 coloron.clear(); 00980 coloroff.clear(); 00981 underline.clear(); 00982 return; 00983 break; 00984 case darkbg: 00985 green = dbg; 00986 red = dbg; 00987 blue = dbg; 00988 coloron = dbg; 00989 coloroff = wbg; 00990 break; 00991 case whitebg: 00992 green = wbg; 00993 red = wbg; 00994 blue = wbg; 00995 coloron = wbg; 00996 coloroff = wbg; 00997 break; 00998 } 00999 green += g; 01000 red += r; 01001 blue += b; 01002 coloron += con; 01003 coloroff = coff; 01004 underline = und; 01005 } 01006 01007 void TaskBrowser::switchTaskContext(std::string& c) { 01008 // if nothing new found, return. 01009 peer = taskcontext; 01010 if ( this->findPeer( c + "." ) == 0 ) { 01011 cerr << "No such peer: "<< c <<nl; 01012 return; 01013 } 01014 01015 if ( peer == taskcontext ) { 01016 cerr << "Already in "<< c <<nl; 01017 return; 01018 } 01019 01020 if ( peer == tb ) { 01021 cerr << "Can not switch to TaskBrowser." <<nl; 01022 return; 01023 } 01024 01025 // findPeer has set 'peer' : 01026 this->switchTaskContext( peer ); 01027 } 01028 01029 void TaskBrowser::switchTaskContext(RTT::TaskContext* tc, bool store) { 01030 // put current on the stack : 01031 if (taskHistory.size() == 20 ) 01032 taskHistory.pop_back(); 01033 if ( taskcontext && store) 01034 taskHistory.push_front( taskcontext ); 01035 01036 // disconnect from current peers. 01037 this->disconnect(); 01038 01039 // cleanup port left-overs. 01040 DataFlowInterface::Ports tports = this->ports()->getPorts(); 01041 for( DataFlowInterface::Ports::iterator i=tports.begin(); i != tports.end(); ++i) { 01042 this->ports()->removePort( (*i)->getName() ); 01043 delete *i; 01044 } 01045 01046 // now switch to new one : 01047 if ( context == taskcontext ) 01048 context = tc; 01049 taskcontext = tc; // peer is the new taskcontext. 01050 lastc = 0; 01051 01052 // connect peer. 01053 this->addPeer( taskcontext ); 01054 01055 // map data ports. 01056 // create 'anti-ports' to allow port-level interaction with the peer. 01057 tports = taskcontext->ports()->getPorts(); 01058 if ( !tports.empty() ) 01059 cout <<nl << "TaskBrowser connects to all data ports of "<<taskcontext->getName()<<endl; 01060 for( DataFlowInterface::Ports::iterator i=tports.begin(); i != tports.end(); ++i) { 01061 if (this->ports()->getPort( (*i)->getName() ) == 0 ) 01062 this->ports()->addPort( *(*i)->antiClone() ); 01063 } 01064 RTT::connectPorts(this,taskcontext); 01065 01066 01067 01068 cerr << " Switched to : " << taskcontext->getName() <<endl; 01069 01070 } 01071 01072 RTT::TaskContext* TaskBrowser::findPeer(std::string c) { 01073 // returns the one but last peer, which is the one we want. 01074 std::string s( c ); 01075 01076 our_pos_iter_t parsebegin( s.begin(), s.end(), "teststring" ); 01077 our_pos_iter_t parseend; 01078 01079 CommonParser cp; 01080 scripting::PeerParser pp( peer, cp, true ); 01081 bool skipref = true; 01082 try { 01083 parse( parsebegin, parseend, pp.parser(), SKIP_PARSER ); 01084 } 01085 catch( ... ) 01086 { 01087 log(Debug) <<"No such peer : "<< c <<endlog(); 01088 return 0; 01089 } 01090 taskobject = pp.taskObject(); 01091 assert(taskobject); 01092 peer = pp.peer(); 01093 return pp.peer(); 01094 } 01095 01096 void TaskBrowser::browserAction(std::string& act) 01097 { 01098 std::stringstream ss(act); 01099 std::string instr; 01100 ss >> instr; 01101 01102 if ( instr == "list" ) { 01103 if (context->provides()->hasService("scripting") == false) { 01104 log(Error)<< "Can not list a program in a TaskContext without scripting service." <<endlog(); 01105 return; 01106 } 01107 int line; 01108 ss >> line; 01109 if (ss) { 01110 this->printProgram(line); 01111 return; 01112 } 01113 ss.clear(); 01114 string arg; 01115 ss >> arg; 01116 if (ss) { 01117 ss.clear(); 01118 ss >> line; 01119 if (ss) { 01120 // progname and line given 01121 this->printProgram(arg, line); 01122 return; 01123 } 01124 // only progname given. 01125 this->printProgram( arg ); 01126 return; 01127 } 01128 // just 'list' : 01129 this->printProgram(); 01130 return; 01131 } 01132 01133 // 01134 // TRACING 01135 // 01136 if ( instr == "trace") { 01137 if (context->provides()->hasService("scripting") == false) { 01138 log(Error)<< "Can not trace a program in a TaskContext without scripting service." <<endlog(); 01139 return; 01140 } 01141 01142 string arg; 01143 ss >> arg; 01144 if (ss) { 01145 bool pi = context->getProvider<Scripting>("scripting")->hasProgram(arg); 01146 if (pi) { 01147 ptraces[make_pair(context, arg)] = context->getProvider<Scripting>("scripting")->getProgramLine(arg); // store current line number. 01148 this->printProgram( arg ); 01149 return; 01150 } 01151 pi = context->getProvider<Scripting>("scripting")->hasStateMachine(arg); 01152 if (pi) { 01153 straces[make_pair(context, arg)] = context->getProvider<Scripting>("scripting")->getStateMachineLine(arg); // store current line number. 01154 this->printProgram( arg ); 01155 return; 01156 } 01157 cerr <<"No such program or state machine: "<< arg <<endl; 01158 return; 01159 } 01160 01161 // just 'trace' : 01162 std::vector<std::string> names; 01163 names = context->getProvider<Scripting>("scripting")->getProgramList(); 01164 for (std::vector<std::string>::iterator it = names.begin(); it != names.end(); ++it) { 01165 bool pi = context->getProvider<Scripting>("scripting")->hasProgram(arg); 01166 if (pi) 01167 ptraces[make_pair(context, arg)] = context->getProvider<Scripting>("scripting")->getProgramLine(arg); // store current line number. 01168 } 01169 01170 names = context->getProvider<Scripting>("scripting")->getStateMachineList(); 01171 for (std::vector<std::string>::iterator it = names.begin(); it != names.end(); ++it) { 01172 bool pi = context->getProvider<Scripting>("scripting")->hasStateMachine(arg); 01173 if (pi) 01174 straces[make_pair(context, arg)] = context->getProvider<Scripting>("scripting")->getStateMachineLine(arg); // store current line number. 01175 } 01176 01177 cerr << "Tracing all programs and state machines in "<< context->getName() << endl; 01178 return; 01179 } 01180 01181 if ( instr == "untrace") { 01182 if (context->provides()->hasService("scripting") == false) { 01183 log(Error)<< "Can not untrace a program in a TaskContext without scripting service." <<endlog(); 01184 return; 01185 } 01186 string arg; 01187 ss >> arg; 01188 if (ss) { 01189 ptraces.erase( make_pair(context, arg) ); 01190 straces.erase( make_pair(context, arg) ); 01191 cerr <<"Untracing "<< arg <<" of "<< context->getName()<<endl; 01192 return; 01193 } 01194 // just 'untrace' : 01195 std::vector<std::string> names; 01196 names = context->getProvider<Scripting>("scripting")->getProgramList(); 01197 for (std::vector<std::string>::iterator it = names.begin(); it != names.end(); ++it) { 01198 bool pi = context->getProvider<Scripting>("scripting")->hasProgram(arg); 01199 if (pi) 01200 ptraces.erase(make_pair(context, arg)); 01201 } 01202 01203 names = context->getProvider<Scripting>("scripting")->getStateMachineList(); 01204 for (std::vector<std::string>::iterator it = names.begin(); it != names.end(); ++it) { 01205 bool pi = context->getProvider<Scripting>("scripting")->hasStateMachine(arg); 01206 if (pi) 01207 straces.erase(make_pair(context, arg)); 01208 } 01209 01210 cerr << "Untracing all programs and state machines of "<< context->getName() << endl; 01211 return; 01212 } 01213 01214 std::string arg; 01215 ss >> arg; 01216 if ( instr == "dark") { 01217 this->setColorTheme(darkbg); 01218 cout << nl << "Setting Color Theme for "+green+"dark"+coloroff+" backgrounds."<<endl; 01219 return; 01220 } 01221 if ( instr == "light") { 01222 this->setColorTheme(whitebg); 01223 cout << nl << "Setting Color Theme for "+green+"light"+coloroff+" backgrounds."<<endl; 01224 return; 01225 } 01226 if ( instr == "nocolors") { 01227 this->setColorTheme(nocolors); 01228 cout <<nl << "Disabling all colors"<<endl; 01229 return; 01230 } 01231 if ( instr == "record") { 01232 recordMacro( arg ); 01233 return; 01234 } 01235 if ( instr == "cancel") { 01236 cancelMacro(); 01237 return; 01238 } 01239 if ( instr == "end") { 01240 endMacro(); 01241 return; 01242 } 01243 if ( instr == "hex") { 01244 usehex = true; 01245 cout << "Switching to hex notation for output (use .nohex to revert)." <<endl; 01246 return; 01247 } 01248 if ( instr == "nohex") { 01249 usehex = false; 01250 cout << "Turning off hex notation for output." <<endl; 01251 return; 01252 } 01253 if ( instr == "provide") { 01254 while ( ss ) { 01255 cout << "Trying to locate service '" << arg << "'..."<<endl; 01256 if ( PluginLoader::Instance()->loadService(arg, context) ) 01257 cout << "Service '"<< arg << "' loaded in " << context->getName() << endl; 01258 else 01259 cout << "Service not found." <<endl; 01260 ss >> arg; 01261 } 01262 return; 01263 } 01264 if (instr == "services") { 01265 vector<string> names = PluginLoader::Instance()->listServices(); 01266 cout << "Available Services: "; 01267 for (std::vector<std::string>::iterator it = names.begin(); it != names.end(); ++it) { 01268 cout << " " << *it; 01269 } 01270 cout <<endl; 01271 return; 01272 } 01273 if (instr == "typekits") { 01274 vector<string> names = PluginLoader::Instance()->listTypekits(); 01275 cout << "Available Typekits: "; 01276 for (std::vector<std::string>::iterator it = names.begin(); it != names.end(); ++it) { 01277 cout << " " << *it; 01278 } 01279 cout <<endl; 01280 return; 01281 } 01282 if (instr == "types") { 01283 vector<string> names = TypeInfoRepository::Instance()->getDottedTypes(); 01284 cout << "Available data types: "; 01285 for (std::vector<std::string>::iterator it = names.begin(); it != names.end(); ++it) { 01286 cout << " " << *it; 01287 } 01288 cout <<endl; 01289 return; 01290 } 01291 cerr << "Unknown Browser Action : "<< act <<endl; 01292 cerr << "See 'help' for valid syntax."<<endl; 01293 } 01294 01295 void TaskBrowser::evaluate(std::string& comm) { 01296 this->evalCommand(comm); 01297 } 01298 01299 Service::shared_ptr TaskBrowser::stringToService(string const& names) { 01300 Service::shared_ptr serv; 01301 std::vector<std::string> strs; 01302 boost::split(strs, names, boost::is_any_of(".")); 01303 01304 // strs could be empty because of a bug in Boost 1.44 (see https://svn.boost.org/trac/boost/ticket/4751) 01305 if (strs.empty()) return serv; 01306 01307 string component = strs.front(); 01308 if (! context->hasPeer(component) && !context->provides()->hasService(component) ) { 01309 return serv; 01310 } 01311 // We only support help for peer or subservice: 01312 if ( context->hasPeer(component) ) 01313 serv = context->getPeer(component)->provides(); 01314 else if (context->provides()->hasService(component)) 01315 serv = context->provides(component); 01316 01317 // remove component name: 01318 strs.erase( strs.begin() ); 01319 01320 // iterate over remainders: 01321 while ( !strs.empty() && serv) { 01322 serv = serv->getService( strs.front() ); 01323 if (serv) 01324 strs.erase( strs.begin() ); 01325 } 01326 return serv; 01327 } 01328 01329 01330 01331 bool TaskBrowser::printService( string name ) { 01332 bool result = false; 01333 Service::shared_ptr ops = stringToService(name); 01334 ServiceRequester* sr = 0; 01335 01336 if ( ops || GlobalService::Instance()->hasService( name ) ) // only object name was typed 01337 { 01338 if ( !ops ) 01339 ops = GlobalService::Instance()->provides(name); 01340 sresult << nl << "Printing Interface of '"<< coloron << ops->getName() <<coloroff <<"' :"<<nl<<nl; 01341 vector<string> methods = ops->getNames(); 01342 std::for_each( methods.begin(), methods.end(), boost::bind(&TaskBrowser::printOperation, this, _1, ops) ); 01343 cout << sresult.str(); 01344 sresult.str(""); 01345 result = true; 01346 } 01347 if ( context->requires()->requiresService( name ) ) // only object name was typed 01348 { 01349 sr = context->requires(name); 01350 sresult << nl << "Requiring '"<< coloron << sr->getRequestName() <<coloroff <<"' with methods: "; 01351 vector<string> methods = sr->getOperationCallerNames(); 01352 sresult << coloron; 01353 std::for_each( methods.begin(), methods.end(), sresult << lambda::_1 <<" " ); 01354 cout << sresult.str() << coloroff << nl; 01355 sresult.str(""); 01356 result = true; 01357 } 01358 return result; 01359 } 01360 01361 void TaskBrowser::evalCommand(std::string& comm ) 01362 { 01363 // deprecated: use 'help servicename' 01364 bool result = printService(comm); 01365 01366 // Minor hack : also check if it was an attribute of current TC, for example, 01367 // if both the object and attribute with that name exist. the if 01368 // statement after this one would return and not give the expr parser 01369 // time to evaluate 'comm'. 01370 if ( context->provides()->getValue( comm ) ) { 01371 if (debug) 01372 cerr << "Found value..."<<nl; 01373 this->printResult( context->provides()->getValue( comm )->getDataSource().get(), true ); 01374 cout << sresult.str()<<nl; 01375 sresult.str(""); 01376 return; 01377 } 01378 01379 if ( result ) { 01380 return; 01381 } 01382 01383 // Set caller=0 to have correct call/send semantics. 01384 // we're outside the updateHook(). Passing 'this' would 01385 // trigger the EE of the TB, but not our own function. 01386 scripting::Parser _parser( 0 ); 01387 01388 if (debug) 01389 cerr << "Trying ValueStatement..."<<nl; 01390 try { 01391 // Check if it was a method or datasource : 01392 last_expr = _parser.parseValueStatement( comm, context ); 01393 // methods and DS'es are processed immediately. 01394 if ( last_expr ) { 01395 // only print if no ';' was given. 01396 assert( comm.size() != 0 ); 01397 if ( comm[ comm.size() - 1 ] != ';' ) { 01398 this->printResult( last_expr.get(), true ); 01399 cout << sresult.str() << nl <<endl; 01400 sresult.str(""); 01401 } else 01402 last_expr->evaluate(); 01403 return; // done here 01404 } else if (debug) 01405 cerr << "returned (null) !"<<nl; 01406 //cout << " (ok)" <<nl; 01407 //return; // 01408 } catch ( fatal_semantic_parse_exception& pe ) { // incorr args, ... 01409 // way to fatal, must be reported immediately 01410 if (debug) 01411 cerr << "fatal_semantic_parse_exception: "; 01412 cerr << pe.what() <<nl; 01413 return; 01414 } catch ( syntactic_parse_exception& pe ) { // wrong content after = sign etc.. 01415 // syntactic errors must be reported immediately 01416 if (debug) 01417 cerr << "syntactic_parse_exception: "; 01418 cerr << pe.what() <<nl; 01419 return; 01420 } catch ( parse_exception_parser_fail &pe ) 01421 { 01422 // ignore, try next parser 01423 if (debug) { 01424 cerr << "Ignoring ValueStatement exception :"<<nl; 01425 cerr << pe.what() <<nl; 01426 } 01427 } catch ( parse_exception& pe ) { 01428 // syntactic errors must be reported immediately 01429 if (debug) 01430 cerr << "parse_exception :"; 01431 cerr << pe.what() <<nl; 01432 return; 01433 } 01434 if (debug) 01435 cerr << "Trying Expression..."<<nl; 01436 try { 01437 // Check if it was a method or datasource : 01438 last_expr = _parser.parseExpression( comm, context ); 01439 // methods and DS'es are processed immediately. 01440 if ( last_expr ) { 01441 // only print if no ';' was given. 01442 assert( comm.size() != 0 ); 01443 if ( comm[ comm.size() - 1 ] != ';' ) { 01444 this->printResult( last_expr.get(), true ); 01445 cout << sresult.str() << nl << endl; 01446 sresult.str(""); 01447 } else 01448 last_expr->evaluate(); 01449 return; // done here 01450 } else if (debug) 01451 cerr << "returned (null) !"<<nl; 01452 } catch ( syntactic_parse_exception& pe ) { // missing brace etc 01453 // syntactic errors must be reported immediately 01454 if (debug) 01455 cerr << "syntactic_parse_exception :"; 01456 cerr << pe.what() <<nl; 01457 return; 01458 } catch ( fatal_semantic_parse_exception& pe ) { // incorr args, ... 01459 // way to fatal, must be reported immediately 01460 if (debug) 01461 cerr << "fatal_semantic_parse_exception :"; 01462 cerr << pe.what() <<nl; 01463 return; 01464 } catch ( parse_exception_parser_fail &pe ) 01465 { 01466 // We're the last parser! 01467 if (debug) 01468 cerr << "Ignoring Expression exception :"<<nl; 01469 cerr << pe.what() <<nl; 01470 01471 } catch ( parse_exception& pe ) { 01472 // We're the last parser! 01473 if (debug) 01474 cerr << "Ignoring Expression parse_exception :"<<nl; 01475 cerr << pe.what() <<nl; 01476 } 01477 } 01478 01479 void TaskBrowser::printResult( base::DataSourceBase* ds, bool recurse) { 01480 std::string prompt(" = "); 01481 // setup prompt : 01482 sresult <<prompt<< setw(20)<<left; 01483 if ( ds ) 01484 doPrint( ds, recurse ); 01485 else 01486 sresult << "(null)"; 01487 sresult << right; 01488 } 01489 01490 void TaskBrowser::doPrint( base::DataSourceBase::shared_ptr ds, bool recurse) { 01491 if (!ds) { 01492 sresult << "(null)"; 01493 return; 01494 } 01495 01496 // this is needed for ds's that rely on initialision. 01497 // e.g. eval true once or time measurements. 01498 // becomes only really handy for 'watches' (to deprecate). 01499 ds->reset(); 01500 // this is needed to read a ds's value. Otherwise, a cached value may be returned. 01501 ds->evaluate(); 01502 01503 DataSource<RTT::PropertyBag>* dspbag = DataSource<RTT::PropertyBag>::narrow(ds.get()); 01504 if (dspbag) { 01505 RTT::PropertyBag bag( dspbag->get() ); 01506 if (!recurse) { 01507 int siz = bag.getProperties().size(); 01508 int wdth = siz ? (20 - (siz / 10 + 1)) : 20; 01509 sresult <<setw(0)<< siz <<setw( wdth )<< " Properties"; 01510 } else { 01511 if ( ! bag.empty() ) { 01512 sresult <<setw(0)<<nl; 01513 for( RTT::PropertyBag::iterator it= bag.getProperties().begin(); it!=bag.getProperties().end(); ++it) { 01514 sresult <<setw(14)<<right<< Types()->toDot( (*it)->getType() )<<" "<<coloron<<setw(14)<< (*it)->getName()<<coloroff; 01515 base::DataSourceBase::shared_ptr propds = (*it)->getDataSource(); 01516 this->printResult( propds.get(), false ); 01517 sresult <<" ("<<(*it)->getDescription()<<')' << nl; 01518 } 01519 } else { 01520 sresult <<prompt<<"(empty RTT::PropertyBag)"; 01521 } 01522 } 01523 return; 01524 } 01525 01526 // Print the members of the type: 01527 base::DataSourceBase::shared_ptr dsb(ds); 01528 if (dsb->getMemberNames().empty() || dsb->getTypeInfo()->isStreamable() ) { 01529 if (debug) cerr << "terminal item " << dsb->getTypeName() << nl; 01530 if (usehex) 01531 sresult << std::hex << dsb; 01532 else 01533 sresult << std::dec << dsb; 01534 } else { 01535 sresult << setw(0); 01536 sresult << "{"; 01537 vector<string> names = dsb->getMemberNames(); 01538 if ( find(names.begin(), names.end(), "capacity") != names.end() && 01539 find(names.begin(), names.end(), "size") != names.end() ) { 01540 // is a container/sequence: 01541 DataSource<int>::shared_ptr seq_size = dynamic_pointer_cast<DataSource<int> >(dsb->getMember("size")); 01542 if (seq_size) { 01543 ValueDataSource<unsigned int>::shared_ptr index = new ValueDataSource<unsigned int>(0); 01544 // print max 10 items of sequence: 01545 sresult << " ["; 01546 for (int i=0; i != seq_size->get(); ++i) { 01547 index->set( i ); 01548 if (i == 10) { 01549 sresult << "...("<< seq_size->get() - 10 <<" items omitted)..."; 01550 break; 01551 } else { 01552 DataSourceBase::shared_ptr element = dsb->getMember(index, DataSourceBase::shared_ptr() ); 01553 doPrint(element, true); 01554 if (i+1 != seq_size->get()) 01555 sresult <<", "; 01556 } 01557 } 01558 sresult << " ], "; // size and capacity will follow... 01559 } 01560 } 01561 for(vector<string>::iterator it = names.begin(); it != names.end(); ) { 01562 sresult << *it << " = "; 01563 doPrint( dsb->getMember(*it), true); 01564 if (++it != names.end()) 01565 sresult <<", "; 01566 } 01567 sresult <<" }"; 01568 } 01569 } 01570 01571 struct comcol 01572 { 01573 const char* command; 01574 comcol(const char* c) :command(c) {} 01575 std::ostream& operator()( std::ostream& os ) const { 01576 os<<"'"<< TaskBrowser::coloron<< TaskBrowser::underline << command << TaskBrowser::coloroff<<"'"; 01577 return os; 01578 } 01579 }; 01580 01581 struct keycol 01582 { 01583 const char* command; 01584 keycol(const char* c) :command(c) {} 01585 std::ostream& operator()( std::ostream& os )const { 01586 os<<"<"<< TaskBrowser::coloron<< TaskBrowser::underline << command << TaskBrowser::coloroff<<">"; 01587 return os; 01588 } 01589 }; 01590 01591 struct titlecol 01592 { 01593 const char* command; 01594 titlecol(const char* c) :command(c) {} 01595 std::ostream& operator()( std::ostream& os ) const { 01596 os<<endl<<"["<< TaskBrowser::coloron<< TaskBrowser::underline << command << TaskBrowser::coloroff<<"]"; 01597 return os; 01598 } 01599 }; 01600 01601 std::ostream& operator<<(std::ostream& os, comcol f ){ 01602 return f(os); 01603 } 01604 01605 std::ostream& operator<<(std::ostream& os, keycol f ){ 01606 return f(os); 01607 } 01608 01609 std::ostream& operator<<(std::ostream& os, titlecol f ){ 01610 return f(os); 01611 } 01612 01613 void TaskBrowser::printHelp() 01614 { 01615 cout << coloroff; 01616 cout <<titlecol("Task Browsing")<<nl; 01617 cout << " To switch to another task, type "<<comcol("cd <path-to-taskname>")<<nl; 01618 cout << " and type "<<comcol("cd ..")<<" to go back to the previous task (History size is 20)."<<nl; 01619 cout << " Pressing "<<keycol("tab")<<" multiple times helps you to complete your command."<<nl; 01620 cout << " It is not mandatory to switch to a task to interact with it, you can type the"<<nl; 01621 cout << " peer-path to the task (dot-separated) and then type command or expression :"<<nl; 01622 cout << " PeerTask.OtherTask.FinalTask.countTo(3) [enter] "<<nl; 01623 cout << " Where 'countTo' is a method of 'FinalTask'."<<nl; 01624 cout << " The TaskBrowser starts by default 'In' the current component. In order to watch"<<nl; 01625 cout << " the TaskBrowser itself, type "<<comcol("leave")<<" You will notice that it"<<nl; 01626 cout << " has connected to the data ports of the visited component. Use "<<comcol("enter")<<" to enter"<<nl; 01627 cout << " the visited component again. The "<<comcol("cd")<<" command works transparantly in both"<<nl; 01628 cout << " modi."<<nl; 01629 01630 cout << " "<<titlecol("Task Context Info")<<nl; 01631 cout << " To see the contents of a task, type "<<comcol("ls")<<nl; 01632 cout << " For a detailed argument list (and helpful info) of the object's methods, "<<nl; 01633 cout <<" type the name of one of the listed task objects : " <<nl; 01634 cout <<" this [enter]" <<nl<<nl; 01635 cout <<" factor( int number ) : bool" <<nl; 01636 cout <<" Factor a value into its primes." <<nl; 01637 cout <<" number : The number to factor in primes." <<nl; 01638 cout <<" isRunning( ) : bool" <<nl; 01639 cout <<" Is this RTT::TaskContext started ?" <<nl; 01640 cout <<" loadProgram( const& std::string Filename ) : bool" <<nl; 01641 cout <<" Load an Orocos Program Script from a file." <<nl; 01642 cout <<" Filename : An ops file." <<nl; 01643 cout <<" ..."<<nl; 01644 01645 cout << " A status character shows the TaskState of a component."<<nl; 01646 cout << " 'E':RunTimeError, 'S':Stopped, 'R':Running, 'U':PreOperational (Unconfigured)"<<nl; 01647 cout << " 'X':Exception, 'F':FatalError" << nl; 01648 01649 cout <<titlecol("Expressions")<<nl; 01650 cout << " You can evaluate any script expression by merely typing it :"<<nl; 01651 cout << " 1+1 [enter]" <<nl; 01652 cout << " = 2" <<nl; 01653 cout << " or inspect the status of a program :"<<nl; 01654 cout << " myProgram.isRunning [enter]" <<nl; 01655 cout << " = false" <<nl; 01656 cout << " and display the contents of complex data types (vector, array,...) :"<<nl; 01657 cout << " array(6)" <<nl; 01658 cout << " = {0, 0, 0, 0, 0, 0}" <<nl; 01659 01660 cout <<titlecol("Changing Attributes and Properties")<<nl; 01661 cout << " To change the value of a Task's attribute, type "<<comcol("varname = <newvalue>")<<nl; 01662 cout << " If you provided a correct assignment, the browser will inform you of the success"<<nl; 01663 cout <<" with the set value." <<nl; 01664 01665 cout <<titlecol("Operations")<<nl; 01666 cout << " An Operation is sent or called (evaluated) "<<nl; 01667 cout << " immediately and print the result. An example could be :"<<nl; 01668 cout << " someTask.bar.getNumberOfBeers(\"Palm\") [enter] "<<nl; 01669 cout << " = 99" <<nl; 01670 cout << " You can ask help on an operation by using the 'help' command: "<<nl; 01671 cout << " help start"<<nl; 01672 cout << " start( ) : bool"<<nl; 01673 cout << " Start this TaskContext (= startHook() + updateHook() )." <<nl; 01674 01675 cout <<titlecol("Program and scripting::StateMachine Scripts")<<nl; 01676 cout << " To load a program script use the scripting service."<<nl; 01677 cout << " Use "<<comcol(".provide scripting")<< " to load the scripting service in a TaskContext."<<nl; 01678 cout << " You can use "<<comcol("ls progname")<<nl; 01679 cout << " to see the programs operations and variables. You can manipulate each one of these"<<nl; 01680 cout << " using the service object of the program."<<nl; 01681 01682 cout << " To print a program or state machine listing, use "<<comcol("list progname [linenumber]")<<nl; 01683 cout << " to list the contents of the current program lines being executed,"<<nl; 01684 cout << " or 10 lines before or after <linenumber>. When only "<<comcol("list [n]")<<nl; 01685 cout << " is typed, 20 lines of the last listed program are printed from line <n> on "<<nl; 01686 cout << " ( default : list next 20 lines after previous list )."<<nl; 01687 01688 cout << " To trace a program or state machine listing, use "<<comcol("trace [progname]")<<" this will"<<nl; 01689 cout << " cause the TaskBrowser to list the contents of a traced program,"<<nl; 01690 cout << " each time the line number of the traced program changes."<<nl; 01691 cout << " Disable tracing with "<<comcol("untrace [progname]")<<""<<nl; 01692 cout << " If no arguments are given to "<<comcol("trace")<<" and "<<comcol("untrace")<<", it applies to all programs."<<nl; 01693 01694 cout << " A status character shows which line is being executed."<<nl; 01695 cout << " For programs : 'E':Error, 'S':Stopped, 'R':Running, 'P':Paused"<<nl; 01696 cout << " For state machines : <the same as programs> + 'A':Active, 'I':Inactive"<<nl; 01697 01698 cout <<titlecol("Changing Colors")<<nl; 01699 cout << " You can inform the TaskBrowser of your background color by typing "<<comcol(".dark")<<nl; 01700 cout << " "<<comcol(".light")<<", or "<<comcol(".nocolors")<<" to increase readability."<<nl; 01701 01702 cout <<titlecol("Output Formatting")<<nl; 01703 cout << " Use the commands "<<comcol(".hex") << " or " << comcol(".nohex") << " to turn hexadecimal "<<nl; 01704 cout << " notation of integers on or off."<<nl; 01705 01706 cout <<titlecol("Macro Recording / RTT::Command line history")<<nl; 01707 cout << " You can browse the commandline history by using the up-arrow key or press "<<comcol("Ctrl r")<<nl; 01708 cout << " and a search term. Hit enter to execute the current searched command."<<nl; 01709 cout << " Macros can be recorded using the "<<comcol(".record 'macro-name'")<<" command."<<nl; 01710 cout << " You can cancel the recording by typing "<<comcol(".cancel")<<" ."<<nl; 01711 cout << " You can save and load the macro by typing "<<comcol(".end")<<" . The macro becomes"<<nl; 01712 cout << " available as a command with name 'macro-name' in the current TaskContext." << nl; 01713 cout << " While you enter the macro, it is not executed, as you must use scripting syntax which"<<nl; 01714 cout << " may use loop or conditional statements, variables etc."<<nl; 01715 01716 cout <<titlecol("Connecting Ports")<<nl; 01717 cout << " You can instruct the TaskBrowser to connect to the ports of the current Peer by"<<nl; 01718 cout << " typing "<<comcol(".connect [port-name]")<<", which will temporarily create connections"<<nl; 01719 cout << " to all ports if [port-name] is omitted or to the specified port otherwise."<<nl; 01720 cout << " The TaskBrowser disconnects these ports when it visits another component, but the"<<nl; 01721 cout << " created connection objects remain in place (this is more or less a bug)!"<<nl; 01722 01723 cout <<titlecol("Plugins, Typekits and Services")<<nl; 01724 cout << " Use "<<comcol(".provide [servicename]")<< " to load a service in a TaskContext."<<nl; 01725 cout << " For example, to add XML marshalling, type: "<<comcol(".provide marshalling")<< "."<<nl; 01726 cout << " Use "<<comcol(".services")<< " to get a list of available services."<<nl; 01727 cout << " Use "<<comcol(".typekits")<< " to get a list of available typekits."<<nl; 01728 cout << " Use "<<comcol(".types")<< " to get a list of available data types."<<nl; 01729 } 01730 01731 void TaskBrowser::printHelp( string helpstring ) { 01732 peer = context; 01733 // trim garbage: 01734 str_trim(helpstring, ' '); 01735 str_trim(helpstring, '.'); 01736 01737 if ( printService(helpstring)) 01738 return; 01739 01740 if ( findPeer( helpstring ) ) { 01741 try { 01742 // findPeer resolved the taskobject holding 'helpstring'. 01743 sresult << nl; 01744 if (helpstring.rfind('.') != string::npos ) 01745 printOperation( helpstring.substr(helpstring.rfind('.')+1 ), taskobject ); 01746 else 01747 printOperation( helpstring, taskobject ); 01748 cout << sresult.str(); 01749 } catch (...) { 01750 cerr<< " help: No such operation known: '"<< helpstring << "'"<<nl; 01751 } 01752 } else { 01753 cerr<< " help: No such operation known (peer not found): '"<< helpstring << "'"<<nl; 01754 } 01755 sresult.str(""); 01756 } 01757 01758 void TaskBrowser::printProgram(const std::string& progname, int cl /*= -1*/, RTT::TaskContext* progpeer /* = 0 */) { 01759 string ps; 01760 char s; 01761 stringstream txtss; 01762 int ln; 01763 int start; 01764 int end; 01765 bool found(false); 01766 01767 if (progpeer == 0 ) 01768 progpeer = context; 01769 01770 // if program exists, display. 01771 if ( progpeer->getProvider<Scripting>("scripting")->hasProgram( progname ) ) { 01772 s = getProgramStatusChar(progpeer, progname); 01773 txtss.str( progpeer->getProvider<Scripting>("scripting")->getProgramText(progname) ); 01774 ln = progpeer->getProvider<Scripting>("scripting")->getProgramLine(progname); 01775 if ( cl < 0 ) cl = ln; 01776 start = cl < 10 ? 1 : cl - 10; 01777 end = cl + 10; 01778 this->listText( txtss, start, end, ln, s); 01779 found = true; 01780 } 01781 01782 // If statemachine exists, display. 01783 if ( progpeer->getProvider<Scripting>("scripting")->hasStateMachine( progname ) ) { 01784 s = getStateMachineStatusChar(progpeer, progname); 01785 txtss.str( progpeer->getProvider<Scripting>("scripting")->getStateMachineText(progname) ); 01786 ln = progpeer->getProvider<Scripting>("scripting")->getStateMachineLine(progname); 01787 if ( cl < 0 ) cl = ln; 01788 start = cl <= 10 ? 1 : cl - 10; 01789 end = cl + 10; 01790 this->listText( txtss, start, end, ln, s); 01791 found = true; 01792 } 01793 if ( !found ) { 01794 cerr << "Error : No such program or state machine found : "<<progname; 01795 cerr << " in "<< progpeer->getName() <<"."<<endl; 01796 return; 01797 } 01798 storedname = progname; 01799 } 01800 01801 void TaskBrowser::printProgram(int cl /* = -1 */) { 01802 string ps; 01803 char s; 01804 stringstream txtss; 01805 int ln; 01806 int start; 01807 int end; 01808 bool found(false); 01809 if ( context->getProvider<Scripting>("scripting")->hasProgram( storedname ) ) { 01810 s = getProgramStatusChar(context, storedname); 01811 txtss.str( context->getProvider<Scripting>("scripting")->getProgramText(storedname) ); 01812 ln = context->getProvider<Scripting>("scripting")->getProgramLine(storedname); 01813 if ( cl < 0 ) cl = storedline; 01814 if (storedline < 0 ) cl = ln -10; 01815 start = cl; 01816 end = cl + 20; 01817 this->listText( txtss, start, end, ln, s); 01818 found = true; 01819 } 01820 if ( context->getProvider<Scripting>("scripting")->hasStateMachine(storedname) ) { 01821 s = getStateMachineStatusChar(context, storedname); 01822 txtss.str( context->getProvider<Scripting>("scripting")->getStateMachineText(storedname) ); 01823 ln = context->getProvider<Scripting>("scripting")->getStateMachineLine(storedname); 01824 if ( cl < 0 ) cl = storedline; 01825 if (storedline < 0 ) cl = ln -10; 01826 start = cl; 01827 end = cl+20; 01828 this->listText( txtss, start, end, ln, s); 01829 found = true; 01830 } 01831 if ( !found ) 01832 cerr << "Error : No such program or state machine found : "<<storedname<<endl; 01833 } 01834 01835 void TaskBrowser::listText(stringstream& txtss,int start, int end, int ln, char s) { 01836 int curln = 1; 01837 string line; 01838 while ( start > 1 && curln != start ) { // consume lines 01839 getline( txtss, line, '\n' ); 01840 if ( ! txtss ) 01841 break; // no more lines, break. 01842 ++curln; 01843 } 01844 while ( end > start && curln != end ) { // print lines 01845 getline( txtss, line, '\n' ); 01846 if ( ! txtss ) 01847 break; // no more lines, break. 01848 if ( curln == ln ) { 01849 cout << s<<'>'; 01850 } 01851 else 01852 cout << " "; 01853 cout<< setw(int(log(double(end)))) <<right << curln<< left; 01854 cout << ' ' << line <<endl; 01855 ++curln; 01856 } 01857 storedline = curln; 01858 // done ! 01859 } 01860 01861 void TaskBrowser::printInfo(const std::string& peerp) 01862 { 01863 // this sets this->peer to the peer given 01864 peer = context; 01865 if ( this->findPeer( peerp+"." ) == 0 ) { 01866 cerr << "No such peer or object: " << peerp << endl; 01867 return; 01868 } 01869 01870 if ( !peer || !peer->ready()) { 01871 cout << nl << " Connection to peer "+peerp+" lost (peer->ready() == false)." <<endlog(); 01872 return; 01873 } 01874 01875 // sresult << *it << "["<<getTaskStatusChar(peer->getPeer(*it))<<"] "; 01876 01877 01878 if ( peer->provides() == taskobject ) 01879 sresult <<nl<<" Listing TaskContext "<< green << peer->getName()<<coloroff << "["<<getTaskStatusChar(peer)<<"] :"<<nl; 01880 else 01881 sresult <<nl<<" Listing Service "<< green << taskobject->getName()<<coloroff<< "["<<getTaskStatusChar(peer)<<"] :"<<nl; 01882 01883 sresult <<nl<<" Configuration Properties: "; 01884 RTT::PropertyBag* bag = taskobject->properties(); 01885 if ( bag && bag->size() != 0 ) { 01886 // Print Properties: 01887 for( RTT::PropertyBag::iterator it = bag->begin(); it != bag->end(); ++it) { 01888 base::DataSourceBase::shared_ptr pds = (*it)->getDataSource(); 01889 sresult << nl << setw(11)<< right << Types()->toDot( (*it)->getType() )<< " " 01890 << coloron <<setw(14)<<left<< (*it)->getName() << coloroff; 01891 this->printResult( pds.get(), false ); // do not recurse 01892 sresult<<" ("<< (*it)->getDescription() <<')'; 01893 } 01894 } else { 01895 sresult << "(none)"; 01896 } 01897 sresult <<nl; 01898 01899 // Print "this" interface (without detail) and then list objects... 01900 sresult <<nl<< " Provided Interface:"; 01901 01902 sresult <<nl<< " Attributes : "; 01903 std::vector<std::string> objlist = taskobject->getAttributeNames(); 01904 if ( !objlist.empty() ) { 01905 sresult << nl; 01906 // Print Attributes: 01907 for( std::vector<std::string>::iterator it = objlist.begin(); it != objlist.end(); ++it) { 01908 base::DataSourceBase::shared_ptr pds = taskobject->getValue(*it)->getDataSource(); 01909 sresult << setw(11)<< right << Types()->toDot( pds->getType() )<< " " 01910 << coloron <<setw( 14 )<<left<< *it << coloroff; 01911 this->printResult( pds.get(), false ); // do not recurse 01912 sresult <<nl; 01913 } 01914 } else { 01915 sresult << coloron << "(none)"; 01916 } 01917 01918 sresult <<coloroff<<nl<< " Operations : "<<coloron; 01919 objlist = taskobject->getNames(); 01920 if ( !objlist.empty() ) { 01921 std::copy(objlist.begin(), objlist.end(), std::ostream_iterator<std::string>(sresult, " ")); 01922 } else { 01923 sresult << "(none)"; 01924 } 01925 sresult << coloroff << nl; 01926 01927 sresult <<nl<< " Data Flow Ports: "; 01928 objlist = taskobject->getPortNames(); 01929 if ( !objlist.empty() ) { 01930 for(vector<string>::iterator it = objlist.begin(); it != objlist.end(); ++it) { 01931 base::PortInterface* port = taskobject->getPort(*it); 01932 bool writer = dynamic_cast<OutputPortInterface*>(port) ? true : false; 01933 // Port type R/W 01934 sresult << nl << " " << ( !writer ? 01935 " In" : "Out"); 01936 // Port data type + name 01937 if ( !port->connected() ) 01938 sresult << "(U) " << setw(11)<<right<< Types()->toDot( port->getTypeInfo()->getTypeName() ); 01939 else 01940 sresult << "(C) " << setw(11)<<right<< Types()->toDot( port->getTypeInfo()->getTypeName() ); 01941 sresult << " " 01942 << coloron <<setw( 14 )<<left<< *it << coloroff; 01943 01944 InputPortInterface* iport = dynamic_cast<InputPortInterface*>(port); 01945 if (iport) { 01946 sresult << " <= ( use '"<< iport->getName() << ".read(sample)' to read a sample from this port)"; 01947 } 01948 OutputPortInterface* oport = dynamic_cast<OutputPortInterface*>(port); 01949 if (oport) { 01950 if ( oport->keepsLastWrittenValue()) { 01951 DataSourceBase::shared_ptr dsb = oport->getDataSource(); 01952 dsb->evaluate(); // read last written value. 01953 sresult << " => " << dsb; 01954 } else 01955 sresult << " => (keepsLastWrittenValue() == false. Enable it for this port in order to see it in the TaskBrowser.)"; 01956 } 01957 #if 0 01958 // only show if we're connected to it 01959 if (peer == taskcontext && peer->provides() == taskobject) { 01960 // Lookup if we have an input with that name and 01961 // consume the last sample this port produced. 01962 InputPortInterface* iport = dynamic_cast<InputPortInterface*>(ports()->getPort(port->getName())); 01963 if (iport) { 01964 // consume sample 01965 iport->getDataSource()->evaluate(); 01966 // display 01967 if ( peer == this) 01968 sresult << " <= " << DataSourceBase::shared_ptr( iport->getDataSource()); 01969 else 01970 sresult << " => " << DataSourceBase::shared_ptr( iport->getDataSource()); 01971 } 01972 OutputPortInterface* oport = dynamic_cast<OutputPortInterface*>(ports()->getPort(port->getName())); 01973 if (oport) { 01974 // display last written value: 01975 DataSourceBase::shared_ptr ds = oport->getDataSource(); 01976 if (ds) { 01977 if ( peer == this) 01978 sresult << " => " << ds; 01979 else 01980 sresult << " <= " << ds << " (sent from TaskBrowser)"; 01981 } else { 01982 sresult << "(no last written value kept)"; 01983 } 01984 } 01985 } else { 01986 sresult << "(TaskBrowser not connected to this port)"; 01987 } 01988 #endif 01989 // Port description (see Service) 01990 // if ( peer->provides(*it) ) 01991 // sresult << " ( "<< taskobject->provides(*it)->getDescription() << " ) "; 01992 } 01993 } else { 01994 sresult << "(none)"; 01995 } 01996 sresult << coloroff << nl; 01997 01998 objlist = taskobject->getProviderNames(); 01999 sresult <<nl<< " Services: "<<nl; 02000 if ( !objlist.empty() ) { 02001 for(vector<string>::iterator it = objlist.begin(); it != objlist.end(); ++it) 02002 sresult <<coloron<< " " << setw(14) << *it <<coloroff<< " ( "<< taskobject->provides(*it)->doc() << " ) "<<nl; 02003 } else { 02004 sresult <<coloron<< "(none)" <<coloroff <<nl; 02005 } 02006 02007 // RTT::TaskContext specific: 02008 if ( peer->provides() == taskobject ) { 02009 02010 objlist = peer->requires()->getOperationCallerNames(); 02011 sresult <<nl<< " Requires Operations :"; 02012 if ( !objlist.empty() ) { 02013 for(vector<string>::iterator it = objlist.begin(); it != objlist.end(); ++it) 02014 sresult <<coloron<< " " << *it <<coloroff << '[' << (peer->requires()->getOperationCaller(*it)->ready() ? "R]" : "!]"); 02015 sresult << nl; 02016 } else { 02017 sresult <<coloron<< " (none)" <<coloroff <<nl; 02018 } 02019 objlist = peer->requires()->getRequesterNames(); 02020 sresult << " Requests Services :"; 02021 if ( !objlist.empty() ) { 02022 for(vector<string>::iterator it = objlist.begin(); it != objlist.end(); ++it) 02023 sresult <<coloron<< " " << *it <<coloroff << '[' << (peer->requires(*it)->ready() ? "R]" : "!]"); 02024 sresult << nl; 02025 } else { 02026 sresult <<coloron<< " (none)" <<coloroff <<nl; 02027 } 02028 02029 if (peer->provides()->hasService("scripting")) { 02030 objlist = peer->getProvider<Scripting>("scripting")->getProgramList(); 02031 if ( !objlist.empty() ) { 02032 sresult << " Programs : "<<coloron; 02033 for(vector<string>::iterator it = objlist.begin(); it != objlist.end(); ++it) 02034 sresult << *it << "["<<getProgramStatusChar(peer,*it)<<"] "; 02035 sresult << coloroff << nl; 02036 } 02037 02038 objlist = peer->getProvider<Scripting>("scripting")->getStateMachineList(); 02039 if ( !objlist.empty() ) { 02040 sresult << " StateMachines: "<<coloron; 02041 for(vector<string>::iterator it = objlist.begin(); it != objlist.end(); ++it) 02042 sresult << *it << "["<<getStateMachineStatusChar(peer,*it)<<"] "; 02043 sresult << coloroff << nl; 02044 } 02045 } 02046 02047 // if we are in the TB, display the peers of our connected task: 02048 if ( context == tb ) 02049 sresult <<nl<< " "<<peer->getName()<<" Peers : "<<coloron; 02050 else 02051 sresult << nl <<" Peers : "<<coloron; 02052 02053 objlist = peer->getPeerList(); 02054 if ( !objlist.empty() ) 02055 for(vector<string>::iterator it = objlist.begin(); it != objlist.end(); ++it) { 02056 if( peer->getPeer(*it) ) 02057 sresult << *it << "["<<getTaskStatusChar(peer->getPeer(*it))<<"] "; 02058 else 02059 sresult << *it << "[X] "; 02060 } 02061 else 02062 sresult << "(none)"; 02063 } 02064 sresult <<coloroff<<nl; 02065 cout << sresult.str(); 02066 sresult.str(""); 02067 } 02068 02069 void TaskBrowser::printOperation( const std::string m, Service::shared_ptr the_ops ) 02070 { 02071 std::vector<ArgumentDescription> args; 02072 Service::shared_ptr ops; 02073 try { 02074 args = the_ops->getArgumentList( m ); // may throw ! 02075 ops = the_ops; 02076 } catch(...) { 02077 args = GlobalService::Instance()->getArgumentList( m ); // may throw ! 02078 ops = GlobalService::Instance(); 02079 } 02080 sresult <<" " << coloron << m << coloroff<< "( "; 02081 for (std::vector<ArgumentDescription>::iterator it = args.begin(); it != args.end(); ++it) { 02082 sresult << Types()->toDot( it->type ) <<" "; 02083 sresult << coloron << it->name << coloroff; 02084 if ( it+1 != args.end() ) 02085 sresult << ", "; 02086 else 02087 sresult << " "; 02088 } 02089 sresult << ") : "<< Types()->toDot( ops->getResultType(m) )<<nl; 02090 sresult << " " << ops->getDescription( m )<<nl; 02091 for (std::vector<ArgumentDescription>::iterator it = args.begin(); it != args.end(); ++it) 02092 sresult <<" "<< it->name <<" : " << it->description << nl; 02093 } 02094 02095 }