SEvMgr Logo  0.2.0
C++ Simulation-Oriented Discrete Event Management Library
 All Classes Namespaces Files Functions Variables Typedefs Friends Macros Pages
sevmgr.cpp
Go to the documentation of this file.
1 
5 // STL
6 #include <cassert>
7 #include <iostream>
8 #include <sstream>
9 #include <fstream>
10 #include <string>
11 // Boost (Extended STL)
12 #include <boost/program_options.hpp>
13 #include <boost/tokenizer.hpp>
14 #include <boost/regex.hpp>
15 #include <boost/swap.hpp>
16 #include <boost/algorithm/string/case_conv.hpp>
17 // StdAir
18 #include <stdair/basic/BasLogParams.hpp>
19 #include <stdair/basic/BasDBParams.hpp>
20 #include <stdair/service/Logger.hpp>
21 // SEvMgr
24 // GNU Readline Wrapper
26 
27 // //////// Constants //////
31 const std::string K_SEVMGR_DEFAULT_LOG_FILENAME ("sevmgr.log");
32 
36 const int K_SEVMGR_EARLY_RETURN_STATUS = 99;
37 
42 typedef std::vector<std::string> TokenList_T;
43 
47 struct Command_T {
48  typedef enum {
49  NOP = 0,
50  QUIT,
51  HELP,
52  LIST,
53  DISPLAY,
54  SELECT,
55  NEXT,
56  RUN,
57  JSON_LIST,
58  JSON_DISPLAY,
59  LAST_VALUE
60  } Type_T;
61 };
62 
63 // ///////// Parsing of Options & Configuration /////////
64 // A helper function to simplify the main part.
65 template<class T> std::ostream& operator<< (std::ostream& os,
66  const std::vector<T>& v) {
67  std::copy (v.begin(), v.end(), std::ostream_iterator<T> (std::cout, " "));
68  return os;
69 }
70 
74 int readConfiguration (int argc, char* argv[], std::string& ioLogFilename) {
75  // Declare a group of options that will be allowed only on command line
76  boost::program_options::options_description generic ("Generic options");
77  generic.add_options()
78  ("prefix", "print installation prefix")
79  ("version,v", "print version string")
80  ("help,h", "produce help message");
81 
82  // Declare a group of options that will be allowed both on command
83  // line and in config file
84 
85  boost::program_options::options_description config ("Configuration");
86  config.add_options()
87  ("log,l",
88  boost::program_options::value< std::string >(&ioLogFilename)->default_value(K_SEVMGR_DEFAULT_LOG_FILENAME),
89  "Filename for the logs")
90  ;
91 
92  // Hidden options, will be allowed both on command line and
93  // in config file, but will not be shown to the user.
94  boost::program_options::options_description hidden ("Hidden options");
95  hidden.add_options()
96  ("copyright",
97  boost::program_options::value< std::vector<std::string> >(),
98  "Show the copyright (license)");
99 
100  boost::program_options::options_description cmdline_options;
101  cmdline_options.add(generic).add(config).add(hidden);
102 
103  boost::program_options::options_description config_file_options;
104  config_file_options.add(config).add(hidden);
105  boost::program_options::options_description visible ("Allowed options");
106  visible.add(generic).add(config);
107 
108  boost::program_options::positional_options_description p;
109  p.add ("copyright", -1);
110 
111  boost::program_options::variables_map vm;
112  boost::program_options::
113  store (boost::program_options::command_line_parser (argc, argv).
114  options (cmdline_options).positional(p).run(), vm);
115 
116  std::ifstream ifs ("sevmgr.cfg");
117  boost::program_options::store (parse_config_file (ifs, config_file_options),
118  vm);
119  boost::program_options::notify (vm);
120 
121  if (vm.count ("help")) {
122  std::cout << visible << std::endl;
124  }
125 
126  if (vm.count ("version")) {
127  std::cout << PACKAGE_NAME << ", version " << PACKAGE_VERSION << std::endl;
129  }
130 
131  if (vm.count ("prefix")) {
132  std::cout << "Installation prefix: " << PREFIXDIR << std::endl;
134  }
135 
136  if (vm.count ("log")) {
137  ioLogFilename = vm["log"].as< std::string >();
138  std::cout << "Log filename is: " << ioLogFilename << std::endl;
139  }
140 
141  return 0;
142 }
143 
144 // //////////////////////////////////////////////////////////////////
145 void initReadline (swift::SReadline& ioInputReader) {
146 
147  // Prepare the list of my own completers
148  std::vector<std::string> Completers;
149 
150  // The following is supported:
151  // - "identifiers"
152  // - special identifier %file - means to perform a file name completion
153  Completers.push_back ("help");
154  Completers.push_back ("list %airline_code %flight_number");
155  Completers.push_back ("select %airline_code %flight_number %flight_date");
156  Completers.push_back ("display");
157  Completers.push_back ("next");
158  Completers.push_back ("run");
159  Completers.push_back ("quit");
160 
161 
162  // Now register the completers.
163  // Actually it is possible to re-register another set at any time
164  ioInputReader.RegisterCompletions (Completers);
165 }
166 
167 // //////////////////////////////////////////////////////////////////
168 Command_T::Type_T extractCommand (TokenList_T& ioTokenList) {
169  Command_T::Type_T oCommandType = Command_T::LAST_VALUE;
170 
171  // Interpret the user input
172  if (ioTokenList.empty() == false) {
173  TokenList_T::iterator itTok = ioTokenList.begin();
174  std::string lCommand (*itTok);
175  boost::algorithm::to_lower (lCommand);
176 
177  if (lCommand == "help") {
178  oCommandType = Command_T::HELP;
179 
180  } else if (lCommand == "list") {
181  oCommandType = Command_T::LIST;
182 
183  } else if (lCommand == "display") {
184  oCommandType = Command_T::DISPLAY;
185 
186  } else if (lCommand == "select") {
187  oCommandType = Command_T::SELECT;
188 
189  } else if (lCommand == "next") {
190  oCommandType = Command_T::NEXT;
191 
192  } else if (lCommand == "run") {
193  oCommandType = Command_T::RUN;
194 
195  } else if (lCommand == "json_list") {
196  oCommandType = Command_T::JSON_LIST;
197 
198  } else if (lCommand == "json_display") {
199  oCommandType = Command_T::JSON_DISPLAY;
200 
201  } else if (lCommand == "quit") {
202  oCommandType = Command_T::QUIT;
203  }
204 
205  // Remove the first token (the command), as the corresponding information
206  // has been extracted in the form of the returned command type enumeration
207  ioTokenList.erase (itTok);
208 
209  } else {
210  oCommandType = Command_T::NOP;
211  }
212 
213  return oCommandType;
214 }
215 
216 // //////////////////////////////////////////////////////////////////
217 void parseFlightKey (const TokenList_T& iTokenList,
218  stdair::AirlineCode_T& ioAirlineCode,
219  stdair::FlightNumber_T& ioFlightNumber) {
220  // Interpret the user input
221  if (iTokenList.empty() == false) {
222 
223  // Read the airline code
224  TokenList_T::const_iterator itTok = iTokenList.begin();
225  if (itTok->empty() == false) {
226  ioAirlineCode = *itTok;
227  boost::algorithm::to_upper (ioAirlineCode);
228  }
229 
230  // Read the flight-number
231  ++itTok;
232  if (itTok != iTokenList.end()) {
233 
234  if (itTok->empty() == false) {
235  try {
236 
237  ioFlightNumber = boost::lexical_cast<stdair::FlightNumber_T> (*itTok);
238 
239  } catch (boost::bad_lexical_cast& eCast) {
240  std::cerr << "The flight number ('" << *itTok
241  << "') cannot be understood. "
242  << "The default value (all) is kept."
243  << std::endl;
244  return;
245  }
246  }
247 
248  } else {
249  return;
250  }
251  }
252 }
253 
254 // //////////////////////////////////////////////////////////////////
255 void parseFlightDateKey (const TokenList_T& iTokenList,
256  stdair::AirlineCode_T& ioAirlineCode,
257  stdair::FlightNumber_T& ioFlightNumber,
258  stdair::Date_T& ioDepartureDate) {
259  //
260  const std::string kMonthStr[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
261  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
262  //
263  unsigned short ioDepartureDateYear = ioDepartureDate.year();
264  unsigned short ioDepartureDateMonth = ioDepartureDate.month();
265  std::string ioDepartureDateMonthStr = kMonthStr[ioDepartureDateMonth-1];
266  unsigned short ioDepartureDateDay = ioDepartureDate.day();
267 
268  // Interpret the user input
269  if (iTokenList.empty() == false) {
270 
271  // Read the airline code
272  TokenList_T::const_iterator itTok = iTokenList.begin();
273  if (itTok->empty() == false) {
274  ioAirlineCode = *itTok;
275  boost::algorithm::to_upper (ioAirlineCode);
276  }
277 
278  // Read the flight-number
279  ++itTok;
280  if (itTok != iTokenList.end()) {
281 
282  if (itTok->empty() == false) {
283  try {
284 
285  ioFlightNumber = boost::lexical_cast<stdair::FlightNumber_T> (*itTok);
286 
287  } catch (boost::bad_lexical_cast& eCast) {
288  std::cerr << "The flight number ('" << *itTok
289  << "') cannot be understood. "
290  << "The default value (all) is kept."
291  << std::endl;
292  return;
293  }
294  }
295 
296  } else {
297  return;
298  }
299 
300  // Read the year for the departure date
301  ++itTok;
302  if (itTok != iTokenList.end()) {
303 
304  if (itTok->empty() == false) {
305  try {
306 
307  ioDepartureDateYear = boost::lexical_cast<unsigned short> (*itTok);
308  if (ioDepartureDateYear < 100) {
309  ioDepartureDateYear += 2000;
310  }
311 
312  } catch (boost::bad_lexical_cast& eCast) {
313  std::cerr << "The year of the flight departure date ('" << *itTok
314  << "') cannot be understood. The default value ("
315  << ioDepartureDateYear << ") is kept. " << std::endl;
316  return;
317  }
318  }
319 
320  } else {
321  return;
322  }
323 
324  // Read the month for the departure date
325  ++itTok;
326  if (itTok != iTokenList.end()) {
327 
328  if (itTok->empty() == false) {
329  try {
330 
331  const boost::regex lMonthRegex ("^(\\d{1,2})$");
332  const bool isMonthANumber = regex_match (*itTok, lMonthRegex);
333 
334  if (isMonthANumber == true) {
335  const unsigned short lMonth =
336  boost::lexical_cast<unsigned short> (*itTok);
337  if (lMonth > 12) {
338  throw boost::bad_lexical_cast();
339  }
340  ioDepartureDateMonthStr = kMonthStr[lMonth-1];
341 
342  } else {
343  const std::string lMonthStr (*itTok);
344  if (lMonthStr.size() < 3) {
345  throw boost::bad_lexical_cast();
346  }
347  std::string lMonthStr1 (lMonthStr.substr (0, 1));
348  boost::algorithm::to_upper (lMonthStr1);
349  std::string lMonthStr23 (lMonthStr.substr (1, 2));
350  boost::algorithm::to_lower (lMonthStr23);
351  ioDepartureDateMonthStr = lMonthStr1 + lMonthStr23;
352  }
353 
354  } catch (boost::bad_lexical_cast& eCast) {
355  std::cerr << "The month of the flight departure date ('" << *itTok
356  << "') cannot be understood. The default value ("
357  << ioDepartureDateMonthStr << ") is kept. " << std::endl;
358  return;
359  }
360  }
361 
362  } else {
363  return;
364  }
365 
366  // Read the day for the departure date
367  ++itTok;
368  if (itTok != iTokenList.end()) {
369 
370  if (itTok->empty() == false) {
371  try {
372 
373  ioDepartureDateDay = boost::lexical_cast<unsigned short> (*itTok);
374 
375  } catch (boost::bad_lexical_cast& eCast) {
376  std::cerr << "The day of the flight departure date ('" << *itTok
377  << "') cannot be understood. The default value ("
378  << ioDepartureDateDay << ") is kept. " << std::endl;
379  return;
380  }
381  }
382 
383  } else {
384  return;
385  }
386 
387  // Re-compose the departure date
388  std::ostringstream lDepartureDateStr;
389  lDepartureDateStr << ioDepartureDateYear << "-" << ioDepartureDateMonthStr
390  << "-" << ioDepartureDateDay;
391 
392  try {
393 
394  ioDepartureDate =
395  boost::gregorian::from_simple_string (lDepartureDateStr.str());
396 
397  } catch (boost::gregorian::bad_month& eCast) {
398  std::cerr << "The flight departure date ('" << lDepartureDateStr.str()
399  << "') cannot be understood. The default value ("
400  << ioDepartureDate << ") is kept. " << std::endl;
401  return;
402  }
403 
404  }
405 }
406 
407 // //////////////////////////////////////////////////////////////////
408 void parseBookingClassKey (const TokenList_T& iTokenList,
409  stdair::ClassCode_T& ioBookingClass,
410  stdair::PartySize_T& ioPartySize,
411  stdair::AirportCode_T& ioOrigin,
412  stdair::AirportCode_T& ioDestination) {
413  // Interpret the user input
414  if (iTokenList.empty() == false) {
415 
416  // Read the booking class
417  TokenList_T::const_iterator itTok = iTokenList.begin();
418  if (itTok->empty() == false) {
419  ioBookingClass = *itTok;
420  boost::algorithm::to_upper (ioBookingClass);
421  }
422 
423  // Read the party size
424  ++itTok;
425  if (itTok != iTokenList.end()) {
426 
427  if (itTok->empty() == false) {
428  try {
429 
430  ioPartySize = boost::lexical_cast<stdair::PartySize_T> (*itTok);
431 
432  } catch (boost::bad_lexical_cast& eCast) {
433  std::cerr << "The party size ('" << *itTok
434  << "') cannot be understood. The default value ("
435  << ioPartySize << ") is kept." << std::endl;
436  return;
437  }
438  }
439 
440  } else {
441  return;
442  }
443 
444  // Read the origin
445  ++itTok;
446  if (itTok != iTokenList.end()) {
447 
448  if (itTok->empty() == false) {
449  ioOrigin = *itTok;
450  boost::algorithm::to_upper (ioOrigin);
451  }
452 
453  } else {
454  return;
455  }
456 
457  // Read the destination
458  ++itTok;
459  if (itTok != iTokenList.end()) {
460 
461  if (itTok->empty() == false) {
462  ioDestination = *itTok;
463  boost::algorithm::to_upper (ioDestination);
464  }
465 
466  } else {
467  return;
468  }
469  }
470 }
471 
472 // /////////////////////////////////////////////////////////
473 std::string toString (const TokenList_T& iTokenList) {
474  std::ostringstream oStr;
475 
476  // Re-create the string with all the tokens, trimmed by read-line
477  unsigned short idx = 0;
478  for (TokenList_T::const_iterator itTok = iTokenList.begin();
479  itTok != iTokenList.end(); ++itTok, ++idx) {
480  if (idx != 0) {
481  oStr << " ";
482  }
483  oStr << *itTok;
484  }
485 
486  return oStr.str();
487 }
488 
489 // /////////////////////////////////////////////////////////
490 TokenList_T extractTokenList (const TokenList_T& iTokenList,
491  const std::string& iRegularExpression) {
492  TokenList_T oTokenList;
493 
494  // Re-create the string with all the tokens (which had been trimmed
495  // by read-line)
496  const std::string lFullLine = toString (iTokenList);
497 
498  // See the caller for the regular expression
499  boost::regex expression (iRegularExpression);
500 
501  std::string::const_iterator start = lFullLine.begin();
502  std::string::const_iterator end = lFullLine.end();
503 
504  boost::match_results<std::string::const_iterator> what;
505  boost::match_flag_type flags = boost::match_default | boost::format_sed;
506  regex_search (start, end, what, expression, flags);
507 
508  // Put the matched strings in the list of tokens to be returned back
509  // to the caller
510  const unsigned short lMatchSetSize = what.size();
511  for (unsigned short matchIdx = 1; matchIdx != lMatchSetSize; ++matchIdx) {
512  const std::string lMatchedString (std::string (what[matchIdx].first,
513  what[matchIdx].second));
514  //if (lMatchedString.empty() == false) {
515  oTokenList.push_back (lMatchedString);
516  //}
517  }
518 
519  // DEBUG
520  // std::cout << "After (token list): " << oTokenList << std::endl;
521 
522  return oTokenList;
523 }
524 
525 // /////////////////////////////////////////////////////////
526 TokenList_T extractTokenListForFlight (const TokenList_T& iTokenList) {
533  const std::string lRegEx ("^([[:alpha:]]{2,3})?"
534  "[[:space:]]*([[:digit:]]{1,4})?$");
535 
536  //
537  const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx);
538  return oTokenList;
539 }
540 
541 // /////////////////////////////////////////////////////////
542 TokenList_T extractTokenListForFlightDate (const TokenList_T& iTokenList) {
553  const std::string lRegEx("^([[:alpha:]]{2,3})?"
554  "[[:space:]]*([[:digit:]]{1,4})?"
555  "[/ ]*"
556  "([[:digit:]]{2,4})?[/-]?[[:space:]]*"
557  "([[:alpha:]]{3}|[[:digit:]]{1,2})?[/-]?[[:space:]]*"
558  "([[:digit:]]{1,2})?$");
559 
560  //
561  const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx);
562  return oTokenList;
563 }
564 
565 // /////////////////////////////////////////////////////////
566 TokenList_T extractTokenListForClass (const TokenList_T& iTokenList) {
575  const std::string lRegEx ("^([[:alpha:]])?"
576  "[[:space:]]*([[:digit:]]{1,3})?"
577  "[[:space:]]*([[:alpha:]]{3})?"
578  "[[:space:]]*([[:alpha:]]{3})?$");
579 
580  //
581  const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx);
582  return oTokenList;
583 }
584 
585 
586 // ///////// M A I N ////////////
587 int main (int argc, char* argv[]) {
588 
589  // Readline history
590  const unsigned int lHistorySize (100);
591  const std::string lHistoryFilename ("sevmgr.hist");
592  const std::string lHistoryBackupFilename ("sevmgr.hist.bak");
593 
594  // Default parameters for the interactive session
595  stdair::AirlineCode_T lLastInteractiveAirlineCode;
596  stdair::FlightNumber_T lLastInteractiveFlightNumber;
597  stdair::Date_T lLastInteractiveDate;
598  stdair::AirlineCode_T lInteractiveAirlineCode;
599  stdair::FlightNumber_T lInteractiveFlightNumber;
600  stdair::Date_T lInteractiveDate;
601  stdair::AirportCode_T lInteractiveOrigin;
602  stdair::AirportCode_T lInteractiveDestination;
603  stdair::ClassCode_T lInteractiveBookingClass;
604 
605  // Parameters for the sale
606  std::string lSegmentDateKey;
607 
608  // Output log File
609  stdair::Filename_T lLogFilename;
610 
611  // Call the command-line option parser
612  const int lOptionParserStatus = readConfiguration (argc, argv, lLogFilename);
613 
614  if (lOptionParserStatus == K_SEVMGR_EARLY_RETURN_STATUS) {
615  return 0;
616  }
617 
618  // Set the log parameters
619  std::ofstream logOutputFile;
620  // Open and clean the log outputfile
621  logOutputFile.open (lLogFilename.c_str());
622  logOutputFile.clear();
623 
624  // Initialise the inventory service
625  const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile);
626  SEVMGR::SEVMGR_Service sevmgrService (lLogParams);
627 
628  // DEBUG
629  STDAIR_LOG_DEBUG ("Welcome to SEvMgr");
630 
631  // Build the sample BOM tree for RMOL
632  sevmgrService.buildSampleBom();
633 
634  // Update the default parameters for the following interactive session
635  lInteractiveAirlineCode = "BA";
636  lInteractiveFlightNumber = 9;
637  lInteractiveDate = stdair::Date_T (2011, 06, 10);
638  lInteractiveBookingClass = "Q";
639  lInteractiveOrigin = "LHR";
640  lInteractiveDestination = "SYD";
641 
642  // Save the last state
643  lLastInteractiveAirlineCode = lInteractiveAirlineCode;
644  lLastInteractiveFlightNumber = lInteractiveFlightNumber;
645  lLastInteractiveDate = lInteractiveDate;
646 
647  // DEBUG
648  STDAIR_LOG_DEBUG ("====================================================");
649  STDAIR_LOG_DEBUG ("= Beginning of the interactive session =");
650  STDAIR_LOG_DEBUG ("====================================================");
651  STDAIR_LOG_DEBUG ("Last saved state: " << lLastInteractiveAirlineCode
652  << lLastInteractiveFlightNumber << " / "
653  << lLastInteractiveDate);
654 
655  // Initialise the GNU readline wrapper
656  swift::SReadline lReader (lHistoryFilename, lHistorySize);
657  initReadline (lReader);
658 
659  // Now we can ask user for a line
660  std::string lUserInput;
661  bool EndOfInput (false);
662  Command_T::Type_T lCommandType (Command_T::NOP);
663 
664  while (lCommandType != Command_T::QUIT && EndOfInput == false) {
665  // Prompt
666  std::ostringstream oPromptStr;
667  oPromptStr << "sevmgr "
668  << lInteractiveAirlineCode << lInteractiveFlightNumber
669  << " / " << lInteractiveDate
670  << "> ";
671  // Call read-line, which will fill the list of tokens
672  TokenList_T lTokenListByReadline;
673  lUserInput = lReader.GetLine (oPromptStr.str(), lTokenListByReadline,
674  EndOfInput);
675 
676  // The history can be saved to an arbitrary file at any time
677  lReader.SaveHistory (lHistoryBackupFilename);
678 
679  // The end-of-input typically corresponds to a CTRL-D typed by the user
680  if (EndOfInput) {
681  std::cout << std::endl;
682  break;
683  }
684 
685  // Interpret the user input
686  lCommandType = extractCommand (lTokenListByReadline);
687 
688  switch (lCommandType) {
689 
690  // ////////////////////////////// Help ////////////////////////
691  case Command_T::HELP: {
692  std::cout << std::endl;
693  std::cout << "Commands: " << std::endl;
694  std::cout << " help" << "\t\t" << "Display this help" << std::endl;
695  std::cout << " quit" << "\t\t" << "Quit the application" << std::endl;
696  std::cout << " list" << "\t\t" << "List events" << std::endl;
697  std::cout << " select" << "\t\t"
698  << "Select an event to become the current one" << std::endl;
699  std::cout << " display" << "\t"
700  << "Display the current event" << std::endl;
701  std::cout << " next" << "\t\t"
702  << "Play the current event and pop the next one from the queue"
703  << std::endl;
704  std::cout << " run" << "\t\t"
705  << "Play all the events until the next break-point, if any"
706  << std::endl;
707  std::cout << " \nDebug Commands" << std::endl;
708  std::cout << " json_list" << "\t"
709  << "List events in a JSON format"
710  << std::endl;
711  std::cout << " json_display" << "\t"
712  << "Display the current event in a JSON format"
713  << std::endl;
714  std::cout << std::endl;
715  break;
716  }
717 
718  // ////////////////////////////// Quit ////////////////////////
719  case Command_T::QUIT: {
720  break;
721  }
722 
723  // ////////////////////////////// List /////////////////////////
724  case Command_T::LIST: {
725  //
726  std::cout << "List" << std::endl;
727 
728  //
729  break;
730  }
731 
732  // ////////////////////////////// Select ////////////////////////
733  case Command_T::SELECT: {
734  //
735  std::cout << "Select" << std::endl;
736 
737  //
738  break;
739  }
740 
741  // ////////////////////////////// Display ////////////////////////
742  case Command_T::DISPLAY: {
743  //
744  std::cout << "Display" << std::endl;
745 
746  //
747  break;
748  }
749 
750  // ////////////////////////////// Next ////////////////////////
751  case Command_T::NEXT: {
752  //
753  std::cout << "Next" << std::endl;
754 
755  //
756  break;
757  }
758 
759  // ////////////////////////////// Run ////////////////////////
760  case Command_T::RUN: {
761  //
762  std::cout << "Run" << std::endl;
763 
764  //
765  break;
766  }
767 
768  // ////////////////////////////// JSon List ////////////////////////
769 
770  case Command_T::JSON_LIST: {
771  //
772  std::cout << "JSON List" << std::endl;
773 
774  //
775  break;
776  }
777 
778  // ////////////////////////////// JSon Display ////////////////////////
779 
780  case Command_T::JSON_DISPLAY: {
781  //
782  std::cout << "JSON Display" << std::endl;
783 
784  //
785  break;
786  }
787 
788  // /////////////////////////// Default / No value ///////////////////////
789  case Command_T::NOP: {
790  break;
791  }
792 
793  case Command_T::LAST_VALUE:
794  default: {
795  // DEBUG
796  std::ostringstream oStr;
797  oStr << "That command is not yet understood: '" << lUserInput
798  << "' => " << lTokenListByReadline;
799  STDAIR_LOG_DEBUG (oStr.str());
800  std::cout << oStr.str() << std::endl;
801  }
802  }
803  }
804 
805  // DEBUG
806  STDAIR_LOG_DEBUG ("End of the session. Exiting.");
807  std::cout << "End of the session. Exiting." << std::endl;
808 
809  // Close the Log outputFile
810  logOutputFile.close();
811 
812  /*
813  Note: as that program is not intended to be run on a server in
814  production, it is better not to catch the exceptions. When it
815  happens (that an exception is throwned), that way we get the
816  call stack.
817  */
818 
819  return 0;
820 }