From 6520b63cb25580420e477cba2c776b2639cbf21b Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 21 Mar 2018 13:19:18 +0200 Subject: Guarantee validity of values returned by scanner for two arguments --- cli/options.cxx | 6 +++--- cli/options.hxx | 13 ++++++++++++- cli/options.ixx | 4 ++++ cli/runtime-header.cxx | 19 +++++++++++++++---- cli/runtime-inline.cxx | 12 ++++++++---- cli/runtime-source.cxx | 6 +++--- 6 files changed, 45 insertions(+), 15 deletions(-) diff --git a/cli/options.cxx b/cli/options.cxx index 43f271b..a59fb66 100644 --- a/cli/options.cxx +++ b/cli/options.cxx @@ -274,9 +274,9 @@ namespace cli return base::next (); else { - hold_.swap (args_.front ()); + hold_[i_ == 0 ? ++i_ : --i_].swap (args_.front ()); args_.pop_front (); - return hold_.c_str (); + return hold_[i_].c_str (); } } @@ -420,7 +420,7 @@ namespace cli { using namespace std; - string o (s.next ()); + const char* o (s.next ()); if (s.more ()) { diff --git a/cli/options.hxx b/cli/options.hxx index cc9d897..a3dffd2 100644 --- a/cli/options.hxx +++ b/cli/options.hxx @@ -224,6 +224,12 @@ namespace cli std::string argument_; }; + // Command line argument scanner interface. + // + // The values returned by next() are guaranteed to be valid + // for the two previous arguments up until a call to a third + // peek() or next(). + // class scanner { public: @@ -335,8 +341,13 @@ namespace cli const option_info* options_; std::size_t options_count_; - std::string hold_; std::deque args_; + + // Circular buffer of two arguments. + // + std::string hold_[2]; + std::size_t i_; + bool skip_; }; diff --git a/cli/options.ixx b/cli/options.ixx index df89810..5e60a8c 100644 --- a/cli/options.ixx +++ b/cli/options.ixx @@ -158,6 +158,7 @@ namespace cli option_ (option), options_ (&option_info_), options_count_ (1), + i_ (1), skip_ (false) { option_info_.option = option_.c_str (); @@ -174,6 +175,7 @@ namespace cli option_ (option), options_ (&option_info_), options_count_ (1), + i_ (1), skip_ (false) { option_info_.option = option_.c_str (); @@ -189,6 +191,7 @@ namespace cli : argv_scanner (argc, argv, erase), options_ (options), options_count_ (options_count), + i_ (1), skip_ (false) { } @@ -203,6 +206,7 @@ namespace cli : argv_scanner (start, argc, argv, erase), options_ (options), options_count_ (options_count), + i_ (1), skip_ (false) { } diff --git a/cli/runtime-header.cxx b/cli/runtime-header.cxx index 9861166..9f92262 100644 --- a/cli/runtime-header.cxx +++ b/cli/runtime-header.cxx @@ -246,7 +246,13 @@ generate_runtime_header (context& ctx) // scanner // - os << "class scanner" + os << "// Command line argument scanner interface." << endl + << "//" << endl + << "// The values returned by next() are guaranteed to be valid" << endl + << "// for the two previous arguments up until a call to a third" << endl + << "// peek() or next()." << endl + << "//" << endl + << "class scanner" << "{" << "public:" << endl << "virtual" << endl @@ -396,11 +402,16 @@ generate_runtime_header (context& ctx) << "const option_info* options_;" << "std::size_t options_count_;" << endl - << "std::string hold_;" - << "std::deque args_;"; + << "std::deque args_;" + << endl + << "// Circular buffer of two arguments." << endl + << "//" << endl + << "std::string hold_[2];" + << "std::size_t i_;"; if (!ctx.opt_sep.empty ()) - os << "bool skip_;"; + os << endl + << "bool skip_;"; os << "};"; } diff --git a/cli/runtime-inline.cxx b/cli/runtime-inline.cxx index abcf56a..6ae5c68 100644 --- a/cli/runtime-inline.cxx +++ b/cli/runtime-inline.cxx @@ -231,7 +231,8 @@ generate_runtime_inline (context& ctx) << ": argv_scanner (argc, argv, erase)," << endl << " option_ (option)," << endl << " options_ (&option_info_)," << endl - << " options_count_ (1)"; + << " options_count_ (1)," << endl + << " i_ (1)"; if (sep) os << "," << endl << " skip_ (false)"; @@ -249,7 +250,8 @@ generate_runtime_inline (context& ctx) << ": argv_scanner (start, argc, argv, erase)," << endl << " option_ (option)," << endl << " options_ (&option_info_)," << endl - << " options_count_ (1)"; + << " options_count_ (1)," << endl + << " i_ (1)"; if (sep) os << "," << endl << " skip_ (false)"; @@ -266,7 +268,8 @@ generate_runtime_inline (context& ctx) << "bool erase)" << endl << ": argv_scanner (argc, argv, erase)," << endl << " options_ (options)," << endl - << " options_count_ (options_count)"; + << " options_count_ (options_count)," << endl + << " i_ (1)"; if (sep) os << "," << endl << " skip_ (false)"; @@ -282,7 +285,8 @@ generate_runtime_inline (context& ctx) << "bool erase)" << endl << ": argv_scanner (start, argc, argv, erase)," << endl << " options_ (options)," << endl - << " options_count_ (options_count)"; + << " options_count_ (options_count)," << endl + << " i_ (1)"; if (sep) os << "," << endl << " skip_ (false)"; diff --git a/cli/runtime-source.cxx b/cli/runtime-source.cxx index 49c1bf2..e3be19e 100644 --- a/cli/runtime-source.cxx +++ b/cli/runtime-source.cxx @@ -356,9 +356,9 @@ generate_runtime_source (context& ctx, bool complete) << "return base::next ();" << "else" << "{" - << "hold_.swap (args_.front ());" + << "hold_[i_ == 0 ? ++i_ : --i_].swap (args_.front ());" << "args_.pop_front ();" - << "return hold_.c_str ();" + << "return hold_[i_].c_str ();" << "}" << "}" @@ -530,7 +530,7 @@ generate_runtime_source (context& ctx, bool complete) << "{" << "using namespace std;" << endl - << "string o (s.next ());" + << "const char* o (s.next ());" << endl << "if (s.more ())" << "{" -- cgit v1.1