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


ocl
Author(s): OCL Development Team
autogenerated on Mon Sep 14 2015 14:21:47