TaskBrowser.cpp
Go to the documentation of this file.
1 #ifndef NO_GPL
2 /***************************************************************************
3  tag: Peter Soetens Thu Jul 3 15:31:34 CEST 2008 TaskBrowser.cpp
4 
5  TaskBrowser.cpp - description
6  -------------------
7  begin : Thu July 03 2008
8  copyright : (C) 2008 Peter Soetens
9  email : peter.soetens@fmtc.be
10 
11  ***************************************************************************
12  * *
13  * This program is free software; you can redistribute it and/or modify *
14  * it under the terms of the GNU General Public License as published by *
15  * the Free Software Foundation; either version 2 of the License, or *
16  * (at your option) any later version. *
17  * *
18  * This program is distributed in the hope that it will be useful, *
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
21  * General Public License for more details. *
22  * *
23  * You should have received a copy of the GNU General Public *
24  * License along with this program; if not, write to the Free Software *
25  * Foundation, Inc., 59 Temple Place, *
26  * Suite 330, Boston, MA 02111-1307 USA *
27  ***************************************************************************/
28 #else
29 /***************************************************************************
30  tag: Peter Soetens Tue Dec 21 22:43:07 CET 2004 TaskBrowser.cxx
31 
32  TaskBrowser.cxx - description
33  -------------------
34  begin : Tue December 21 2004
35  copyright : (C) 2004 Peter Soetens
36  email : peter.soetens@mech.kuleuven.ac.be
37 
38  ***************************************************************************
39  * This library is free software; you can redistribute it and/or *
40  * modify it under the terms of the GNU Lesser General Public *
41  * License as published by the Free Software Foundation; either *
42  * version 2.1 of the License, or (at your option) any later version. *
43  * *
44  * This library is distributed in the hope that it will be useful, *
45  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
46  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
47  * Lesser General Public License for more details. *
48  * *
49  * You should have received a copy of the GNU Lesser General Public *
50  * License along with this library; if not, write to the Free Software *
51  * Foundation, Inc., 59 Temple Place, *
52  * Suite 330, Boston, MA 02111-1307 USA *
53  * *
54  ***************************************************************************/
55 #endif
56 
57 
58 #include <rtt/Logger.hpp>
60 #include <rtt/types/TypeStream.hpp>
61 #include <rtt/types/Types.hpp>
62 #include "TaskBrowser.hpp"
63 
65 #include <rtt/TaskContext.hpp>
68 #include <rtt/scripting/Parser.hpp>
76 #include <boost/algorithm/string.hpp>
77 
78 #include <iostream>
79 #include <fstream>
80 #include <sstream>
81 #include <iomanip>
82 #include <deque>
83 #include <stdio.h>
84 #include <algorithm>
85 
86 #if defined(HAS_READLINE) && !defined(NO_GPL)
87 # define USE_READLINE
88 #endif
89 #if defined(HAS_EDITLINE)
90 // we use the readline bc wrapper:
91 # define USE_READLINE
92 # define USE_EDITLINE
93 #endif
94 // only use signals if posix, and pure readline
95 # if defined(_POSIX_VERSION) && defined(HAS_READLINE) && !defined(HAS_EDITLINE)
96 # define USE_SIGNALS 1
97 # endif
98 
99 
100 #ifdef USE_READLINE
101 # ifdef USE_EDITLINE
102 # include <editline/readline.h>
103 # else
104 # include <readline/readline.h>
105 # include <readline/history.h>
106 # endif
107 #endif
108 #include <boost/bind.hpp>
109 #include <boost/lambda/lambda.hpp>
110 
111 #ifdef USE_SIGNALS
112 #include <signal.h>
113 #endif
114 
115 // we need to declare it since Xenomai does not declare it in any header
116 #if defined(USE_SIGNALS) && defined(OROCOS_TARGET_XENOMAI) && CONFIG_XENO_VERSION_MAJOR == 2 && CONFIG_XENO_VERSION_MINOR >= 5
117 extern "C"
118 int xeno_sigwinch_handler(int sig, siginfo_t *si, void *ctxt);
119 #endif
120 
121 #if defined(USE_SIGNALS) && defined(OROCOS_TARGET_XENOMAI) && CONFIG_XENO_VERSION_MAJOR == 3
122 extern "C"
123 int cobalt_sigshadow_handler(int sig, siginfo_t *si, void *ctxt);
124 #endif
125 
126 namespace OCL
127 {
128  using namespace boost;
129  using namespace std;
130  using namespace RTT;
131  using namespace RTT::detail;
132 #ifdef USE_READLINE
133  std::vector<std::string> TaskBrowser::candidates;
134  std::vector<std::string> TaskBrowser::completes;
135  std::vector<std::string>::iterator TaskBrowser::complete_iter;
136  std::string TaskBrowser::component;
137  std::string TaskBrowser::component_found;
138  std::string TaskBrowser::peerpath;
139  std::string TaskBrowser::text;
140 #endif
146 
147  using boost::bind;
148  using namespace RTT;
149  using namespace std;
150 
151  string TaskBrowser::red;
152  string TaskBrowser::green;
153  string TaskBrowser::blue;
154  std::deque<TaskContext*> taskHistory;
155  std::string TaskBrowser::prompt("> ");
156  std::string TaskBrowser::coloron;
157  std::string TaskBrowser::underline;
158  std::string TaskBrowser::coloroff;
159 
160 
164  static std::ostream&
165  nl(std::ostream& __os)
166  { return __os.put(__os.widen('\n')); }
167 
168  // All readline specific functions
169 #if defined(USE_READLINE)
170 
171 #if defined(USE_SIGNALS)
172  // Signal code only on Posix:
173  int TaskBrowser::rl_received_signal;
174  void TaskBrowser::rl_sigwinch_handler(int sig, siginfo_t *si, void *ctxt) {
175  rl_received_signal = sig;
176 #if defined(OROCOS_TARGET_XENOMAI) && CONFIG_XENO_VERSION_MAJOR == 2 && CONFIG_XENO_VERSION_MINOR >= 5
177  if (xeno_sigwinch_handler(sig, si, ctxt) == 0)
178 #endif
179 #if defined(OROCOS_TARGET_XENOMAI) && CONFIG_XENO_VERSION_MAJOR == 3
180  if (cobalt_sigshadow_handler(sig, si, ctxt) == 0)
181 #endif
182  rl_resize_terminal();
183  }
184 
185  void TaskBrowser::rl_signal_handler(int sig, siginfo_t *si, void *ctxt) {
186  rl_received_signal = sig;
187  switch(sig) {
188  case SIGINT:
189  if (rl_end > 0) {
190  rl_free_line_state();
191  rl_echo_signal_char(sig);
192  rl_received_signal = 0;
193  }
194  }
195  }
196 
197  int TaskBrowser::rl_getc(FILE *stream)
198  {
199  int result;
200  unsigned char c;
201 
202  while (1)
203  {
204  rl_received_signal = 0;
205  result = ::read(fileno(stream), &c, sizeof(unsigned char));
206 
207  if (result == sizeof(unsigned char))
208  return (c);
209 
210  /* If zero characters are returned, then the file that we are
211  reading from is empty! Return EOF in that case. */
212  if (result == 0)
213  return (EOF);
214 
215  /* Return an error if SIGINT has been received */
216  if (errno == EINTR && (rl_received_signal == SIGINT || rl_received_signal == SIGTERM))
217  return (RL_ISSTATE (RL_STATE_READCMD) ? READERR : EOF);
218 
219  /* If the error that we received was EINTR, then try again,
220  this is simply an interrupted system call to read ().
221  Otherwise, some error ocurred, also signifying EOF. */
222  if (errno != EINTR)
223  return (RL_ISSTATE (RL_STATE_READCMD) ? READERR : EOF);
224  }
225  }
226 #endif // USE_SIGNALS
227 
228  char *TaskBrowser::rl_gets ()
229  {
230  /* If the buffer has already been allocated,
231  return the memory to the free pool. */
232  if (line_read)
233  {
234 #ifdef _WIN32
235 
246  free(line_read);
247 #else
248  free (line_read);
249 #endif
250  line_read = 0;
251  }
252 
253  /* Get a line from the user. */
254  std::string p;
255  if ( !macrorecording ) {
256  p = prompt;
257  } else {
258  p = "> ";
259  }
260 
261 #ifdef USE_SIGNALS
262  if (rl_set_signals() != 0)
263  cerr << "Error setting signals !" <<endl;
264 #endif
265 
266  line_read = readline ( p.c_str() );
267 
268 #ifdef USE_SIGNALS
269  if (rl_clear_signals() != 0)
270  cerr << "Error clearing signals !" <<endl;
271 #endif
272 
273  /* If the line has any text in it,
274  save it on the history. */
275  if (line_read && *line_read) {
276  // do not store "quit"
277  string s = line_read;
278  if (s != "quit" && ! ( history_get( where_history() ) && s == string(history_get( where_history() )->line) ) ) {
279 // cout << "Where: " << where_history() << " history_get: " << ( history_get( where_history() ) ? history_get( where_history() )->line : "(null)") << endl;
280 // cout << "History: " << (current_history() ? (const char*) current_history()->line : "(null)") << endl;
281  add_history (line_read);
282  }
283  }
284  return (line_read);
285  }
286 
287  char* TaskBrowser::dupstr( const char *s )
288  {
289  char * rv;
290  // must be C-style :
291  rv = (char*) malloc( strlen( s ) + 1 );
292  strncpy( rv, s, strlen(s) + 1 );
293  return rv;
294  }
295 
296  char *TaskBrowser::command_generator( const char *_text, int state )
297  {
298  // first time called.
299  if ( !state )
300  {
301  // make a copy :
302  text = _text;
303  // rebuild a completion list
304  completes.clear();
305  find_completes();
306  complete_iter = completes.begin();
307  }
308  else
309  ++complete_iter;
310 
311  // return zero if nothing more is found
312  if ( complete_iter == completes.end() )
313  return 0;
314  // return the next completion option
315  return dupstr( complete_iter->c_str() ); // RL requires malloc !
316  }
317 
322  void TaskBrowser::find_completes() {
323  std::string::size_type pos;
324  std::string::size_type startpos;
325  std::string line( rl_line_buffer, rl_point );
326 
327  // complete on 'cd' or 'ls' :
328  if ( line.find(std::string("cd ")) == 0 || line.find(std::string("ls ")) == 0) {
329  //cerr <<endl<< "switch to :" << text<<endl;
330 // pos = text.rfind(".");
331  pos = line.find(" "); // pos+1 is first peername
332  startpos = line.find_last_of(". "); // find last peer
333  //cerr <<"startpos :"<<startpos<<endl;
334  // start searching from component.
335  peer = taskcontext;
336  if ( pos+1 != line.length() ) // bounds check
337  peer = findPeer( line.substr(pos+1) );
338 
339  if (!peer)
340  return;
341  //std::string peername = text.substring( pos+1, std::string::npos );
342  RTT::TaskContext::PeerList v = peer->getPeerList();
343  for (RTT::TaskContext::PeerList::iterator i = v.begin(); i != v.end(); ++i) {
344  std::string path;
345  if ( !( pos+1 > startpos) )
346  path = line.substr(pos+1, startpos - pos);
347  //cerr << "path :"<<path<<endl;
348  if ( *i == line.substr(startpos+1) )
349  completes.push_back( path + *i + ".");
350  else
351  if ( startpos == std::string::npos || startpos+1 == line.length() || i->find( line.substr(startpos+1)) == 0 )
352  completes.push_back( *i );
353  }
354  // Stop here if 'cd'
355  if (line.find(std::string("cd ")) == 0)
356  return;
357  // Add objects for 'ls'.
358  v = peer->provides()->getProviderNames();
359  for (RTT::TaskContext::PeerList::iterator i = v.begin(); i != v.end(); ++i) {
360  std::string path;
361  if ( !( pos+1 > startpos) )
362  path = line.substr(pos+1, startpos - pos);
363  //cerr << "provider:"<< *i << ", path :"<<path<<endl;
364  if ( *i == line.substr(startpos+1) )
365  completes.push_back( path + *i + ".");
366  else
367  if ( startpos == std::string::npos || startpos+1 == line.length() || i->find( line.substr(startpos+1)) == 0 )
368  completes.push_back( *i );
369  }
370  return; // do not add component names.
371  }
372 
373  // TaskBrowser commands :
374  if ( line.find(std::string(".")) == 0 ) {
375  // first make a list of all sensible completions.
376  std::vector<std::string> tbcoms;
377  tbcoms.push_back(".loadProgram ");
378  tbcoms.push_back(".unloadProgram ");
379  tbcoms.push_back(".loadStateMachine ");
380  tbcoms.push_back(".unloadStateMachine ");
381  tbcoms.push_back(".light");
382  tbcoms.push_back(".dark");
383  tbcoms.push_back(".hex");
384  tbcoms.push_back(".nohex");
385  tbcoms.push_back(".nocolors");
386  tbcoms.push_back(".connect");
387  tbcoms.push_back(".record");
388  tbcoms.push_back(".end");
389  tbcoms.push_back(".cancel");
390  tbcoms.push_back(".provide");
391  tbcoms.push_back(".services");
392  tbcoms.push_back(".typekits");
393  tbcoms.push_back(".types");
394 
395  // then see which one matches the already typed line :
396  for( std::vector<std::string>::iterator it = tbcoms.begin();
397  it != tbcoms.end();
398  ++it)
399  if ( it->find(line) == 0 )
400  completes.push_back( *it ); // if partial match, add.
401  return;
402  }
403 
404  if ( line.find(std::string("list ")) == 0
405  || line.find(std::string("trace ")) == 0
406  || line.find(std::string("untrace ")) == 0) {
407  stringstream ss( line.c_str() ); // copy line into ss.
408  string lcommand;
409  ss >> lcommand;
410  lcommand += ' ';
411  std::vector<std::string> progs;
412 
413  if ( context->provides()->hasService("scripting") ) {
414  // THIS:
415  progs = context->getProvider<Scripting>("scripting")->getProgramList();
416  // then see which one matches the already typed line :
417  for( std::vector<std::string>::iterator it = progs.begin();
418  it != progs.end();
419  ++it) {
420  string res = lcommand + *it;
421  if ( res.find(line) == 0 )
422  completes.push_back( *it ); // if partial match, add.
423  }
424  progs = context->getProvider<Scripting>("scripting")->getStateMachineList();
425  for( std::vector<std::string>::iterator it = progs.begin();
426  it != progs.end();
427  ++it) {
428  string res = lcommand + *it;
429  if ( res.find(line) == 0 )
430  completes.push_back( *it ); // if partial match, add.
431  }
432  }
433  return;
434  }
435 
436  startpos = text.find_last_of(",( ");
437  if ( startpos == std::string::npos )
438  startpos = 0; // if none is found, start at beginning
439 
440  // complete on peers and objects, and find the peer the user wants completion for
441  find_peers(startpos);
442  // now proceed with 'this->peer' as TC,
443  // this->taskobject as TO and
444  // this->component as object and
445  // this->peerpath as the text leading up to 'this->component'.
446 
447  // store the partial compname or peername
448  std::string comp = component;
449 
450 
451  // NEXT: use taskobject to complete commands, events, methods, attrs
452  // based on 'component' (find trick).
453  // if taskobject == peer, also complete properties
454  find_ops();
455 
456  // TODO: concat two cases below as text.find("cd")...
457  // check if the user is tabbing on an empty command, then add the console commands :
458  if ( line.empty() ) {
459  completes.push_back("cd ");
460  completes.push_back("cd ..");
461  completes.push_back("ls");
462  completes.push_back("help");
463  completes.push_back("quit");
464  completes.push_back("list");
465  completes.push_back("trace");
466  completes.push_back("untrace");
467  if (taskcontext == context)
468  completes.push_back("leave");
469  else
470  completes.push_back("enter");
471  // go on below to add components and tasks as well.
472  }
473 
474  // only try this if text is not empty.
475  if ( !text.empty() ) {
476  if ( std::string( "cd " ).find(text) == 0 )
477  completes.push_back("cd ");
478  if ( std::string( "ls" ).find(text) == 0 )
479  completes.push_back("ls");
480  if ( std::string( "cd .." ).find(text) == 0 )
481  completes.push_back("cd ..");
482  if ( std::string( "help" ).find(text) == 0 )
483  completes.push_back("help");
484  if ( std::string( "quit" ).find(text) == 0 )
485  completes.push_back("quit");
486  if ( std::string( "list " ).find(text) == 0 )
487  completes.push_back("list ");
488  if ( std::string( "trace " ).find(text) == 0 )
489  completes.push_back("trace ");
490  if ( std::string( "untrace " ).find(text) == 0 )
491  completes.push_back("untrace ");
492  if ( std::string( "GlobalService" ).find(text) == 0 )
493  completes.push_back("GlobalService");
494  if ( std::string( "GlobalsRepository" ).find(text) == 0 )
495  completes.push_back("GlobalsRepository");
496 
497  if (taskcontext == context && string("leave").find(text) == 0)
498  completes.push_back("leave");
499 
500  if (context == tb && string("enter").find(text) == 0)
501  completes.push_back("enter");
502  }
503  }
504 
505  void TaskBrowser::find_ops()
506  {
507  // the last (incomplete) text is stored in 'component'.
508  // all attributes :
509  std::vector<std::string> attrs;
510  attrs = taskobject->getAttributeNames();
511  for (std::vector<std::string>::iterator i = attrs.begin(); i!= attrs.end(); ++i ) {
512  if ( i->find( component ) == 0 )
513  completes.push_back( peerpath + *i );
514  }
515  // all properties if RTT::TaskContext/Service:
516  std::vector<std::string> props;
517  taskobject->properties()->list(props);
518  for (std::vector<std::string>::iterator i = props.begin(); i!= props.end(); ++i ) {
519  if ( i->find( component ) == 0 ) {
520  completes.push_back( peerpath + *i );
521  }
522  }
523 
524  // methods:
525  vector<string> comps = taskobject->getNames();
526  for (std::vector<std::string>::iterator i = comps.begin(); i!= comps.end(); ++i ) {
527  if ( i->find( component ) == 0 )
528  completes.push_back( peerpath + *i );
529  }
530 
531  // types:
532  comps = Types()->getDottedTypes();
533  for (std::vector<std::string>::iterator i = comps.begin(); i!= comps.end(); ++i ) {
534  if ( peerpath.empty() && i->find( component ) == 0 )
535  completes.push_back( *i );
536  }
537 
538  // Global Attributes:
539  comps = GlobalsRepository::Instance()->getAttributeNames();
540  for (std::vector<std::string>::iterator i = comps.begin(); i!= comps.end(); ++i ) {
541  if ( peerpath.empty() && i->find( component ) == 0 )
542  completes.push_back( *i );
543  }
544 
545  // Global Properties:
546  comps = GlobalsRepository::Instance()->properties()->list();
547  for (std::vector<std::string>::iterator i = comps.begin(); i!= comps.end(); ++i ) {
548  if ( peerpath.empty() && i->find( component ) == 0 )
549  completes.push_back( *i );
550  }
551 
552  if (component.find("GlobalsRepository") == 0) {
553 
554  // Global Attributes:
555  comps = GlobalsRepository::Instance()->getAttributeNames();
556  for (std::vector<std::string>::iterator i = comps.begin(); i!= comps.end(); ++i ) {
557  completes.push_back( "GlobalsRepository." + *i );
558  }
559 
560  // Global Properties:
561  comps = GlobalsRepository::Instance()->properties()->list();
562  for (std::vector<std::string>::iterator i = comps.begin(); i!= comps.end(); ++i ) {
563  completes.push_back( "GlobalsRepository." + *i );
564  }
565  } else if ( taskobject == peer->provides() && peer == context ) {
566  // Global methods:
567  comps = GlobalService::Instance()->getNames();
568  for (std::vector<std::string>::iterator i = comps.begin(); i!= comps.end(); ++i ) {
569  if ( i->find( component ) == 0 )
570  completes.push_back( peerpath + *i );
571  }
572  }
573 
574  // Global methods:
575  if ( taskobject == peer->provides() && peer == context) {
576  comps = GlobalService::Instance()->getNames();
577  for (std::vector<std::string>::iterator i = comps.begin(); i!= comps.end(); ++i ) {
578  if ( i->find( component ) == 0 )
579  completes.push_back( peerpath + *i );
580  }
581  }
582 
583  // complete on types:
584  bool try_deeper = false;
585  try {
586  Parser parser(GlobalEngine::Instance());
587  DataSourceBase::shared_ptr result = parser.parseExpression( peerpath + component_found, context );
588  if (result && !component.empty() ) {
589  DataSource<PropertyBag>::shared_ptr bag = DataSource<PropertyBag>::narrow(result.get());
590  vector<string> members;
591  if(bag){
592  members = bag->rvalue().getPropertyNames();
593  }
594  else{
595  members = result->getMemberNames();
596  }
597  for (std::vector<std::string>::iterator i = members.begin(); i!= members.end(); ++i ) {
598  if ( string( component_found + "." + *i ).find( component ) == 0 )
599  completes.push_back( peerpath + component_found + "." + *i );
600  if ( component_found + "." + *i == component )
601  try_deeper = true;
602  }
603  }
604  } catch(...) {}
605  // this is a hack to initiate a complete on a valid expression that might have members.
606  // the completer above would only return the expression itself, while this one tries to
607  // go a level deeper again.
608  if (try_deeper) {
609  try {
610  Parser parser(GlobalEngine::Instance());
611  DataSourceBase::shared_ptr result = parser.parseExpression( peerpath + component, context );
612  if (result && !component.empty() ) {
613  DataSource<PropertyBag>::shared_ptr bag = DataSource<PropertyBag>::narrow(result.get());
614  vector<string> members;
615  if(bag){
616  members = bag->rvalue().getPropertyNames();
617  }
618  else{
619  members = result->getMemberNames();
620  }
621  for (std::vector<std::string>::iterator i = members.begin(); i!= members.end(); ++i ) {
622  if (component_found + "." != component ) // catch corner case.
623  completes.push_back( peerpath + component + "." + *i );
624  }
625  }
626  } catch(...) {}
627  }
628  }
629 
630  void TaskBrowser::find_peers( std::string::size_type startpos )
631  {
632  peerpath.clear();
633  peer = context;
634  taskobject = context->provides();
635 
636  std::string to_parse = text.substr(startpos);
637  startpos = 0;
638  std::string::size_type endpos = 0;
639  // Traverse the entered peer-list
640  component.clear();
641  peerpath.clear();
642  // This loop separates the peer/service from the member/method
643  while (endpos != std::string::npos )
644  {
645  bool itemfound = false;
646  endpos = to_parse.find(".");
647  if ( endpos == startpos ) {
648  component.clear();
649  break;
650  }
651  std::string item = to_parse.substr(startpos, endpos);
652 
653  if ( taskobject->hasService( item ) ) {
654  taskobject = taskobject->provides(item);
655  itemfound = true;
656  } else
657  if ( peer->hasPeer( item ) ) {
658  peer = peer->getPeer( item );
659  taskobject = peer->provides();
660  itemfound = true;
661  } else if ( GlobalService::Instance()->hasService(item) ) {
662  taskobject = GlobalService::Instance()->provides(item);
663  itemfound = true;
664  }
665  if ( itemfound ) { // if "." found and correct path
666  peerpath += to_parse.substr(startpos, endpos) + ".";
667  if ( endpos != std::string::npos )
668  to_parse = to_parse.substr(endpos + 1);
669  else
670  to_parse.clear();
671  startpos = 0;
672  }
673  else {
674  // no match: typo or member name
675  // store the text until the last dot:
676  component_found = to_parse.substr(startpos, to_parse.rfind("."));
677  // store the complete text
678  component = to_parse.substr(startpos, std::string::npos);
679  break;
680  }
681  }
682 
683  // now we got the peer and taskobject pointers,
684  // the completed path in peerpath
685  // the last partial path in component
686 // cout << "text: '" << text <<"'"<<endl;
687 // cout << "to_parse: '" << text <<"'"<<endl;
688 // cout << "Peerpath: '" << peerpath <<"'"<<endl;
689  // cout <<endl<< "Component: '" << component <<"'"<<endl;
690  // cout << "Component_found: '" << component_found <<"'"<<endl;
691 
693  if ( taskobject == peer->provides() ) {
694  // add peer's completes:
695  v = peer->getPeerList();
696  for (RTT::TaskContext::PeerList::iterator i = v.begin(); i != v.end(); ++i) {
697  if ( i->find( component ) == 0 ) { // only add if match
698  completes.push_back( peerpath + *i );
699  completes.push_back( peerpath + *i + "." );
700  //cerr << "added " << peerpath+*i+"."<<endl;
701  }
702  }
703  }
704  // add taskobject's completes:
705  v = taskobject->getProviderNames();
706  for (RTT::TaskContext::PeerList::iterator i = v.begin(); i != v.end(); ++i) {
707  if ( i->find( component ) == 0 ) { // only add if match
708  completes.push_back( peerpath + *i );
709  if ( *i != "this" ) // "this." confuses our parsing lateron
710  completes.push_back( peerpath + *i + "." );
711  //cerr << "added " << peerpath+*i+"."<<endl;
712  }
713  }
714  // add global service completes:
715  if ( peer == context && taskobject == peer->provides() ) {
716  v = GlobalService::Instance()->getProviderNames();
717  for (RTT::TaskContext::PeerList::iterator i = v.begin(); i != v.end(); ++i) {
718  if ( i->find( component ) == 0 ) { // only add if match
719  completes.push_back( peerpath + *i );
720  if ( *i != "this" ) // "this." confuses our parsing lateron
721  completes.push_back( peerpath + *i + "." );
722  //cerr << "added " << peerpath+*i+"."<<endl;
723  }
724  }
725  }
726  return;
727  }
728 
729  char ** TaskBrowser::orocos_hmi_completion ( const char *text, int start, int end )
730  {
731  char **matches;
732  matches = ( char ** ) 0;
733 
734  matches = rl_completion_matches ( text, &TaskBrowser::command_generator );
735 
736  return ( matches );
737  }
738 #endif // USE_READLINE
739 
741  : RTT::TaskContext("TaskBrowser"),
742  debug(0),
743  line_read(0),
744  lastc(0), storedname(""), storedline(-1),
745  usehex(false),
746  histfile(0),
747  macrorecording(false)
748  {
749  tb = this;
750  context = tb;
751  this->switchTaskContext(_c);
752 #ifdef USE_READLINE
753  // we always catch sigwinch ourselves, in order to pass it on to Xenomai if necessary.
754 #ifdef USE_SIGNALS
755  rl_catch_sigwinch = 0;
756  rl_catch_signals = 0;
757  rl_getc_function = &TaskBrowser::rl_getc;
758 #endif
759  rl_completion_append_character = '\0'; // avoid adding spaces
760  rl_attempted_completion_function = &TaskBrowser::orocos_hmi_completion;
761 
762  using_history();
763  histfile = getenv("ORO_TB_HISTFILE");
764  if(histfile == 0)
765  histfile = ".tb_history";
766  if ( read_history(histfile) != 0 ) {
767  read_history("~/.tb_history");
768  }
769 #ifdef USE_SIGNALS
770  struct sigaction sa;
771  sa.sa_sigaction = &TaskBrowser::rl_sigwinch_handler;
772  sa.sa_flags = SA_SIGINFO | SA_RESTART;
773  sigemptyset( &sa.sa_mask );
774  sigaction(SIGWINCH, &sa, 0);
775 
776  sa.sa_sigaction = &(TaskBrowser::rl_signal_handler);
777  sa.sa_flags = SA_SIGINFO;
778  sigaction(SIGINT, &sa, 0);
779  sigaction(SIGTERM, &sa, 0);
780 #endif // USE_SIGNALS
781 #endif // USE_READLINE
782 
783  this->setColorTheme( darkbg );
784  this->enterTask();
785  }
786 
788 #ifdef USE_READLINE
789  if (line_read)
790  {
791  free (line_read);
792  }
793  if ( write_history(histfile) != 0 ) {
794  write_history("~/.tb_history");
795  }
796 #endif
797  }
798 
803  {
804  if (t->inFatalError())
805  return 'F';
806  if (t->inRunTimeError())
807  return 'E';
808  if (t->inException())
809  return 'X';
810  if (t->isRunning() )
811  return 'R'; // Running
812  if (t->isConfigured() )
813  return 'S'; // Stopped
814  return 'U'; // Unconfigured/Preoperational
815  }
816 
818  {
819  string ps = t->getProvider<Scripting>("scripting")->getStateMachineStatusStr(progname);
820  return toupper(ps[0]);
821  }
822 
824  {
825  string ps = t->getProvider<Scripting>("scripting")->getProgramStatusStr(progname);
826  return toupper(ps[0]);
827  }
828 
829  void str_trim(string& str, char to_trim)
830  {
831  string::size_type pos1 = str.find_first_not_of(to_trim);
832  string::size_type pos2 = str.find_last_not_of(to_trim);
833  if (pos1 == string::npos)
834  str.clear(); // nothing else present
835  else
836  str = str.substr(pos1, pos2 - pos1 + 1);
837  }
838 
839 
845  {
846  cout << nl<<
847  coloron <<
848  " This console reader allows you to browse and manipulate TaskContexts."<<nl<<
849  " You can type in an operation, expression, create or change variables."<<nl;
850  cout <<" (type '"<<underline<<"help"<<coloroff<<coloron<<"' for instructions and '"
851  <<underline<<"ls"<<coloroff<<coloron<<"' for context info)"<<nl<<nl;
852 #ifdef USE_READLINE
853  cout << " TAB completion and HISTORY is available ('bash' like)" <<nl<<nl;
854 #else
855  cout << " TAB completion and history is NOT available (LGPL-version)" <<nl<<nl;
856 #endif
857  cout << " Use '"<<underline<<"Ctrl-D"<<coloroff<<coloron<<"' or type '"<<underline<<"quit"<<coloroff<<coloron<<"' to exit this program." <<coloroff<<nl<<nl;
858 
859  while (1) {
860  try {
861  if (!macrorecording) {
862  if ( context == tb )
863  cout << green << " Watching " <<coloroff;
864 
865  char state = getTaskStatusChar(taskcontext);
866 
867  // sets prompt for readline:
868 // prompt = green + taskcontext->getName() + coloroff + "[" + state + "]> ";
869  prompt = taskcontext->getName() + " [" + state + "]> ";
870  // This 'endl' is important because it flushes the whole output to screen of all
871  // processing that previously happened, which was using 'nl'.
872  cout.flush();
873 
874  // print traces.
875  for (PTrace::iterator it = ptraces.begin(); it != ptraces.end(); ++it) {
876  RTT::TaskContext* progpeer = it->first.first;
877  int line = progpeer->getProvider<Scripting>("scripting")->getProgramLine(it->first.second);
878  if ( line != it->second ) {
879  it->second = line;
880  printProgram( it->first.second, -1, progpeer );
881  }
882  }
883 
884  for (PTrace::iterator it = straces.begin(); it != straces.end(); ++it) {
885  RTT::TaskContext* progpeer = it->first.first;
886  int line = progpeer->getProvider<Scripting>("scripting")->getStateMachineLine(it->first.second);
887  if ( line != it->second ) {
888  it->second = line;
889  printProgram( it->first.second, -1, progpeer );
890  }
891  }
892  }
893  // Check port status:
894  checkPorts();
895  std::string command;
896  // When using rxvt on windows, the process will receive signals when the arrow keys are used
897  // during input. We compile with /EHa to catch these signals and don't print anything.
898  try {
899 #ifdef USE_READLINE
900  const char* const commandStr = rl_gets();
901  // quit on EOF (Ctrl-D)
902  command = commandStr ? commandStr : "quit"; // copy over to string
903 #else
904  cout << prompt;
905  getline(cin,command);
906  if (!cin) // Ctrl-D
907  command = "quit";
908 #endif
909  } catch(std::exception& e) {
910  cerr << "The command line reader throwed a std::exception: '"<< e.what()<<"'."<<endl;
911  } catch (...) {
912  cerr << "The command line reader throwed an exception." <<endlog();
913  }
914  str_trim( command, ' ');
915  cout << coloroff;
916  if ( command == "quit" ) {
917  // Intercept no Ctrl-C
918  cout << endl;
919  return;
920  } else if ( command == "help") {
921  printHelp();
922  } else if ( command.find("help ") == 0) {
923  printHelp( command.substr(command.rfind(' ')));
924  } else if ( command == "GlobalService" ) {
925  printService(command);
926  } else if ( command == "GlobalsRepository" ) {
927  printGlobals();
928  } else if ( command == "#debug") {
929  debug = !debug;
930  } else if ( command.find("list ") == 0 || command == "list" ) {
931  browserAction(command);
932  } else if ( command.find("trace ") == 0 || command == "trace" ) {
933  browserAction(command);
934  } else if ( command.find("untrace ") == 0 || command == "untrace" ) {
935  browserAction(command);
936  } else if ( command.find("ls") == 0 ) {
937  std::string::size_type pos = command.find("ls")+2;
938  command = std::string(command, pos, command.length());
939  str_trim( command, ' ');
940  printInfo( command );
941  } else if ( command == "" ) { // nop
942  } else if ( command.find("cd ..") == 0 ) {
943  this->switchBack( );
944  } else if ( command.find("enter") == 0 ) {
945  this->enterTask();
946  } else if ( command.find("leave") == 0 ) {
947  this->leaveTask();
948  } else if ( command.find("cd ") == 0 ) {
949  std::string::size_type pos = command.find("cd")+2;
950  command = std::string(command, pos, command.length());
951  this->switchTaskContext( command );
952  } else if ( command.find(".") == 0 ) {
953  command = std::string(command, 1, command.length());
954  this->browserAction( command );
955  } else if ( macrorecording) {
956  macrotext += command +'\n';
957  } else {
958  try {
959  this->evalCommand( command );
960  } catch(std::exception& e) {
961  cerr << "The command '"<<command<<"' caused a std::exception: '"<< e.what()<<"' and could not be completed."<<endl;
962  } catch(...){
963  cerr << "The command '"<<command<<"' caused an unknown exception and could not be completed."<<endl;
964  }
965  // a command was typed... clear storedline such that a next 'list'
966  // shows the 'IP' again.
967  storedline = -1;
968  }
969  //cout <<endl;
970  } catch(std::exception& e) {
971  cerr << "Warning: The command caused a std::exception: '"<< e.what()<<"' in the TaskBrowser's loop() function."<<endl;
972  } catch(...) {
973  cerr << "Warning: The command caused an exception in the TaskBrowser's loop() function." << endl;
974  }
975  }
976  }
977 
979  {
980  if ( context == taskcontext ) {
981  log(Info) <<"Already in Task "<< taskcontext->getName()<<endlog();
982  return;
983  }
985  log(Info) <<"Entering Task "<< taskcontext->getName()<<endlog();
986  }
987 
989  {
990  if ( context == tb ) {
991  log(Info) <<"Already watching Task "<< taskcontext->getName()<<endlog();
992  return;
993  }
994  context = tb;
995  log(Info) <<"Watching Task "<< taskcontext->getName()<<endlog();
996  }
997 
998  void TaskBrowser::recordMacro(std::string name)
999  {
1000  if (macrorecording) {
1001  log(Error)<< "Macro already active." <<endlog();
1002  return;
1003  }
1004  if (context->provides()->hasService("scripting") == false) {
1005  log(Error)<< "Can not create a macro in a TaskContext without scripting service." <<endlog();
1006  return;
1007  }
1008  if ( name.empty() ) {
1009  cerr << "Please specify a macro name." <<endl;
1010  return;
1011  } else {
1012  cout << "Recording macro "<< name <<endl;
1013  cout << "Use program scripting syntax (do, set,...) !" << endl <<endl;
1014  cout << "export function "<< name<<" {"<<endl;
1015  }
1016  macrorecording = true;
1017  macroname = name;
1018  }
1019 
1021  if (!macrorecording) {
1022  log(Warning)<< "Macro recording was not active." <<endlog();
1023  return;
1024  }
1025  cout << "Canceling macro "<< macroname <<endl;
1026  macrorecording = false;
1027  macrotext.clear();
1028  }
1029 
1031  if (!macrorecording) {
1032  log(Warning)<< "Macro recording was not active." <<endlog();
1033  return;
1034  }
1035  string fname = macroname + ".ops";
1036  macrorecording = false;
1037  cout << "}" <<endl;
1038  cout << "Saving file "<< fname <<endl;
1039  ofstream macrofile( fname.c_str() );
1040  macrofile << "/* TaskBrowser macro '"<<macroname<<"' */" <<endl<<endl;
1041  macrofile << "export function "<<macroname<<" {"<<endl;
1042  macrofile << macrotext.c_str();
1043  macrofile << "}"<<endl;
1044  macrotext.clear();
1045 
1046  cout << "Loading file "<< fname <<endl;
1047  context->getProvider<Scripting>("Scripting")->loadPrograms(fname);
1048  }
1049 
1051  {
1052  if ( taskHistory.size() == 0)
1053  return;
1054 
1055  this->switchTaskContext( taskHistory.front(), false ); // store==false
1056  lastc = 0;
1057  taskHistory.pop_front();
1058  }
1059 
1061  {
1062  // check periodically if the taskcontext did not change its ports.
1063 
1065  ports = this->ports()->getPorts();
1066  for( DataFlowInterface::Ports::iterator i=ports.begin(); i != ports.end(); ++i) {
1067  // If our port is no longer connected, try to reconnect.
1068  base::PortInterface* p = *i;
1070  if ( p->connected() == false || tcp == 0 || tcp->connected() == false) {
1071  this->ports()->removePort( p->getName() );
1072  delete p;
1073  }
1074  }
1075  }
1076 
1078  {
1079  // background color palettes:
1080  const char* dbg = "\033[01;";
1081  const char* wbg = "\033[02;";
1082  // colors in palettes:
1083  const char* r = "31m";
1084  const char* g = "32m";
1085  const char* b = "34m";
1086  const char* con = "31m";
1087  const char* coff = "\33[0m";
1088  const char* und = "\33[4m";
1089 
1090  switch (t)
1091  {
1092  case nocolors:
1093  green.clear();
1094  red.clear();
1095  blue.clear();
1096  coloron.clear();
1097  coloroff.clear();
1098  underline.clear();
1099  return;
1100  break;
1101  case darkbg:
1102  green = dbg;
1103  red = dbg;
1104  blue = dbg;
1105  coloron = dbg;
1106  coloroff = wbg;
1107  break;
1108  case whitebg:
1109  green = wbg;
1110  red = wbg;
1111  blue = wbg;
1112  coloron = wbg;
1113  coloroff = wbg;
1114  break;
1115  }
1116  green += g;
1117  red += r;
1118  blue += b;
1119  coloron += con;
1120  coloroff = coff;
1121  underline = und;
1122  }
1123 
1124  void TaskBrowser::switchTaskContext(std::string& c) {
1125  // if nothing new found, return.
1126  peer = taskcontext;
1127  if ( this->findPeer( c + "." ) == 0 ) {
1128  cerr << "No such peer: "<< c <<nl;
1129  return;
1130  }
1131 
1132  if ( peer == taskcontext ) {
1133  cerr << "Already in "<< c <<nl;
1134  return;
1135  }
1136 
1137  if ( peer == tb ) {
1138  cerr << "Can not switch to TaskBrowser." <<nl;
1139  return;
1140  }
1141 
1142  // findPeer has set 'peer' :
1143  this->switchTaskContext( peer );
1144  }
1145 
1147  // put current on the stack :
1148  if (taskHistory.size() == 20 )
1149  taskHistory.pop_back();
1150  if ( taskcontext && store)
1151  taskHistory.push_front( taskcontext );
1152 
1153  // disconnect from current peers.
1154  this->disconnect();
1155 
1156  // cleanup port left-overs.
1157  DataFlowInterface::Ports tports = this->ports()->getPorts();
1158  for( DataFlowInterface::Ports::iterator i=tports.begin(); i != tports.end(); ++i) {
1159  this->ports()->removePort( (*i)->getName() );
1160  delete *i;
1161  }
1162 
1163  // now switch to new one :
1164  if ( context == taskcontext )
1165  context = tc;
1166  taskcontext = tc; // peer is the new taskcontext.
1167  lastc = 0;
1168 
1169  // connect peer.
1170  this->addPeer( taskcontext );
1171 
1172  // map data ports.
1173  // create 'anti-ports' to allow port-level interaction with the peer.
1174  tports = taskcontext->ports()->getPorts();
1175  if ( !tports.empty() )
1176  cout <<nl << "TaskBrowser connects to all data ports of "<<taskcontext->getName()<<endl;
1177  for( DataFlowInterface::Ports::iterator i=tports.begin(); i != tports.end(); ++i) {
1178  if (this->ports()->getPort( (*i)->getName() ) == 0 )
1179  this->ports()->addPort( *(*i)->antiClone() );
1180  }
1182 
1183 
1184 
1185  cerr << " Switched to : " << taskcontext->getName() <<endl;
1186 
1187  }
1188 
1190  // returns the one but last peer, which is the one we want.
1191  std::string s( c );
1192 
1193  our_pos_iter_t parsebegin( s.begin(), s.end(), "teststring" );
1194  our_pos_iter_t parseend;
1195 
1196  CommonParser cp;
1197  scripting::PeerParser pp( peer, cp, true );
1198  bool skipref = true;
1199  try {
1200  parse( parsebegin, parseend, pp.parser(), SKIP_PARSER );
1201  }
1202  catch( ... )
1203  {
1204  log(Debug) <<"No such peer : "<< c <<endlog();
1205  return 0;
1206  }
1207  taskobject = pp.taskObject();
1208  peer = pp.peer();
1209  return pp.peer();
1210  }
1211 
1212  void TaskBrowser::browserAction(std::string& act)
1213  {
1214  std::stringstream ss(act);
1215  std::string instr;
1216  ss >> instr;
1217 
1218  if ( instr == "list" ) {
1219  if (context->provides()->hasService("scripting") == false) {
1220  log(Error)<< "Can not list a program in a TaskContext without scripting service." <<endlog();
1221  return;
1222  }
1223  int line;
1224  ss >> line;
1225  if (ss) {
1226  this->printProgram(line);
1227  return;
1228  }
1229  ss.clear();
1230  string arg;
1231  ss >> arg;
1232  if (ss) {
1233  ss.clear();
1234  ss >> line;
1235  if (ss) {
1236  // progname and line given
1237  this->printProgram(arg, line);
1238  return;
1239  }
1240  // only progname given.
1241  this->printProgram( arg );
1242  return;
1243  }
1244  // just 'list' :
1245  this->printProgram();
1246  return;
1247  }
1248 
1249  //
1250  // TRACING
1251  //
1252  if ( instr == "trace") {
1253  if (context->provides()->hasService("scripting") == false) {
1254  log(Error)<< "Can not trace a program in a TaskContext without scripting service." <<endlog();
1255  return;
1256  }
1257 
1258  string arg;
1259  ss >> arg;
1260  if (ss) {
1261  bool pi = context->getProvider<Scripting>("scripting")->hasProgram(arg);
1262  if (pi) {
1263  ptraces[make_pair(context, arg)] = context->getProvider<Scripting>("scripting")->getProgramLine(arg); // store current line number.
1264  this->printProgram( arg );
1265  return;
1266  }
1267  pi = context->getProvider<Scripting>("scripting")->hasStateMachine(arg);
1268  if (pi) {
1269  straces[make_pair(context, arg)] = context->getProvider<Scripting>("scripting")->getStateMachineLine(arg); // store current line number.
1270  this->printProgram( arg );
1271  return;
1272  }
1273  cerr <<"No such program or state machine: "<< arg <<endl;
1274  return;
1275  }
1276 
1277  // just 'trace' :
1278  std::vector<std::string> names;
1279  names = context->getProvider<Scripting>("scripting")->getProgramList();
1280  for (std::vector<std::string>::iterator it = names.begin(); it != names.end(); ++it) {
1281  bool pi = context->getProvider<Scripting>("scripting")->hasProgram(arg);
1282  if (pi)
1283  ptraces[make_pair(context, arg)] = context->getProvider<Scripting>("scripting")->getProgramLine(arg); // store current line number.
1284  }
1285 
1286  names = context->getProvider<Scripting>("scripting")->getStateMachineList();
1287  for (std::vector<std::string>::iterator it = names.begin(); it != names.end(); ++it) {
1288  bool pi = context->getProvider<Scripting>("scripting")->hasStateMachine(arg);
1289  if (pi)
1290  straces[make_pair(context, arg)] = context->getProvider<Scripting>("scripting")->getStateMachineLine(arg); // store current line number.
1291  }
1292 
1293  cerr << "Tracing all programs and state machines in "<< context->getName() << endl;
1294  return;
1295  }
1296 
1297  if ( instr == "untrace") {
1298  if (context->provides()->hasService("scripting") == false) {
1299  log(Error)<< "Can not untrace a program in a TaskContext without scripting service." <<endlog();
1300  return;
1301  }
1302  string arg;
1303  ss >> arg;
1304  if (ss) {
1305  ptraces.erase( make_pair(context, arg) );
1306  straces.erase( make_pair(context, arg) );
1307  cerr <<"Untracing "<< arg <<" of "<< context->getName()<<endl;
1308  return;
1309  }
1310  // just 'untrace' :
1311  std::vector<std::string> names;
1312  names = context->getProvider<Scripting>("scripting")->getProgramList();
1313  for (std::vector<std::string>::iterator it = names.begin(); it != names.end(); ++it) {
1314  bool pi = context->getProvider<Scripting>("scripting")->hasProgram(arg);
1315  if (pi)
1316  ptraces.erase(make_pair(context, arg));
1317  }
1318 
1319  names = context->getProvider<Scripting>("scripting")->getStateMachineList();
1320  for (std::vector<std::string>::iterator it = names.begin(); it != names.end(); ++it) {
1321  bool pi = context->getProvider<Scripting>("scripting")->hasStateMachine(arg);
1322  if (pi)
1323  straces.erase(make_pair(context, arg));
1324  }
1325 
1326  cerr << "Untracing all programs and state machines of "<< context->getName() << endl;
1327  return;
1328  }
1329 
1330  std::string arg;
1331  ss >> arg;
1332  if ( instr == "dark") {
1333  this->setColorTheme(darkbg);
1334  cout << nl << "Setting Color Theme for "+green+"dark"+coloroff+" backgrounds."<<endl;
1335  return;
1336  }
1337  if ( instr == "light") {
1338  this->setColorTheme(whitebg);
1339  cout << nl << "Setting Color Theme for "+green+"light"+coloroff+" backgrounds."<<endl;
1340  return;
1341  }
1342  if ( instr == "nocolors") {
1343  this->setColorTheme(nocolors);
1344  cout <<nl << "Disabling all colors"<<endl;
1345  return;
1346  }
1347  if ( instr == "record") {
1348  recordMacro( arg );
1349  return;
1350  }
1351  if ( instr == "cancel") {
1352  cancelMacro();
1353  return;
1354  }
1355  if ( instr == "end") {
1356  endMacro();
1357  return;
1358  }
1359  if ( instr == "hex") {
1360  usehex = true;
1361  cout << "Switching to hex notation for output (use .nohex to revert)." <<endl;
1362  return;
1363  }
1364  if ( instr == "nohex") {
1365  usehex = false;
1366  cout << "Turning off hex notation for output." <<endl;
1367  return;
1368  }
1369  if ( instr == "provide") {
1370  while ( ss ) {
1371  cout << "Trying to locate service '" << arg << "'..."<<endl;
1372  if ( PluginLoader::Instance()->loadService(arg, context) )
1373  cout << "Service '"<< arg << "' loaded in " << context->getName() << endl;
1374  else
1375  cout << "Service not found." <<endl;
1376  ss >> arg;
1377  }
1378  return;
1379  }
1380  if (instr == "services") {
1381  vector<string> names = PluginLoader::Instance()->listServices();
1382  cout << "Available Services: ";
1383  for (std::vector<std::string>::iterator it = names.begin(); it != names.end(); ++it) {
1384  cout << " " << *it;
1385  }
1386  cout <<endl;
1387  return;
1388  }
1389  if (instr == "typekits") {
1390  vector<string> names = PluginLoader::Instance()->listTypekits();
1391  cout << "Available Typekits: ";
1392  for (std::vector<std::string>::iterator it = names.begin(); it != names.end(); ++it) {
1393  cout << " " << *it;
1394  }
1395  cout <<endl;
1396  return;
1397  }
1398  if (instr == "types") {
1399  vector<string> names = TypeInfoRepository::Instance()->getDottedTypes();
1400  cout << "Available data types: ";
1401  for (std::vector<std::string>::iterator it = names.begin(); it != names.end(); ++it) {
1402  cout << " " << *it;
1403  }
1404  cout <<endl;
1405  return;
1406  }
1407  cerr << "Unknown Browser Action : "<< act <<endl;
1408  cerr << "See 'help' for valid syntax."<<endl;
1409  }
1410 
1411  void TaskBrowser::evaluate(std::string& comm) {
1412  this->evalCommand(comm);
1413  }
1414 
1416  Service::shared_ptr serv;
1417  std::vector<std::string> strs;
1418  boost::split(strs, names, boost::is_any_of("."));
1419 
1420  // strs could be empty because of a bug in Boost 1.44 (see https://svn.boost.org/trac/boost/ticket/4751)
1421  if (strs.empty()) return serv;
1422 
1423  string component = strs.front();
1424  if (! context->hasPeer(component) && !context->provides()->hasService(component) ) {
1425  return serv;
1426  }
1427  // We only support help for peer or subservice:
1428  if ( context->hasPeer(component) )
1429  serv = context->getPeer(component)->provides();
1430  else if (context->provides()->hasService(component))
1431  serv = context->provides(component);
1432 
1433  // remove component name:
1434  strs.erase( strs.begin() );
1435 
1436  // iterate over remainders:
1437  while ( !strs.empty() && serv) {
1438  serv = serv->getService( strs.front() );
1439  if (serv)
1440  strs.erase( strs.begin() );
1441  }
1442  return serv;
1443  }
1444 
1445 
1446 
1447  bool TaskBrowser::printService( string name ) {
1448  bool result = false;
1451 
1452  if ( ops || GlobalService::Instance()->hasService( name ) || name == "GlobalService" ) // only object name was typed
1453  {
1454  if ( name == "GlobalService" )
1455  ops = GlobalService::Instance();
1456  else if ( !ops )
1457  ops = GlobalService::Instance()->provides(name);
1458  sresult << nl << "Printing Interface of '"<< coloron << ops->getName() <<coloroff <<"' :"<<nl;
1459 
1460  sresult << nl <<" Configuration Properties: ";
1461  RTT::PropertyBag* bag = ops->properties();
1462  if ( bag && bag->size() != 0 ) {
1463  // Print Properties:
1464  for( RTT::PropertyBag::iterator it = bag->begin(); it != bag->end(); ++it) {
1465  base::DataSourceBase::shared_ptr pds = (*it)->getDataSource();
1466  sresult << nl << setw(11)<< right << Types()->toDot( (*it)->getType() )<< " "
1467  << coloron <<setw(14)<<left<< (*it)->getName() << coloroff;
1468  this->printResult( pds.get(), false ); // do not recurse
1469  sresult<<" ("<< (*it)->getDescription() <<')';
1470  }
1471  } else {
1472  sresult << coloron << "(none)";
1473  sresult << coloroff << nl;
1474  }
1475 
1476  sresult << nl << " Attributes : ";
1477  std::vector<std::string> objlist = ops->getAttributeNames();
1478  if ( !objlist.empty() ) {
1479  sresult << nl;
1480  // Print Attributes:
1481  for( std::vector<std::string>::iterator it = objlist.begin(); it != objlist.end(); ++it) {
1482  base::DataSourceBase::shared_ptr pds = ops->getValue(*it)->getDataSource();
1483  sresult << setw(11)<< right << Types()->toDot( pds->getType() )<< " "
1484  << coloron <<setw( 14 )<<left<< *it << coloroff;
1485  this->printResult( pds.get(), false ); // do not recurse
1486  sresult <<nl;
1487  }
1488  } else {
1489  sresult << coloron << "(none)";
1490  sresult << coloroff << nl;
1491  }
1492 
1493  sresult << coloroff << nl << " Operations : " << coloron << nl;
1494  vector<string> methods = ops->getNames();
1495  if ( !methods.empty() ) {
1496  std::for_each( methods.begin(), methods.end(), boost::bind(&TaskBrowser::printOperation, this, _1, ops) );
1497  sresult <<nl;
1498  } else {
1499  sresult << coloron << "(none)";
1500  sresult << coloroff << nl;
1501  }
1502 
1503  sresult << nl << " Data Flow Ports: ";
1504  objlist = ops->getPortNames();
1505  if ( !objlist.empty() ) {
1506  for(vector<string>::iterator it = objlist.begin(); it != objlist.end(); ++it) {
1507  base::PortInterface* port = ops->getPort(*it);
1508  bool writer = dynamic_cast<OutputPortInterface*>(port) ? true : false;
1509  // Port type R/W
1510  sresult << nl << " " << ( !writer ? " In" : "Out");
1511  // Port data type + name
1512  if ( !port->connected() )
1513  sresult << "(U) " << setw(11)<<right<< Types()->toDot( port->getTypeInfo()->getTypeName() );
1514  else
1515  sresult << "(C) " << setw(11)<<right<< Types()->toDot( port->getTypeInfo()->getTypeName() );
1516  sresult << " "
1517  << coloron <<setw( 14 )<<left<< *it << coloroff;
1518 
1519  InputPortInterface* iport = dynamic_cast<InputPortInterface*>(port);
1520  if (iport) {
1521  sresult << " <= ( use '"<< iport->getName() << ".read(sample)' to read a sample from this port)";
1522  }
1523  OutputPortInterface* oport = dynamic_cast<OutputPortInterface*>(port);
1524  if (oport) {
1525  if ( oport->keepsLastWrittenValue()) {
1526  DataSourceBase::shared_ptr dsb = oport->getDataSource();
1527  dsb->evaluate(); // read last written value.
1528  sresult << " => " << dsb;
1529  } else
1530  sresult << " => (keepsLastWrittenValue() == false. Enable it for this port in order to see it in the TaskBrowser.)";
1531  }
1532  }
1533  } else {
1534  sresult << coloron << "(none)";
1535  }
1536  sresult << coloroff << nl;
1537 
1538  objlist = ops->getProviderNames();
1539  sresult <<nl<< " Services: "<<nl;
1540  if ( !objlist.empty() ) {
1541  for(vector<string>::iterator it = objlist.begin(); it != objlist.end(); ++it)
1542  sresult <<coloron<< " " << setw(14) << *it <<coloroff<< " ( "<< ops->provides(*it)->doc() << " ) "<<nl;
1543  } else {
1544  sresult <<coloron<< "(none)";
1545  }
1546  cout << sresult.str() << coloroff << nl;
1547  sresult.str("");
1548  result = true;
1549  }
1550  if ( context->requires()->requiresService( name ) ) // only object name was typed
1551  {
1552  sr = context->requires(name);
1553  sresult << nl << "Requiring '"<< coloron << sr->getRequestName() <<coloroff <<"' with methods: ";
1554  vector<string> methods = sr->getOperationCallerNames();
1555  sresult << coloron;
1556  std::for_each( methods.begin(), methods.end(), sresult << lambda::_1 <<" " );
1557  cout << sresult.str() << coloroff << nl;
1558  sresult.str("");
1559  result = true;
1560  }
1561  return result;
1562  }
1563 
1565  GlobalsRepository::shared_ptr globals = GlobalsRepository::Instance();
1566 
1567  sresult << nl << "Printing Interface of '"<< coloron << "GlobalsRepository" <<coloroff <<"' :"<<nl;
1568  sresult << nl << " Configuration Properties: ";
1569  RTT::PropertyBag* bag = globals->properties();
1570  if ( bag && bag->size() != 0 ) {
1571  // Print Properties:
1572  for( RTT::PropertyBag::iterator it = bag->begin(); it != bag->end(); ++it) {
1573  base::DataSourceBase::shared_ptr pds = (*it)->getDataSource();
1574  sresult << nl << setw(11)<< right << Types()->toDot( (*it)->getType() )<< " "
1575  << coloron <<setw(14)<<left<< (*it)->getName() << coloroff;
1576  this->printResult( pds.get(), false ); // do not recurse
1577  sresult<<" ("<< (*it)->getDescription() <<')';
1578  }
1579  } else {
1580  sresult << coloron << "(none)";
1581  sresult << coloroff << nl;
1582  }
1583 
1584  sresult << nl << " Attributes : ";
1585  std::vector<std::string> objlist = globals->getAttributeNames();
1586  if ( !objlist.empty() ) {
1587  sresult << nl;
1588  // Print Attributes:
1589  for( std::vector<std::string>::iterator it = objlist.begin(); it != objlist.end(); ++it) {
1590  base::DataSourceBase::shared_ptr pds = globals->getValue(*it)->getDataSource();
1591  sresult << setw(11)<< right << Types()->toDot( pds->getType() )<< " "
1592  << coloron <<setw( 14 )<<left<< *it << coloroff;
1593  this->printResult( pds.get(), false ); // do not recurse
1594  sresult <<nl;
1595  }
1596  } else {
1597  sresult << coloron << "(none)";
1598  sresult << coloroff << nl;
1599  }
1600 
1601  cout << sresult.str() << coloroff << nl;
1602  sresult.str("");
1603  return true;
1604  }
1605 
1606  void TaskBrowser::evalCommand(std::string& comm )
1607  {
1608  // deprecated: use 'help servicename'
1609  bool result = printService(comm);
1610 
1611  // Minor hack : also check if it was an attribute of current TC, for example,
1612  // if both the object and attribute with that name exist. the if
1613  // statement after this one would return and not give the expr parser
1614  // time to evaluate 'comm'.
1615  if ( context->provides()->getValue( comm ) ) {
1616  if (debug)
1617  cerr << "Found value..."<<nl;
1618  this->printResult( context->provides()->getValue( comm )->getDataSource().get(), true );
1619  cout << sresult.str()<<nl;
1620  sresult.str("");
1621  return;
1622  }
1623 
1624  if ( result ) {
1625  return;
1626  }
1627 
1628  // Set caller=0 to have correct call/send semantics.
1629  // we're outside the updateHook(). Passing 'this' would
1630  // trigger the EE of the TB, but not our own function.
1631  scripting::Parser _parser( GlobalEngine::Instance() );
1632 
1633  if (debug)
1634  cerr << "Trying ValueStatement..."<<nl;
1635  try {
1636  // Check if it was a method or datasource :
1637  last_expr = _parser.parseValueStatement( comm, context );
1638  // methods and DS'es are processed immediately.
1639  if ( last_expr ) {
1640  // only print if no ';' was given.
1641  assert( comm.size() != 0 );
1642  if ( comm[ comm.size() - 1 ] != ';' ) {
1643  this->printResult( last_expr.get(), true );
1644  cout << sresult.str() << nl <<endl;
1645  sresult.str("");
1646  } else
1647  last_expr->evaluate();
1648  return; // done here
1649  } else if (debug)
1650  cerr << "returned (null) !"<<nl;
1651  //cout << " (ok)" <<nl;
1652  //return; //
1653  } catch ( fatal_semantic_parse_exception& pe ) { // incorr args, ...
1654  // way to fatal, must be reported immediately
1655  if (debug)
1656  cerr << "fatal_semantic_parse_exception: ";
1657  cerr << pe.what() <<nl;
1658  return;
1659  } catch ( syntactic_parse_exception& pe ) { // wrong content after = sign etc..
1660  // syntactic errors must be reported immediately
1661  if (debug)
1662  cerr << "syntactic_parse_exception: ";
1663  cerr << pe.what() <<nl;
1664  return;
1665  } catch ( parse_exception_parser_fail &pe )
1666  {
1667  // ignore, try next parser
1668  if (debug) {
1669  cerr << "Ignoring ValueStatement exception :"<<nl;
1670  cerr << pe.what() <<nl;
1671  }
1672  } catch ( parse_exception& pe ) {
1673  // syntactic errors must be reported immediately
1674  if (debug)
1675  cerr << "parse_exception :";
1676  cerr << pe.what() <<nl;
1677  return;
1678  }
1679  if (debug)
1680  cerr << "Trying Expression..."<<nl;
1681  try {
1682  // Check if it was a method or datasource :
1683  last_expr = _parser.parseExpression( comm, context );
1684  // methods and DS'es are processed immediately.
1685  if ( last_expr ) {
1686  // only print if no ';' was given.
1687  assert( comm.size() != 0 );
1688  if ( comm[ comm.size() - 1 ] != ';' ) {
1689  this->printResult( last_expr.get(), true );
1690  cout << sresult.str() << nl << endl;
1691  sresult.str("");
1692  } else
1693  last_expr->evaluate();
1694  return; // done here
1695  } else if (debug)
1696  cerr << "returned (null) !"<<nl;
1697  } catch ( syntactic_parse_exception& pe ) { // missing brace etc
1698  // syntactic errors must be reported immediately
1699  if (debug)
1700  cerr << "syntactic_parse_exception :";
1701  cerr << pe.what() <<nl;
1702  return;
1703  } catch ( fatal_semantic_parse_exception& pe ) { // incorr args, ...
1704  // way to fatal, must be reported immediately
1705  if (debug)
1706  cerr << "fatal_semantic_parse_exception :";
1707  cerr << pe.what() <<nl;
1708  return;
1709  } catch ( parse_exception_parser_fail &pe )
1710  {
1711  // We're the last parser!
1712  if (debug)
1713  cerr << "Ignoring Expression exception :"<<nl;
1714  cerr << pe.what() <<nl;
1715 
1716  } catch ( parse_exception& pe ) {
1717  // We're the last parser!
1718  if (debug)
1719  cerr << "Ignoring Expression parse_exception :"<<nl;
1720  cerr << pe.what() <<nl;
1721  }
1722  }
1723 
1725  std::string prompt(" = ");
1726  // setup prompt :
1727  sresult <<prompt<< setw(20)<<left;
1728  if ( ds )
1729  doPrint( ds, recurse );
1730  else
1731  sresult << "(null)";
1732  sresult << right;
1733  }
1734 
1736  if (!ds) {
1737  sresult << "(null)";
1738  return;
1739  }
1740 
1741  // this is needed for ds's that rely on initialision.
1742  // e.g. eval true once or time measurements.
1743  // becomes only really handy for 'watches' (to deprecate).
1744  ds->reset();
1745  // this is needed to read a ds's value. Otherwise, a cached value may be returned.
1746  ds->evaluate();
1747 
1748  DataSource<RTT::PropertyBag>* dspbag = DataSource<RTT::PropertyBag>::narrow(ds.get());
1749  if (dspbag) {
1750  RTT::PropertyBag bag( dspbag->get() );
1751  if (!recurse) {
1752  int siz = bag.getProperties().size();
1753  int wdth = siz ? (20 - (siz / 10 + 1)) : 20;
1754  sresult <<setw(0)<< siz <<setw( wdth )<< " Properties";
1755  } else {
1756  if ( ! bag.empty() ) {
1757  sresult <<setw(0)<<nl;
1758  for( RTT::PropertyBag::iterator it= bag.getProperties().begin(); it!=bag.getProperties().end(); ++it) {
1759  sresult <<setw(14)<<right<< Types()->toDot( (*it)->getType() )<<" "<<coloron<<setw(14)<< (*it)->getName()<<coloroff;
1760  base::DataSourceBase::shared_ptr propds = (*it)->getDataSource();
1761  this->printResult( propds.get(), false );
1762  sresult <<" ("<<(*it)->getDescription()<<')' << nl;
1763  }
1764  } else {
1765  sresult <<prompt<<"(empty RTT::PropertyBag)";
1766  }
1767  }
1768  return;
1769  }
1770 
1771  // Print the members of the type:
1773  if (dsb->getMemberNames().empty() || dsb->getTypeInfo()->isStreamable() ) {
1774  if (debug) cerr << "terminal item " << dsb->getTypeName() << nl;
1775  if (usehex)
1776  sresult << std::hex << dsb;
1777  else
1778  sresult << std::dec << dsb;
1779  } else {
1780  sresult << setw(0);
1781  sresult << "{";
1782  vector<string> names = dsb->getMemberNames();
1783  if ( find(names.begin(), names.end(), "capacity") != names.end() &&
1784  find(names.begin(), names.end(), "size") != names.end() ) {
1785  // is a container/sequence:
1786  DataSource<int>::shared_ptr seq_size = dynamic_pointer_cast<DataSource<int> >(dsb->getMember("size"));
1787  if (seq_size) {
1788  ValueDataSource<unsigned int>::shared_ptr index = new ValueDataSource<unsigned int>(0);
1789  // print max 10 items of sequence:
1790  sresult << " [";
1791  for (int i=0; i != seq_size->get(); ++i) {
1792  index->set( i );
1793  if (i == 10) {
1794  sresult << "...("<< seq_size->get() - 10 <<" items omitted)...";
1795  break;
1796  } else {
1797  DataSourceBase::shared_ptr element = dsb->getMember(index, DataSourceBase::shared_ptr() );
1798  doPrint(element, true);
1799  if (i+1 != seq_size->get())
1800  sresult <<", ";
1801  }
1802  }
1803  sresult << " ], "; // size and capacity will follow...
1804  }
1805  }
1806  for(vector<string>::iterator it = names.begin(); it != names.end(); ) {
1807  sresult << *it << " = ";
1808  doPrint( dsb->getMember(*it), true);
1809  if (++it != names.end())
1810  sresult <<", ";
1811  }
1812  sresult <<" }";
1813  }
1814  }
1815 
1816  struct comcol
1817  {
1818  const char* command;
1819  comcol(const char* c) :command(c) {}
1820  std::ostream& operator()( std::ostream& os ) const {
1821  os<<"'"<< TaskBrowser::coloron<< TaskBrowser::underline << command << TaskBrowser::coloroff<<"'";
1822  return os;
1823  }
1824  };
1825 
1826  struct keycol
1827  {
1828  const char* command;
1829  keycol(const char* c) :command(c) {}
1830  std::ostream& operator()( std::ostream& os )const {
1831  os<<"<"<< TaskBrowser::coloron<< TaskBrowser::underline << command << TaskBrowser::coloroff<<">";
1832  return os;
1833  }
1834  };
1835 
1836  struct titlecol
1837  {
1838  const char* command;
1839  titlecol(const char* c) :command(c) {}
1840  std::ostream& operator()( std::ostream& os ) const {
1841  os<<endl<<"["<< TaskBrowser::coloron<< TaskBrowser::underline << command << TaskBrowser::coloroff<<"]";
1842  return os;
1843  }
1844  };
1845 
1846  std::ostream& operator<<(std::ostream& os, comcol f ){
1847  return f(os);
1848  }
1849 
1850  std::ostream& operator<<(std::ostream& os, keycol f ){
1851  return f(os);
1852  }
1853 
1854  std::ostream& operator<<(std::ostream& os, titlecol f ){
1855  return f(os);
1856  }
1857 
1859  {
1860  cout << coloroff;
1861  cout <<titlecol("Task Browsing")<<nl;
1862  cout << " To switch to another task, type "<<comcol("cd <path-to-taskname>")<<nl;
1863  cout << " and type "<<comcol("cd ..")<<" to go back to the previous task (History size is 20)."<<nl;
1864  cout << " Pressing "<<keycol("tab")<<" multiple times helps you to complete your command."<<nl;
1865  cout << " It is not mandatory to switch to a task to interact with it, you can type the"<<nl;
1866  cout << " peer-path to the task (dot-separated) and then type command or expression :"<<nl;
1867  cout << " PeerTask.OtherTask.FinalTask.countTo(3) [enter] "<<nl;
1868  cout << " Where 'countTo' is a method of 'FinalTask'."<<nl;
1869  cout << " The TaskBrowser starts by default 'In' the current component. In order to watch"<<nl;
1870  cout << " the TaskBrowser itself, type "<<comcol("leave")<<" You will notice that it"<<nl;
1871  cout << " has connected to the data ports of the visited component. Use "<<comcol("enter")<<" to enter"<<nl;
1872  cout << " the visited component again. The "<<comcol("cd")<<" command works transparantly in both"<<nl;
1873  cout << " modi."<<nl;
1874 
1875  cout << " "<<titlecol("Task Context Info")<<nl;
1876  cout << " To see the contents of a task, type "<<comcol("ls")<<nl;
1877  cout << " For a detailed argument list (and helpful info) of the object's methods, "<<nl;
1878  cout <<" type the name of one of the listed task objects : " <<nl;
1879  cout <<" this [enter]" <<nl<<nl;
1880  cout <<" factor( int number ) : bool" <<nl;
1881  cout <<" Factor a value into its primes." <<nl;
1882  cout <<" number : The number to factor in primes." <<nl;
1883  cout <<" isRunning( ) : bool" <<nl;
1884  cout <<" Is this RTT::TaskContext started ?" <<nl;
1885  cout <<" loadProgram( const& std::string Filename ) : bool" <<nl;
1886  cout <<" Load an Orocos Program Script from a file." <<nl;
1887  cout <<" Filename : An ops file." <<nl;
1888  cout <<" ..."<<nl;
1889 
1890  cout << " A status character shows the TaskState of a component."<<nl;
1891  cout << " 'E':RunTimeError, 'S':Stopped, 'R':Running, 'U':PreOperational (Unconfigured)"<<nl;
1892  cout << " 'X':Exception, 'F':FatalError" << nl;
1893 
1894  cout <<titlecol("Expressions")<<nl;
1895  cout << " You can evaluate any script expression by merely typing it :"<<nl;
1896  cout << " 1+1 [enter]" <<nl;
1897  cout << " = 2" <<nl;
1898  cout << " or inspect the status of a program :"<<nl;
1899  cout << " myProgram.isRunning [enter]" <<nl;
1900  cout << " = false" <<nl;
1901  cout << " and display the contents of complex data types (vector, array,...) :"<<nl;
1902  cout << " array(6)" <<nl;
1903  cout << " = {0, 0, 0, 0, 0, 0}" <<nl;
1904 
1905  cout <<titlecol("Changing Attributes and Properties")<<nl;
1906  cout << " To change the value of a Task's attribute, type "<<comcol("varname = <newvalue>")<<nl;
1907  cout << " If you provided a correct assignment, the browser will inform you of the success"<<nl;
1908  cout <<" with the set value." <<nl;
1909 
1910  cout <<titlecol("Operations")<<nl;
1911  cout << " An Operation is sent or called (evaluated) "<<nl;
1912  cout << " immediately and print the result. An example could be :"<<nl;
1913  cout << " someTask.bar.getNumberOfBeers(\"Palm\") [enter] "<<nl;
1914  cout << " = 99" <<nl;
1915  cout << " You can ask help on an operation by using the 'help' command: "<<nl;
1916  cout << " help start"<<nl;
1917  cout << " start( ) : bool"<<nl;
1918  cout << " Start this TaskContext (= startHook() + updateHook() )." <<nl;
1919 
1920  cout <<titlecol("Program and scripting::StateMachine Scripts")<<nl;
1921  cout << " To load a program script use the scripting service."<<nl;
1922  cout << " Use "<<comcol(".provide scripting")<< " to load the scripting service in a TaskContext."<<nl;
1923  cout << " You can use "<<comcol("ls progname")<<nl;
1924  cout << " to see the programs operations and variables. You can manipulate each one of these"<<nl;
1925  cout << " using the service object of the program."<<nl;
1926 
1927  cout << " To print a program or state machine listing, use "<<comcol("list progname [linenumber]")<<nl;
1928  cout << " to list the contents of the current program lines being executed,"<<nl;
1929  cout << " or 10 lines before or after <linenumber>. When only "<<comcol("list [n]")<<nl;
1930  cout << " is typed, 20 lines of the last listed program are printed from line <n> on "<<nl;
1931  cout << " ( default : list next 20 lines after previous list )."<<nl;
1932 
1933  cout << " To trace a program or state machine listing, use "<<comcol("trace [progname]")<<" this will"<<nl;
1934  cout << " cause the TaskBrowser to list the contents of a traced program,"<<nl;
1935  cout << " each time the line number of the traced program changes."<<nl;
1936  cout << " Disable tracing with "<<comcol("untrace [progname]")<<""<<nl;
1937  cout << " If no arguments are given to "<<comcol("trace")<<" and "<<comcol("untrace")<<", it applies to all programs."<<nl;
1938 
1939  cout << " A status character shows which line is being executed."<<nl;
1940  cout << " For programs : 'E':Error, 'S':Stopped, 'R':Running, 'P':Paused"<<nl;
1941  cout << " For state machines : <the same as programs> + 'A':Active, 'I':Inactive"<<nl;
1942 
1943  cout <<titlecol("Changing Colors")<<nl;
1944  cout << " You can inform the TaskBrowser of your background color by typing "<<comcol(".dark")<<nl;
1945  cout << " "<<comcol(".light")<<", or "<<comcol(".nocolors")<<" to increase readability."<<nl;
1946 
1947  cout <<titlecol("Output Formatting")<<nl;
1948  cout << " Use the commands "<<comcol(".hex") << " or " << comcol(".nohex") << " to turn hexadecimal "<<nl;
1949  cout << " notation of integers on or off."<<nl;
1950 
1951  cout <<titlecol("Macro Recording / RTT::Command line history")<<nl;
1952  cout << " You can browse the commandline history by using the up-arrow key or press "<<comcol("Ctrl r")<<nl;
1953  cout << " and a search term. Hit enter to execute the current searched command."<<nl;
1954  cout << " Macros can be recorded using the "<<comcol(".record 'macro-name'")<<" command."<<nl;
1955  cout << " You can cancel the recording by typing "<<comcol(".cancel")<<" ."<<nl;
1956  cout << " You can save and load the macro by typing "<<comcol(".end")<<" . The macro becomes"<<nl;
1957  cout << " available as a command with name 'macro-name' in the current TaskContext." << nl;
1958  cout << " While you enter the macro, it is not executed, as you must use scripting syntax which"<<nl;
1959  cout << " may use loop or conditional statements, variables etc."<<nl;
1960 
1961  cout <<titlecol("Connecting Ports")<<nl;
1962  cout << " You can instruct the TaskBrowser to connect to the ports of the current Peer by"<<nl;
1963  cout << " typing "<<comcol(".connect [port-name]")<<", which will temporarily create connections"<<nl;
1964  cout << " to all ports if [port-name] is omitted or to the specified port otherwise."<<nl;
1965  cout << " The TaskBrowser disconnects these ports when it visits another component, but the"<<nl;
1966  cout << " created connection objects remain in place (this is more or less a bug)!"<<nl;
1967 
1968  cout <<titlecol("Plugins, Typekits and Services")<<nl;
1969  cout << " Use "<<comcol(".provide [servicename]")<< " to load a service in a TaskContext."<<nl;
1970  cout << " For example, to add XML marshalling, type: "<<comcol(".provide marshalling")<< "."<<nl;
1971  cout << " Use "<<comcol(".services")<< " to get a list of available services."<<nl;
1972  cout << " Use "<<comcol(".typekits")<< " to get a list of available typekits."<<nl;
1973  cout << " Use "<<comcol(".types")<< " to get a list of available data types."<<nl;
1974  }
1975 
1976  void TaskBrowser::printHelp( string helpstring ) {
1977  peer = context;
1978  // trim garbage:
1979  str_trim(helpstring, ' ');
1980  str_trim(helpstring, '.');
1981 
1982  if ( printService(helpstring))
1983  return;
1984 
1985  if ( findPeer( helpstring ) ) {
1986  try {
1987  // findPeer resolved the taskobject holding 'helpstring'.
1988  sresult << nl;
1989  if (helpstring.rfind('.') != string::npos )
1990  printOperation( helpstring.substr(helpstring.rfind('.')+1 ), taskobject );
1991  else
1992  printOperation( helpstring, taskobject );
1993  cout << sresult.str();
1994  } catch (...) {
1995  cerr<< " help: No such operation known: '"<< helpstring << "'"<<nl;
1996  }
1997  } else {
1998  cerr<< " help: No such operation known (peer not found): '"<< helpstring << "'"<<nl;
1999  }
2000  sresult.str("");
2001  }
2002 
2003  void TaskBrowser::printProgram(const std::string& progname, int cl /*= -1*/, RTT::TaskContext* progpeer /* = 0 */) {
2004  string ps;
2005  char s;
2006  stringstream txtss;
2007  int ln;
2008  int start;
2009  int end;
2010  bool found(false);
2011 
2012  if (progpeer == 0 )
2013  progpeer = context;
2014 
2015  // if program exists, display.
2016  if ( progpeer->getProvider<Scripting>("scripting")->hasProgram( progname ) ) {
2017  s = getProgramStatusChar(progpeer, progname);
2018  txtss.str( progpeer->getProvider<Scripting>("scripting")->getProgramText(progname) );
2019  ln = progpeer->getProvider<Scripting>("scripting")->getProgramLine(progname);
2020  if ( cl < 0 ) cl = ln;
2021  start = cl < 10 ? 1 : cl - 10;
2022  end = cl + 10;
2023  this->listText( txtss, start, end, ln, s);
2024  found = true;
2025  }
2026 
2027  // If statemachine exists, display.
2028  if ( progpeer->getProvider<Scripting>("scripting")->hasStateMachine( progname ) ) {
2029  s = getStateMachineStatusChar(progpeer, progname);
2030  txtss.str( progpeer->getProvider<Scripting>("scripting")->getStateMachineText(progname) );
2031  ln = progpeer->getProvider<Scripting>("scripting")->getStateMachineLine(progname);
2032  if ( cl < 0 ) cl = ln;
2033  start = cl <= 10 ? 1 : cl - 10;
2034  end = cl + 10;
2035  this->listText( txtss, start, end, ln, s);
2036  found = true;
2037  }
2038  if ( !found ) {
2039  cerr << "Error : No such program or state machine found : "<<progname;
2040  cerr << " in "<< progpeer->getName() <<"."<<endl;
2041  return;
2042  }
2043  storedname = progname;
2044  }
2045 
2046  void TaskBrowser::printProgram(int cl /* = -1 */) {
2047  string ps;
2048  char s;
2049  stringstream txtss;
2050  int ln;
2051  int start;
2052  int end;
2053  bool found(false);
2054  if ( context->getProvider<Scripting>("scripting")->hasProgram( storedname ) ) {
2056  txtss.str( context->getProvider<Scripting>("scripting")->getProgramText(storedname) );
2057  ln = context->getProvider<Scripting>("scripting")->getProgramLine(storedname);
2058  if ( cl < 0 ) cl = storedline;
2059  if (storedline < 0 ) cl = ln -10;
2060  start = cl;
2061  end = cl + 20;
2062  this->listText( txtss, start, end, ln, s);
2063  found = true;
2064  }
2065  if ( context->getProvider<Scripting>("scripting")->hasStateMachine(storedname) ) {
2067  txtss.str( context->getProvider<Scripting>("scripting")->getStateMachineText(storedname) );
2068  ln = context->getProvider<Scripting>("scripting")->getStateMachineLine(storedname);
2069  if ( cl < 0 ) cl = storedline;
2070  if (storedline < 0 ) cl = ln -10;
2071  start = cl;
2072  end = cl+20;
2073  this->listText( txtss, start, end, ln, s);
2074  found = true;
2075  }
2076  if ( !found )
2077  cerr << "Error : No such program or state machine found : "<<storedname<<endl;
2078  }
2079 
2080  void TaskBrowser::listText(stringstream& txtss,int start, int end, int ln, char s) {
2081  int curln = 1;
2082  string line;
2083  while ( start > 1 && curln != start ) { // consume lines
2084  getline( txtss, line, '\n' );
2085  if ( ! txtss )
2086  break; // no more lines, break.
2087  ++curln;
2088  }
2089  while ( end > start && curln != end ) { // print lines
2090  getline( txtss, line, '\n' );
2091  if ( ! txtss )
2092  break; // no more lines, break.
2093  if ( curln == ln ) {
2094  cout << s<<'>';
2095  }
2096  else
2097  cout << " ";
2098  cout<< setw(int(log(double(end)))) <<right << curln<< left;
2099  cout << ' ' << line <<endl;
2100  ++curln;
2101  }
2102  storedline = curln;
2103  // done !
2104  }
2105 
2106  void TaskBrowser::printInfo(const std::string& peerp)
2107  {
2108  // this sets this->peer to the peer given
2109  peer = context;
2110  taskobject = peer->provides();
2111  if ( !peerp.empty() && peerp != "." && this->findPeer( peerp+"." ) == 0 ) {
2112  cerr << "No such peer or object: " << peerp << endl;
2113  return;
2114  }
2115 
2116  if ( !peer || !peer->ready()) {
2117  cout << nl << " Connection to peer "+peerp+" lost (peer->ready() == false)." <<endlog();
2118  return;
2119  }
2120 
2121  // sresult << *it << "["<<getTaskStatusChar(peer->getPeer(*it))<<"] ";
2122 
2123 
2124  if ( peer->provides() == taskobject )
2125  sresult <<nl<<" Listing TaskContext "<< green << peer->getName()<<coloroff << "["<<getTaskStatusChar(peer)<<"] :"<<nl;
2126  else
2127  sresult <<nl<<" Listing Service "<< green << taskobject->getName()<<coloroff<< "["<<getTaskStatusChar(peer)<<"] :"<<nl;
2128 
2129  sresult <<nl<<" Configuration Properties: ";
2130  RTT::PropertyBag* bag = taskobject->properties();
2131  if ( bag && bag->size() != 0 ) {
2132  // Print Properties:
2133  for( RTT::PropertyBag::iterator it = bag->begin(); it != bag->end(); ++it) {
2134  base::DataSourceBase::shared_ptr pds = (*it)->getDataSource();
2135  sresult << nl << setw(11)<< right << Types()->toDot( (*it)->getType() )<< " "
2136  << coloron <<setw(14)<<left<< (*it)->getName() << coloroff;
2137  this->printResult( pds.get(), false ); // do not recurse
2138  sresult<<" ("<< (*it)->getDescription() <<')';
2139  }
2140  } else {
2141  sresult << "(none)";
2142  }
2143  sresult <<nl;
2144 
2145  // Print "this" interface (without detail) and then list objects...
2146  sresult <<nl<< " Provided Interface:";
2147 
2148  sresult <<nl<< " Attributes : ";
2149  std::vector<std::string> objlist = taskobject->getAttributeNames();
2150  if ( !objlist.empty() ) {
2151  sresult << nl;
2152  // Print Attributes:
2153  for( std::vector<std::string>::iterator it = objlist.begin(); it != objlist.end(); ++it) {
2154  base::DataSourceBase::shared_ptr pds = taskobject->getValue(*it)->getDataSource();
2155  sresult << setw(11)<< right << Types()->toDot( pds->getType() )<< " "
2156  << coloron <<setw( 14 )<<left<< *it << coloroff;
2157  this->printResult( pds.get(), false ); // do not recurse
2158  sresult <<nl;
2159  }
2160  } else {
2161  sresult << coloron << "(none)";
2162  }
2163 
2164  sresult <<coloroff<<nl<< " Operations : "<<coloron;
2165  objlist = taskobject->getNames();
2166  if ( !objlist.empty() ) {
2167  std::copy(objlist.begin(), objlist.end(), std::ostream_iterator<std::string>(sresult, " "));
2168  } else {
2169  sresult << "(none)";
2170  }
2171  sresult << coloroff << nl;
2172 
2173  sresult <<nl<< " Data Flow Ports: ";
2174  objlist = taskobject->getPortNames();
2175  if ( !objlist.empty() ) {
2176  for(vector<string>::iterator it = objlist.begin(); it != objlist.end(); ++it) {
2177  base::PortInterface* port = taskobject->getPort(*it);
2178  bool writer = dynamic_cast<OutputPortInterface*>(port) ? true : false;
2179  // Port type R/W
2180  sresult << nl << " " << ( !writer ?
2181  " In" : "Out");
2182  // Port data type + name
2183  if ( !port->connected() )
2184  sresult << "(U) " << setw(11)<<right<< Types()->toDot( port->getTypeInfo()->getTypeName() );
2185  else
2186  sresult << "(C) " << setw(11)<<right<< Types()->toDot( port->getTypeInfo()->getTypeName() );
2187  sresult << " "
2188  << coloron <<setw( 14 )<<left<< *it << coloroff;
2189 
2190  InputPortInterface* iport = dynamic_cast<InputPortInterface*>(port);
2191  if (iport) {
2192  sresult << " <= ( use '"<< iport->getName() << ".read(sample)' to read a sample from this port)";
2193  }
2194  OutputPortInterface* oport = dynamic_cast<OutputPortInterface*>(port);
2195  if (oport) {
2196  if ( oport->keepsLastWrittenValue()) {
2197  DataSourceBase::shared_ptr dsb = oport->getDataSource();
2198  dsb->evaluate(); // read last written value.
2199  sresult << " => " << dsb;
2200  } else
2201  sresult << " => (keepsLastWrittenValue() == false. Enable it for this port in order to see it in the TaskBrowser.)";
2202  }
2203 #if 0
2204  // only show if we're connected to it
2205  if (peer == taskcontext && peer->provides() == taskobject) {
2206  // Lookup if we have an input with that name and
2207  // consume the last sample this port produced.
2208  InputPortInterface* iport = dynamic_cast<InputPortInterface*>(ports()->getPort(port->getName()));
2209  if (iport) {
2210  // consume sample
2211  iport->getDataSource()->evaluate();
2212  // display
2213  if ( peer == this)
2214  sresult << " <= " << DataSourceBase::shared_ptr( iport->getDataSource());
2215  else
2216  sresult << " => " << DataSourceBase::shared_ptr( iport->getDataSource());
2217  }
2218  OutputPortInterface* oport = dynamic_cast<OutputPortInterface*>(ports()->getPort(port->getName()));
2219  if (oport) {
2220  // display last written value:
2221  DataSourceBase::shared_ptr ds = oport->getDataSource();
2222  if (ds) {
2223  if ( peer == this)
2224  sresult << " => " << ds;
2225  else
2226  sresult << " <= " << ds << " (sent from TaskBrowser)";
2227  } else {
2228  sresult << "(no last written value kept)";
2229  }
2230  }
2231  } else {
2232  sresult << "(TaskBrowser not connected to this port)";
2233  }
2234 #endif
2235  // Port description (see Service)
2236 // if ( peer->provides(*it) )
2237 // sresult << " ( "<< taskobject->provides(*it)->getDescription() << " ) ";
2238  }
2239  } else {
2240  sresult << "(none)";
2241  }
2242  sresult << coloroff << nl;
2243 
2244  objlist = taskobject->getProviderNames();
2245  sresult <<nl<< " Services: "<<nl;
2246  if ( !objlist.empty() ) {
2247  for(vector<string>::iterator it = objlist.begin(); it != objlist.end(); ++it)
2248  sresult <<coloron<< " " << setw(14) << *it <<coloroff<< " ( "<< taskobject->provides(*it)->doc() << " ) "<<nl;
2249  } else {
2250  sresult <<coloron<< "(none)" <<coloroff <<nl;
2251  }
2252 
2253  // RTT::TaskContext specific:
2254  if ( peer->provides() == taskobject ) {
2255 
2256  objlist = peer->requires()->getOperationCallerNames();
2257  sresult <<nl<< " Requires Operations :";
2258  if ( !objlist.empty() ) {
2259  for(vector<string>::iterator it = objlist.begin(); it != objlist.end(); ++it)
2260  sresult <<coloron<< " " << *it <<coloroff << '[' << (peer->requires()->getOperationCaller(*it)->ready() ? "R]" : "!]");
2261  sresult << nl;
2262  } else {
2263  sresult <<coloron<< " (none)" <<coloroff <<nl;
2264  }
2265  objlist = peer->requires()->getRequesterNames();
2266  sresult << " Requests Services :";
2267  if ( !objlist.empty() ) {
2268  for(vector<string>::iterator it = objlist.begin(); it != objlist.end(); ++it)
2269  sresult <<coloron<< " " << *it <<coloroff << '[' << (peer->requires(*it)->ready() ? "R]" : "!]");
2270  sresult << nl;
2271  } else {
2272  sresult <<coloron<< " (none)" <<coloroff <<nl;
2273  }
2274 
2275  if (peer->provides()->hasService("scripting")) {
2276  objlist = peer->getProvider<Scripting>("scripting")->getProgramList();
2277  if ( !objlist.empty() ) {
2278  sresult << " Programs : "<<coloron;
2279  for(vector<string>::iterator it = objlist.begin(); it != objlist.end(); ++it)
2280  sresult << *it << "["<<getProgramStatusChar(peer,*it)<<"] ";
2281  sresult << coloroff << nl;
2282  }
2283 
2284  objlist = peer->getProvider<Scripting>("scripting")->getStateMachineList();
2285  if ( !objlist.empty() ) {
2286  sresult << " StateMachines: "<<coloron;
2287  for(vector<string>::iterator it = objlist.begin(); it != objlist.end(); ++it)
2288  sresult << *it << "["<<getStateMachineStatusChar(peer,*it)<<"] ";
2289  sresult << coloroff << nl;
2290  }
2291  }
2292 
2293  // if we are in the TB, display the peers of our connected task:
2294  if ( context == tb )
2295  sresult <<nl<< " "<<peer->getName()<<" Peers : "<<coloron;
2296  else
2297  sresult << nl <<" Peers : "<<coloron;
2298 
2299  objlist = peer->getPeerList();
2300  if ( !objlist.empty() )
2301  for(vector<string>::iterator it = objlist.begin(); it != objlist.end(); ++it) {
2302  if( peer->getPeer(*it) )
2303  sresult << *it << "["<<getTaskStatusChar(peer->getPeer(*it))<<"] ";
2304  else
2305  sresult << *it << "[X] ";
2306  }
2307  else
2308  sresult << "(none)";
2309  }
2310  sresult <<coloroff<<nl;
2311  cout << sresult.str();
2312  sresult.str("");
2313  }
2314 
2315  void TaskBrowser::printOperation( const std::string m, Service::shared_ptr the_ops )
2316  {
2317  std::vector<ArgumentDescription> args;
2318  Service::shared_ptr ops;
2319  try {
2320  args = the_ops->getArgumentList( m ); // may throw !
2321  ops = the_ops;
2322  } catch(...) {
2323  args = GlobalService::Instance()->getArgumentList( m ); // may throw !
2324  ops = GlobalService::Instance();
2325  }
2326  sresult <<" " << coloron << m << coloroff<< "( ";
2327  for (std::vector<ArgumentDescription>::iterator it = args.begin(); it != args.end(); ++it) {
2328  sresult << Types()->toDot( it->type ) <<" ";
2329  sresult << coloron << it->name << coloroff;
2330  if ( it+1 != args.end() )
2331  sresult << ", ";
2332  else
2333  sresult << " ";
2334  }
2335  sresult << ") : "<< Types()->toDot( ops->getResultType(m) )<<nl;
2336  sresult << " " << ops->getDescription( m )<<nl;
2337  for (std::vector<ArgumentDescription>::iterator it = args.begin(); it != args.end(); ++it)
2338  sresult <<" "<< it->name <<" : " << it->description << nl;
2339  }
2340 
2341 }
void loop()
Call this method from ORO_main() to process keyboard input and thus startup the TaskBrowser.
titlecol(const char *c)
void listText(std::stringstream &txtss, int start, int end, int ln, char s)
Variable opBinary s not applicable to args
Definition: rtt.cpp:757
base::PortInterface & addPort(const std::string &name, base::PortInterface &port)
std::ostream & operator<<(std::ostream &os, comcol f)
const char * command
virtual const types::TypeInfo * getTypeInfo() const =0
static RTT::TaskContext * taskcontext
Definition: TaskBrowser.hpp:90
iterator end()
Use colors suitable for a white background.
void evalCommand(std::string &comm)
std::ostream & operator()(std::ostream &os) const
Service::shared_ptr provides()
virtual const std::string what() const =0
void setColorTheme(ColorTheme t)
const std::string & getTypeName() const
static std::ostream & nl(std::ostream &__os)
char getProgramStatusChar(RTT::TaskContext *t, string progname)
void doPrint(RTT::base::DataSourceBase::shared_ptr ds, bool recurse)
std::deque< TaskContext * > taskHistory
#define SKIP_PARSER
std::stringstream sresult
bool loadService(const std::string &service_name)
static RTT::TaskContext * context
Definition: TaskBrowser.hpp:96
void printProgram(const std::string &pn, int line=-1, RTT::TaskContext *progpeer=0)
char getStateMachineStatusChar(RTT::TaskContext *t, string progname)
bool usehex
last program line number listed to screen
boost::shared_ptr< ServiceRequester > shared_ptr
const std::string & getName() const
Do not use colors.
void browserAction(std::string &act)
Use colors suitable for a dark background.
static std::string green
char getTaskStatusChar(RTT::TaskContext *t)
static RTT::Service::shared_ptr taskobject
Definition: TaskBrowser.hpp:97
OperationCaller< std::string(const std::string &)> getStateMachineText
base::DataSourceBase::shared_ptr parseValueStatement(const std::string &s, TaskContext *)
virtual bool isConfigured() const
virtual bool isRunning() const
void str_trim(string &str, char to_trim)
std::ostream & operator()(std::ostream &os) const
virtual TaskContext * getPeer(const std::string &peer_name) const
TaskBrowser(RTT::TaskContext *c)
boost::shared_ptr< Service > shared_ptr
virtual bool inException() const
virtual bool hasPeer(const std::string &peer_name) const
keycol(const char *c)
const char * command
OperationCaller< bool(const std::string &)> hasStateMachine
void switchTaskContext(std::string &path)
ServiceRequester::shared_ptr requires()
static RTT::TaskContext * findPeer(std::string comm)
printstream cout
position_iterator< our_iterator_t > our_pos_iter_t
virtual void disconnect()
comcol(const char *c)
DataFlowInterface * ports()
std::string macroname
virtual bool inFatalError() const
base::PortInterface * getPort(const std::string &name) const
virtual PeerList getPeerList() const
void removePort(const std::string &name)
base::DataSourceBase::shared_ptr last_expr
const char * histfile
std::vector< std::string > PeerList
LOG4CPP_EXPORT CategoryStream & left(CategoryStream &os)
Debug
TypeInfoRepository::shared_ptr Types()
basic_ostreams & endl(basic_ostreams &s)
void printInfo(const std::string &peerpath)
void printResult(RTT::base::DataSourceBase *ds, bool recurse)
std::vector< base::PortInterface * > Ports
static std::string prompt
Error
base::DataSourceBase::shared_ptr parseExpression(const std::string &s, TaskContext *)
boost::intrusive_ptr< DataSource< int > > shared_ptr
virtual bool inRunTimeError() const
std::string macrotext
Info
static RTT::TaskContext * peer
Definition: TaskBrowser.hpp:92
const char * command
static std::string coloroff
OperationCaller< std::string(const std::string &)> getProgramText
Warning
Service::shared_ptr stringToService(std::string const &names)
int storedline
last program listed to screen
static RTT::TaskContext * tb
Definition: TaskBrowser.hpp:94
static std::string underline
bool printService(const std::string name)
void printOperation(const std::string m, Service::shared_ptr ops)
Ports getPorts() const
void evaluate(std::string &comm)
static std::string blue
bool connectPorts(TaskContext *A, TaskContext *B)
Properties::iterator iterator
boost::intrusive_ptr< DataSourceBase > shared_ptr
static std::string red
size_t size() const
virtual bool connected() const =0
static const char * progname
Definition: lua-repl.c:36
std::ostream & operator()(std::ostream &os) const
void recordMacro(std::string name)
OperationCaller< bool(const std::string &)> hasProgram
std::string storedname
static std::string coloron
virtual bool start()
virtual bool addPeer(TaskContext *peer, std::string alias="")
virtual const std::string & getName() const
iterator begin()
boost::shared_ptr< ServiceType > getProvider(const std::string &name)


ocl
Author(s): OCL Development Team
autogenerated on Wed Jun 26 2019 19:26:27