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


ocl
Author(s): OCL Development Team
autogenerated on Sat Jun 8 2019 18:48:55