TaskBrowser.cpp
Go to the documentation of this file.
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 }


ocl
Author(s): OCL Development Team
autogenerated on Thu Jan 2 2014 11:38:08