Parser.cpp
Go to the documentation of this file.
1 // **********************************************************************
2 //
3 // Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved.
4 //
5 // This copy of Ice is licensed to you under the terms described in the
6 // ICE_LICENSE file included in this distribution.
7 //
8 // **********************************************************************
9 
10 #include <IceUtil/DisableWarnings.h>
11 #include <Ice/Ice.h>
12 #include <Ice/ConsoleUtil.h>
13 #include <IceStorm/Parser.h>
15 #include <algorithm>
16 
17 #ifdef HAVE_READLINE
18 # include <readline/readline.h>
19 # include <readline/history.h>
20 #endif
21 
22 extern FILE* yyin;
23 extern int yydebug;
24 
25 using namespace std;
26 using namespace Ice;
27 using namespace IceInternal;
28 using namespace IceStorm;
29 
30 namespace IceStorm
31 {
32 
34 
35 #ifdef _WIN32
36  Ice::StringConverterPtr windowsConsoleConverter = 0;
37 #endif
38 
39 }
40 
41 namespace
42 {
43 
44  class UnknownManagerException : public Exception
45  {
46  public:
47 
48  UnknownManagerException(const string& name, const char* file, int line) :
49  Exception(file, line),
50  name(name)
51  {
52  }
53 
54 #ifndef ICE_CPP11_COMPILER
55  virtual
56  ~UnknownManagerException() throw()
57  {
58  }
59 #endif
60 
61  virtual string
62  ice_id() const
63  {
64  return "::UnknownManagerException";
65  }
66 
67  virtual Exception*
68  ice_clone() const
69  {
70  return new UnknownManagerException(*this);
71  }
72 
73  virtual void
74  ice_throw() const
75  {
76  throw* this;
77  }
78 
79  const string name;
80  };
81 
82 }
83 
85 Parser::createParser(const CommunicatorPtr& communicator, const TopicManagerPrx& admin,
86  const map<Ice::Identity, TopicManagerPrx>& managers)
87 {
88  return new Parser(communicator, admin, managers);
89 }
90 
91 void
92 Parser::usage()
93 {
94  consoleOut <<
95  "help Print this message.\n"
96  "exit, quit Exit this program.\n"
97  "create TOPICS Add TOPICS.\n"
98  "destroy TOPICS Remove TOPICS.\n"
99  "link FROM TO [COST] Link FROM to TO with the optional given COST.\n"
100  "unlink FROM TO Unlink TO from FROM.\n"
101  "links [INSTANCE-NAME] Display all links for the topics in the current topic\n"
102  " manager, or in the given INSTANCE-NAME.\n"
103  "topics [INSTANCE-NAME] Display the names of all topics in the current topic\n"
104  " manager, or in the given INSTANCE-NAME.\n"
105  "current [INSTANCE-NAME] Display the current topic manager, or change it to\n"
106  " INSTANCE-NAME.\n"
107  "replica [INSTANCE-NAME] Display replication information for the given INSTANCE-NAME.\n"
108  "subscribers TOPICS List TOPICS subscribers.\n"
109  ;
110 }
111 
112 void
113 Parser::create(const list<string>& args)
114 {
115  if (args.empty())
116  {
117  error("`create' requires at least one argument (type `help' for more info)");
118  return;
119  }
120 
121  for (list<string>::const_iterator i = args.begin(); i != args.end() ; ++i)
122  {
123  try
124  {
125  string topicName;
126  TopicManagerPrx manager = findManagerById(*i, topicName);
127  manager->create(topicName);
128  }
129  catch (const Ice::Exception& ex)
130  {
131  exception(ex, args.size() > 1); // Print a warning if we're creating multiple topics, an error otherwise.
132  }
133  }
134 }
135 
136 void
137 Parser::destroy(const list<string>& args)
138 {
139  if (args.empty())
140  {
141  error("`destroy' requires at least one argument (type `help' for more info)");
142  return;
143  }
144 
145  for (list<string>::const_iterator i = args.begin(); i != args.end() ; ++i)
146  {
147  try
148  {
149  findTopic(*i)->destroy();
150  }
151  catch (const Ice::Exception& ex)
152  {
153  exception(ex, args.size() > 1); // Print a warning if we're destroying multiple topics, an error otherwise.
154  }
155  }
156 }
157 
158 void
159 Parser::link(const list<string>& args)
160 {
161  if (args.size() != 2 && args.size() != 3)
162  {
163  error("`link' requires two or three arguments (type `help' for more info)");
164  return;
165  }
166 
167  try
168  {
169  list<string>::const_iterator p = args.begin();
170 
171  TopicPrx fromTopic = findTopic(*p++);
172  TopicPrx toTopic = findTopic(*p++);
173  Ice::Int cost = p != args.end() ? atoi(p->c_str()) : 0;
174 
175  fromTopic->link(toTopic, cost);
176  }
177  catch (const Exception& ex)
178  {
179  exception(ex);
180  }
181 }
182 
183 void
184 Parser::unlink(const list<string>& args)
185 {
186  if (args.size() != 2)
187  {
188  error("`unlink' requires exactly two arguments (type `help' for more info)");
189  return;
190  }
191 
192  try
193  {
194  list<string>::const_iterator p = args.begin();
195 
196  TopicPrx fromTopic = findTopic(*p++);
197  TopicPrx toTopic = findTopic(*p++);
198 
199  fromTopic->unlink(toTopic);
200  }
201  catch (const Exception& ex)
202  {
203  exception(ex);
204  }
205 }
206 
207 void
208 Parser::links(const list<string>& args)
209 {
210  if (args.size() > 1)
211  {
212  error("`links' requires at most one argument (type `help' for more info)");
213  return;
214  }
215 
216  try
217  {
218  TopicManagerPrx manager;
219  if (args.size() == 0)
220  {
221  manager = _defaultManager;
222  }
223  else
224  {
225  manager = findManagerByCategory(args.front());
226  }
227 
228  TopicDict d = manager->retrieveAll();
229  for (TopicDict::iterator i = d.begin(); i != d.end(); ++i)
230  {
231  LinkInfoSeq links = i->second->getLinkInfoSeq();
232  for (LinkInfoSeq::const_iterator p = links.begin(); p != links.end(); ++p)
233  {
234  consoleOut << i->first << " to " << p->name << " with cost " << p->cost << endl;
235  }
236  }
237  }
238  catch (const Exception& ex)
239  {
240  exception(ex);
241  }
242 }
243 
244 void
245 Parser::topics(const list<string>& args)
246 {
247  if (args.size() > 1)
248  {
249  error("`topics' requires at most one argument (type `help' for more info)");
250  return;
251  }
252 
253  try
254  {
255  TopicManagerPrx manager;
256  if (args.size() == 0)
257  {
258  manager = _defaultManager;
259  }
260  else
261  {
262  manager = findManagerByCategory(args.front());
263  }
264 
265  TopicDict d = manager->retrieveAll();
266  for (TopicDict::iterator i = d.begin(); i != d.end(); ++i)
267  {
268  consoleOut << i->first << endl;
269  }
270  }
271  catch (const Exception& ex)
272  {
273  exception(ex);
274  }
275 }
276 
277 void
278 Parser::replica(const list<string>& args)
279 {
280  if (args.size() > 1)
281  {
282  error("`replica' requires at most one argument (type `help' for more info)");
283  return;
284  }
285 
286  try
287  {
288  TopicManagerPrx m;
289  if (args.size() == 0)
290  {
291  m = _defaultManager;
292  }
293  else
294  {
295  m = findManagerByCategory(args.front());
296  }
297  TopicManagerInternalPrx manager = TopicManagerInternalPrx::uncheckedCast(m);
298  IceStormElection::NodePrx node = manager->getReplicaNode();
299  if (!node)
300  {
301  error("This topic is not replicated");
302  }
303  IceStormElection::NodeInfoSeq nodes = node->nodes();
304  consoleOut << "replica count: " << nodes.size() << endl;
305  for (IceStormElection::NodeInfoSeq::const_iterator p = nodes.begin(); p != nodes.end(); ++p)
306  {
307  try
308  {
309  IceStormElection::QueryInfo info = p->n->query();
310  consoleOut << p->id << ": id: " << info.id << endl;
311  consoleOut << p->id << ": coord: " << info.coord << endl;
312  consoleOut << p->id << ": group name: " << info.group << endl;
313  consoleOut << p->id << ": state: ";
314  switch (info.state)
315  {
317  consoleOut << "inactive";
318  break;
320  consoleOut << "election";
321  break;
323  consoleOut << "reorganization";
324  break;
326  consoleOut << "normal";
327  break;
328  default:
329  consoleOut << "unknown";
330  }
331  consoleOut << endl;
332  consoleOut << p->id << ": group: ";
333  for (IceStormElection::GroupInfoSeq::const_iterator q = info.up.begin(); q != info.up.end(); ++q)
334  {
335  if (q != info.up.begin())
336  {
337  consoleOut << ",";
338  }
339  consoleOut << q->id;
340  }
341  consoleOut << endl;
342  consoleOut << p->id << ": max: " << info.max
343  << endl;
344  }
345  catch (const Exception& ex)
346  {
347  consoleOut << p->id << ": " << ex.ice_id() << endl;
348  }
349  }
350  }
351  catch (const Exception& ex)
352  {
353  exception(ex);
354  }
355 }
356 
357 void
358 Parser::subscribers(const list<string>& args)
359 {
360  if (args.empty())
361  {
362  error("subscribers' requires at least one argument (type `help' for more info) ");
363  return;
364  }
365  try
366  {
367  for (list<string>::const_iterator i = args.begin(); i != args.end() ; ++i)
368  {
369  TopicPrx topic = _defaultManager->retrieve(*i);
370  consoleOut << (*i) << ": subscribers:" << endl;
371  IdentitySeq subscribers = topic->getSubscribers();
372  for (IdentitySeq::const_iterator j = subscribers.begin(); j != subscribers.end(); ++j)
373  {
374  consoleOut << "\t" << _communicator->identityToString(*j) << endl;
375  }
376  }
377  }
378  catch (const Exception& ex)
379  {
380  exception(ex);
381  }
382 }
383 
384 void
385 Parser::current(const list<string>& args)
386 {
387  if (args.empty())
388  {
389  consoleOut << _communicator->identityToString(_defaultManager->ice_getIdentity()) << endl;
390  return;
391  }
392  else if (args.size() > 1)
393  {
394  error("`current' requires at most one argument (type `help' for more info)");
395  return;
396  }
397 
398  try
399  {
400  TopicManagerPrx manager = findManagerByCategory(args.front());
401  manager->ice_ping();
402  _defaultManager = manager;
403  }
404  catch (const Exception& ex)
405  {
406  exception(ex);
407  }
408 }
409 
410 void
411 Parser::showBanner()
412 {
413  consoleOut << "Ice " << ICE_STRING_VERSION << " Copyright (c) 2003-2017 ZeroC, Inc." << endl;
414 }
415 
416 //
417 // With older flex version <= 2.5.35 YY_INPUT second
418 // paramenter is of type int&, in newer versions it
419 // changes to size_t&
420 //
421 void
422 Parser::getInput(char* buf, int& result, size_t maxSize)
423 {
424  size_t r = static_cast<size_t>(result);
425  getInput(buf, r, maxSize);
426  result = static_cast<int>(r);
427 }
428 
429 void
430 Parser::getInput(char* buf, size_t& result, size_t maxSize)
431 {
432  if (!_commands.empty())
433  {
434  if (_commands == ";")
435  {
436  result = 0;
437  }
438  else
439  {
440  result = min(maxSize, _commands.length());
441  strncpy(buf, _commands.c_str(), result);
442  _commands.erase(0, result);
443  if (_commands.empty())
444  {
445  _commands = ";";
446  }
447  }
448  }
449  else
450  {
451 #ifdef HAVE_READLINE
452 
453  const char* prompt = parser->getPrompt();
454  char* line = readline(const_cast<char*>(prompt));
455  if (!line)
456  {
457  result = 0;
458  }
459  else
460  {
461  if (*line)
462  {
463  add_history(line);
464  }
465 
466  result = strlen(line) + 1;
467  if (result > maxSize)
468  {
469  free(line);
470  error("input line too long");
471  result = 0;
472  }
473  else
474  {
475  strcpy(buf, line);
476  strcat(buf, "\n");
477  free(line);
478  }
479  }
480 
481 #else
482 
483  consoleOut << parser->getPrompt() << flush;
484 
485  string line;
486  while (true)
487  {
488  char c = static_cast<char>(getc(yyin));
489  if (c == static_cast<char>(EOF))
490  {
491  if (line.size())
492  {
493  line += '\n';
494  }
495  break;
496  }
497 
498  line += c;
499  if (c == '\n')
500  {
501  break;
502  }
503  }
504 #ifdef _WIN32
505  if (windowsConsoleConverter)
506  {
507  line = nativeToUTF8(line, windowsConsoleConverter);
508  }
509 #endif
510  result = line.length();
511  if (result > maxSize)
512  {
513  error("input line too long");
514  buf[0] = EOF;
515  result = 1;
516  }
517  else
518  {
519  strcpy(buf, line.c_str());
520  }
521 
522 #endif
523  }
524 }
525 
526 void
527 Parser::continueLine()
528 {
529  _continue = true;
530 }
531 
532 const char*
533 Parser::getPrompt()
534 {
535  assert(_commands.empty());
536 
537  if (_continue)
538  {
539  _continue = false;
540  return "(cont) ";
541  }
542  else
543  {
544  return ">>> ";
545  }
546 }
547 
548 void
549 Parser::error(const char* s)
550 {
551  consoleErr << "error: " << s << endl;
552  _errors++;
553 }
554 
555 void
556 Parser::error(const string& s)
557 {
558  error(s.c_str());
559 }
560 
561 void
562 Parser::warning(const char* s)
563 {
564  consoleErr << "warning: " << s << endl;
565 }
566 
567 void
568 Parser::warning(const string& s)
569 {
570  warning(s.c_str());
571 }
572 
573 void
574 Parser::invalidCommand(const string& s)
575 {
576  consoleErr << s << endl;
577 }
578 
579 int
580 Parser::parse(FILE* file, bool debug)
581 {
582  yydebug = debug ? 1 : 0;
583 
584  assert(!parser);
585  parser = this;
586 
587  _errors = 0;
588  bool commands_empty = _commands.empty();
589  (void) commands_empty;
590  yyin = file;
591  assert(yyin);
592 
593  _continue = false;
594 
595  int status = yyparse();
596  if (_errors)
597  {
598  status = EXIT_FAILURE;
599  }
600 
601  parser = 0;
602  return status;
603 }
604 
605 int
606 Parser::parse(const std::string& commands, bool debug)
607 {
608  yydebug = debug ? 1 : 0;
609 
610  assert(!parser);
611  parser = this;
612 
613  _errors = 0;
614  _commands = commands;
615  assert(!_commands.empty());
616  yyin = 0;
617 
618  _continue = false;
619 
620  int status = yyparse();
621  if (_errors)
622  {
623  status = EXIT_FAILURE;
624  }
625 
626  parser = 0;
627  return status;
628 }
629 
631 Parser::findManagerById(const string& full, string& arg) const
632 {
633  Ice::Identity id = Ice::stringToIdentity(full);
634  arg = id.name;
635  if (id.category.empty())
636  {
637  return _defaultManager;
638  }
639  id.name = "TopicManager";
640  map<Ice::Identity, TopicManagerPrx>::const_iterator p = _managers.find(id);
641  if (p == _managers.end())
642  {
643  throw UnknownManagerException(id.category, __FILE__, __LINE__);
644  }
645  return p->second;
646 }
647 
649 Parser::findManagerByCategory(const string& full) const
650 {
651  Ice::Identity id;
652  id.category = full;
653  id.name = "TopicManager";
654  map<Ice::Identity, TopicManagerPrx>::const_iterator p = _managers.find(id);
655  if (p == _managers.end())
656  {
657  throw UnknownManagerException(id.category, __FILE__, __LINE__);
658  }
659  return p->second;
660 }
661 
662 TopicPrx
663 Parser::findTopic(const string& full) const
664 {
665  string topicName;
666  TopicManagerPrx manager = findManagerById(full, topicName);
667  return manager->retrieve(topicName);
668 }
669 
670 Parser::Parser(const CommunicatorPtr& communicator, const TopicManagerPrx& admin,
671  const map<Ice::Identity, TopicManagerPrx>& managers) :
672  _communicator(communicator),
673  _defaultManager(admin),
674  _managers(managers)
675 {
676 #ifdef _WIN32
677  if (!windowsConsoleConverter)
678  {
679  windowsConsoleConverter = Ice::createWindowsStringConverter(GetConsoleOutputCP());
680  }
681 #endif
682 }
683 
684 void
685 Parser::exception(const Ice::Exception& ex, bool warn)
686 {
687  ostringstream os;
688  try
689  {
690  ex.ice_throw();
691  }
692  catch (const LinkExists& ex)
693  {
694  os << "link `" << ex.name << "' already exists";
695  }
696  catch (const NoSuchLink& ex)
697  {
698  os << "couldn't find link `" << ex.name << "'";
699  }
700  catch (const TopicExists& ex)
701  {
702  os << "topic `" << ex.name << "' exists";
703  }
704  catch (const NoSuchTopic& ex)
705  {
706  os << "couldn't find topic `" << ex.name << "'";
707  }
708  catch (const UnknownManagerException& ex)
709  {
710  os << "couldn't find IceStorm service `" << ex.name << "'";
711  }
712  catch (const IdentityParseException& ex)
713  {
714  os << "invalid identity `" << ex.str << "'";
715  }
716  catch (const Ice::LocalException& ex)
717  {
718  os << "couldn't reach IceStorm service:\n" << ex;
719  }
720  catch (const Ice::Exception& ex)
721  {
722  os << ex;
723  }
724 
725  if (warn)
726  {
727  warning(os.str());
728  }
729  else
730  {
731  error(os.str());
732  }
733 }
IceStorm
Definition: DBTypes.ice:22
IceStorm::Parser::getPrompt
const char * getPrompt()
Parser.h
IceStorm::Parser
Definition: Parser.h:52
IceStormInternal.h
IceStormElection::QueryInfo::coord
int coord
The nodes coordinator.
Definition: Election.ice:183
IceStormElection::QueryInfo
Definition: Election.ice:177
IceStormElection::QueryInfo::up
GroupInfoSeq up
The sequence of nodes in this nodes group.
Definition: Election.ice:195
c
constexpr T c
Definition: UnscentedKalmanFilterTest.cpp:43
IceStormElection::NodeStateElection
@ NodeStateElection
The node is electing a leader.
Definition: Election.ice:144
IceStorm::Parser::warning
void warning(const char *)
IceStormElection::QueryInfo::id
int id
The node id.
Definition: Election.ice:180
IceInternal::Handle< ::Ice::Communicator >
armarx::status
status
Definition: FiniteStateMachine.h:259
GfxTL::Identity
void Identity(MatrixXX< N, N, T > *a)
Definition: MatrixXX.h:523
IceStormElection::NodeStateInactive
@ NodeStateInactive
The node is inactive and awaiting an election.
Definition: Election.ice:142
IceStormElection::QueryInfo::max
int max
The highest priority node that this node has seen.
Definition: Election.ice:198
IceStormElection::QueryInfo::group
string group
The nodes group name.
Definition: Election.ice:186
armarx::flush
const LogSender::manipulator flush
Definition: LogSender.h:251
armarx::ProxyType::topic
@ topic
IceStormElection::NodeStateReorganization
@ NodeStateReorganization
The replica group is reorganizing.
Definition: Election.ice:146
IceInternal
Definition: InstrumentationI.h:16
IceStormElection::NodeStateNormal
@ NodeStateNormal
The replica group is active & replicating.
Definition: Election.ice:148
yyin
FILE * yyin
Definition: Scanner.cpp:342
q
#define q
yyparse
int yyparse()
Definition: Grammar.cpp:1187
Ice
Definition: DBTypes.cpp:64
IceStorm::parser
Parser * parser
Definition: Parser.cpp:33
std
Definition: Application.h:66
IceStormElection::QueryInfo::state
NodeState state
The node state.
Definition: Election.ice:192
IceUtil::Handle
Definition: forward_declarations.h:29
IceStormElection::NodeInfoSeq
::std::vector< ::IceStormElection::NodeInfo > NodeInfoSeq
A sequence of node info.
Definition: Election.h:857
IceInternal::ProxyHandle
Definition: ObjectPoseClientWidget.h:39
IceStorm::Parser::error
void error(const char *)
armarx::VariantType::Int
const VariantTypeId Int
Definition: Variant.h:916
yydebug
int yydebug
Definition: Grammar.cpp:844
min
T min(T t1, T t2)
Definition: gdiam.h:42
armarx::ctrlutil::s
double s(double t, double s0, double v0, double a0, double j)
Definition: CtrlUtil.h:33