diff options
Diffstat (limited to 'cli')
-rw-r--r-- | cli/cli/runtime-header.cxx | 79 | ||||
-rw-r--r-- | cli/cli/runtime-inline.cxx | 63 | ||||
-rw-r--r-- | cli/cli/runtime-source.cxx | 75 |
3 files changed, 175 insertions, 42 deletions
diff --git a/cli/cli/runtime-header.cxx b/cli/cli/runtime-header.cxx index adf70dd..5bbe5c6 100644 --- a/cli/cli/runtime-header.cxx +++ b/cli/cli/runtime-header.cxx @@ -308,12 +308,20 @@ generate_runtime_header (context& ctx) // 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 + 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 + << "// The position() function returns a monotonically-increasing" << endl + << "// number which, if stored, can later be used to determine the"<< endl + << "// relative position of the argument returned by the following"<< endl + << "// call to next(). Note that if multiple scanners are used to" << endl + << "// extract arguments from multiple sources, then the end" << endl + << "// position of the previous scanner should be used as the" << endl + << "// start position of the next." << endl + << "//" << endl << "class scanner" << "{" << "public:" << endl @@ -331,6 +339,9 @@ generate_runtime_header (context& ctx) << endl << "virtual void" << endl << "skip () = 0;" + << endl + << "virtual std::size_t" << endl + << "position () = 0;" << "};"; // argv_scanner @@ -338,8 +349,16 @@ generate_runtime_header (context& ctx) os << "class argv_scanner: public scanner" << "{" << "public:" << endl - << "argv_scanner (int& argc, char** argv, bool erase = false);" - << "argv_scanner (int start, int& argc, char** argv, bool erase = false);" + << "argv_scanner (int& argc," << endl + << "char** argv," << endl + << "bool erase = false," << endl + << "std::size_t start_position = 0);" + << endl + << "argv_scanner (int start," << endl + << "int& argc," << endl + << "char** argv," << endl + << "bool erase = false," << endl + << "std::size_t start_position = 0);" << endl << "int" << endl << "end () const;" @@ -356,7 +375,11 @@ generate_runtime_header (context& ctx) << "virtual void" << endl << "skip ();" << endl - << "private:" << endl + << "virtual std::size_t" << endl + << "position ();" + << endl + << "protected:" << endl + << "std::size_t start_position_;" << "int i_;" << "int& argc_;" << "char** argv_;" @@ -370,14 +393,15 @@ generate_runtime_header (context& ctx) os << "class vector_scanner: public scanner" << "{" << "public:" << endl - << "vector_scanner (const std::vector<std::string>&, " << - "std::size_t start = 0);" + << "vector_scanner (const std::vector<std::string>&," << endl + << "std::size_t start = 0," << endl + << "std::size_t start_position = 0);" << endl << "std::size_t" << endl << "end () const;" << endl << "void" << endl - << "reset (std::size_t start = 0);" + << "reset (std::size_t start = 0, std::size_t start_position = 0);" << endl << "virtual bool" << endl << "more ();" @@ -391,7 +415,11 @@ generate_runtime_header (context& ctx) << "virtual void" << endl << "skip ();" << endl + << "virtual std::size_t" << endl + << "position ();" + << endl << "private:" << endl + << "std::size_t start_position_;" << "const std::vector<std::string>& v_;" << "std::size_t i_;" << "};"; @@ -407,16 +435,19 @@ generate_runtime_header (context& ctx) << "argv_file_scanner (int& argc," << endl << "char** argv," << endl << "const std::string& option," << endl - << "bool erase = false);" + << "bool erase = false," << endl + << "std::size_t start_position = 0);" << endl << "argv_file_scanner (int start," << endl << "int& argc," << endl << "char** argv," << endl << "const std::string& option," << endl - << "bool erase = false);" + << "bool erase = false," << endl + << "std::size_t start_position = 0);" << endl << "argv_file_scanner (const std::string& file," << endl - << "const std::string& option);" + << "const std::string& option," << endl + << "std::size_t start_position = 0);" << endl << "struct option_info" << "{" @@ -432,18 +463,21 @@ generate_runtime_header (context& ctx) << "char** argv," << endl << "const option_info* options," << endl << "std::size_t options_count," << endl - << "bool erase = false);" + << "bool erase = false," << endl + << "std::size_t start_position = 0);" << endl << "argv_file_scanner (int start," << endl << "int& argc," << endl << "char** argv," << endl << "const option_info* options," << endl << "std::size_t options_count," << endl - << "bool erase = false);" + << "bool erase = false," << endl + << "std::size_t start_position = 0);" << endl << "argv_file_scanner (const std::string& file," << endl << "const option_info* options = 0," << endl - << "std::size_t options_count = 0);" + << "std::size_t options_count = 0," << endl + << "std::size_t start_position = 0);" << endl << "virtual bool" << endl << "more ();" @@ -457,6 +491,9 @@ generate_runtime_header (context& ctx) << "virtual void" << endl << "skip ();" << endl + << "virtual std::size_t" << endl + << "position ();" + << endl << "// Return the file path if the peeked at argument came from a file and" << endl << "// the empty string otherwise. The reference is guaranteed to be valid" << endl << "// till the end of the scanner lifetime." << endl @@ -529,12 +566,18 @@ generate_runtime_header (context& ctx) << "virtual void" << endl << "skip ();" << endl + << "virtual std::size_t" << endl + << "position ();" + << endl << "// The group is only available after the call to next()" << endl << "// (and skip() -- in case one needs to make sure the group" << endl << "// was empty, or some such) and is only valid (and must be" << endl << "// handled) until the next call to any of the scanner" << endl << "// functions (including more())." << endl << "//" << endl + << "// Note also that argument positions within each group start"<< endl + << "// from 0." << endl + << "//" << endl << "scanner&" << endl << "group ();" << endl diff --git a/cli/cli/runtime-inline.cxx b/cli/cli/runtime-inline.cxx index 8f0e84c..e3dce1b 100644 --- a/cli/cli/runtime-inline.cxx +++ b/cli/cli/runtime-inline.cxx @@ -232,14 +232,29 @@ generate_runtime_inline (context& ctx) << "//" << endl; os << inl << "argv_scanner::" << endl - << "argv_scanner (int& argc, char** argv, bool erase)" << endl - << ": i_ (1), argc_ (argc), argv_ (argv), erase_ (erase)" + << "argv_scanner (int& argc," << endl + << "char** argv," << endl + << "bool erase," << endl + << "std::size_t sp)" << endl + << ": start_position_ (sp + 1)," << endl + << " i_ (1)," << endl + << " argc_ (argc)," << endl + << " argv_ (argv)," << endl + << " erase_ (erase)" << "{" << "}"; os << inl << "argv_scanner::" << endl - << "argv_scanner (int start, int& argc, char** argv, bool erase)" << endl - << ": i_ (start), argc_ (argc), argv_ (argv), erase_ (erase)" + << "argv_scanner (int start," << endl + << "int& argc," << endl + << "char** argv," << endl + << "bool erase," << endl + << "std::size_t sp)" << endl + << ": start_position_ (sp + static_cast<std::size_t> (start))," << endl + << " i_ (start)," << endl + << " argc_ (argc)," << endl + << " argv_ (argv)," << endl + << " erase_ (erase)" << "{" << "}"; @@ -257,9 +272,10 @@ generate_runtime_inline (context& ctx) << "//" << endl; os << inl << "vector_scanner::" << endl - << "vector_scanner (const std::vector<std::string>& v, " << - "std::size_t i)" << endl - << ": v_ (v), i_ (i)" + << "vector_scanner (const std::vector<std::string>& v," << endl + << "std::size_t i," << endl + << "std::size_t sp)" << endl + << ": start_position_ (sp), v_ (v), i_ (i)" << "{" << "}"; @@ -270,9 +286,10 @@ generate_runtime_inline (context& ctx) << "}"; os << inl << "void vector_scanner::" << endl - << "reset (std::size_t i)" + << "reset (std::size_t i, std::size_t sp)" << "{" << "i_ = i;" + << "start_position_ = sp;" << "}"; } @@ -289,8 +306,9 @@ generate_runtime_inline (context& ctx) << "argv_file_scanner (int& argc," << endl << "char** argv," << endl << "const std::string& option," << endl - << "bool erase)" << endl - << ": argv_scanner (argc, argv, erase)," << endl + << "bool erase," << endl + << "std::size_t sp)" << endl + << ": argv_scanner (argc, argv, erase, sp)," << endl << " option_ (option)," << endl << " options_ (&option_info_)," << endl << " options_count_ (1)," << endl @@ -308,8 +326,9 @@ generate_runtime_inline (context& ctx) << "int& argc," << endl << "char** argv," << endl << "const std::string& option," << endl - << "bool erase)" << endl - << ": argv_scanner (start, argc, argv, erase)," << endl + << "bool erase," << endl + << "std::size_t sp)" << endl + << ": argv_scanner (start, argc, argv, erase, sp)," << endl << " option_ (option)," << endl << " options_ (&option_info_)," << endl << " options_count_ (1)," << endl @@ -324,8 +343,9 @@ generate_runtime_inline (context& ctx) os << inl << "argv_file_scanner::" << endl << "argv_file_scanner (const std::string& file," << endl - << "const std::string& option)" << endl - << ": argv_scanner (0, zero_argc_, 0)," << endl + << "const std::string& option," << endl + << "std::size_t sp)" << endl + << ": argv_scanner (0, zero_argc_, 0, sp)," << endl << " option_ (option)," << endl << " options_ (&option_info_)," << endl << " options_count_ (1)," << endl @@ -345,8 +365,9 @@ generate_runtime_inline (context& ctx) << "char** argv," << endl << "const option_info* options," << endl << "std::size_t options_count," << endl - << "bool erase)" << endl - << ": argv_scanner (argc, argv, erase)," << endl + << "bool erase," << endl + << "std::size_t sp)" << endl + << ": argv_scanner (argc, argv, erase, sp)," << endl << " options_ (options)," << endl << " options_count_ (options_count)," << endl << " i_ (1)"; @@ -362,8 +383,9 @@ generate_runtime_inline (context& ctx) << "char** argv," << endl << "const option_info* options," << endl << "std::size_t options_count," << endl - << "bool erase)" << endl - << ": argv_scanner (start, argc, argv, erase)," << endl + << "bool erase," << endl + << "std::size_t sp)" << endl + << ": argv_scanner (start, argc, argv, erase, sp)," << endl << " options_ (options)," << endl << " options_count_ (options_count)," << endl << " i_ (1)"; @@ -376,8 +398,9 @@ generate_runtime_inline (context& ctx) os << inl << "argv_file_scanner::" << endl << "argv_file_scanner (const std::string& file," << endl << "const option_info* options," << endl - << "std::size_t options_count)" << endl - << ": argv_scanner (0, zero_argc_, 0)," << endl + << "std::size_t options_count," << endl + << "std::size_t sp)" << endl + << ": argv_scanner (0, zero_argc_, 0, sp)," << endl << " options_ (options)," << endl << " options_count_ (options_count)," << endl << " i_ (1)"; diff --git a/cli/cli/runtime-source.cxx b/cli/cli/runtime-source.cxx index 3864163..81eab4a 100644 --- a/cli/cli/runtime-source.cxx +++ b/cli/cli/runtime-source.cxx @@ -15,6 +15,7 @@ generate_runtime_source (context& ctx, bool complete) << "#include <set>" << endl << "#include <string>" << endl << "#include <vector>" << endl + << "#include <utility>" << endl // pair << "#include <ostream>" << endl << "#include <sstream>" << endl; @@ -259,6 +260,10 @@ generate_runtime_source (context& ctx, bool complete) // argv_scanner // + // Note that due to the erase logic we cannot just add i_ to + // start_position and so have to increment it instead. See also + // argv_file_scanner that continues with this logic. + // os << "// argv_scanner" << endl << "//" << endl @@ -295,6 +300,7 @@ generate_runtime_source (context& ctx, bool complete) << "else" << endl << "++i_;" << endl + << "++start_position_;" << "return r;" << "}" << "else" << endl @@ -304,10 +310,19 @@ generate_runtime_source (context& ctx, bool complete) << "void argv_scanner::" << endl << "skip ()" << "{" - << "if (i_ < argc_)" << endl + << "if (i_ < argc_)" + << "{" << "++i_;" + << "++start_position_;" + << "}" << "else" << endl << "throw eos_reached ();" + << "}" + + << "std::size_t argv_scanner::" << endl + << "position ()" + << "{" + << "return start_position_;" << "}"; // vector_scanner @@ -348,11 +363,19 @@ generate_runtime_source (context& ctx, bool complete) << "++i_;" << "else" << endl << "throw eos_reached ();" + << "}" + + << "std::size_t vector_scanner::" << endl + << "position ()" + << "{" + << "return start_position_ + i_;" << "}"; } // argv_file_scanner // + // Note that we continue incrementing start_position like argv_scanner. + // if (ctx.options.generate_file_scanner ()) { bool sep (!ctx.opt_sep.empty ()); @@ -486,6 +509,7 @@ generate_runtime_source (context& ctx, bool complete) << "{" << "hold_[i_ == 0 ? ++i_ : --i_].swap (args_.front ().value);" << "args_.pop_front ();" + << "++start_position_;" << "return hold_[i_].c_str ();" << "}" << "}" @@ -498,8 +522,11 @@ generate_runtime_source (context& ctx, bool complete) << endl << "if (args_.empty ())" << endl << "return base::skip ();" - << "else" << endl + << "else" + << "{" << "args_.pop_front ();" + << "++start_position_;" + << "}" << "}" << "const argv_file_scanner::option_info* argv_file_scanner::" << endl @@ -512,6 +539,12 @@ generate_runtime_source (context& ctx, bool complete) << "return 0;" << "}" + << "std::size_t argv_file_scanner::" << endl + << "position ()" + << "{" + << "return start_position_;" + << "}" + << "void argv_file_scanner::" << endl << "load (const std::string& file)" << "{" @@ -734,6 +767,12 @@ generate_runtime_source (context& ctx, bool complete) << "scan_group (skipped);" << "}" + << "std::size_t group_scanner::" << endl + << "position ()" + << "{" + << "return scan_.position ();" + << "}" + << "void group_scanner::" << endl << "scan_group (state st)" << "{" @@ -746,6 +785,11 @@ generate_runtime_source (context& ctx, bool complete) << "throw unexpected_group (arg_[i_], group_scan_.next ());" << "}" + // Note that while it may seem like a good idea to pass + // scan_.position() to reset() below, the trailing group positions + // will overlap with the argument's. So it seems best to start + // positions of each argument in a group from 0. + // << "if (state_ != peeked)" << "{" << "arg_[i_ == 0 ? ++i_ : --i_].clear ();" @@ -934,6 +978,28 @@ generate_runtime_source (context& ctx, bool complete) os << "};"; + // parser<std::pair<X, std::size_t>> + // + os << "template <typename X>" << endl + << "struct parser<std::pair<X, std::size_t> >" + << "{"; + + os << "static void" << endl + << "parse (std::pair<X, std::size_t>& x, " << (sp ? "bool& xs, " : "") << "scanner& s)" + << "{" + << "x.second = s.position ();" + << "parser<X>::parse (x.first, " << (sp ? "xs, " : "") << "s);" + << "}"; + + if (gen_merge) + os << "static void" << endl + << "merge (std::pair<X, std::size_t>& b, const std::pair<X, std::size_t>& a)" + << "{" + << "b = a;" + << "}"; + + os << "};"; + // parser<std::vector<X>> // os << "template <typename X>" << endl @@ -1001,6 +1067,7 @@ generate_runtime_source (context& ctx, bool complete) << endl << "if (s.more ())" << "{" + << "std::size_t pos (s.position ());" << "std::string ov (s.next ());" << "std::string::size_type p = ov.find ('=');" << endl @@ -1020,13 +1087,13 @@ generate_runtime_source (context& ctx, bool complete) os << "if (!kstr.empty ())" << "{" << "av[1] = const_cast<char*> (kstr.c_str ());" - << "argv_scanner s (0, ac, av);" + << "argv_scanner s (0, ac, av, false, pos);" << "parser<K>::parse (k, " << (sp ? "dummy, " : "") << "s);" << "}" << "if (!vstr.empty ())" << "{" << "av[1] = const_cast<char*> (vstr.c_str ());" - << "argv_scanner s (0, ac, av);" + << "argv_scanner s (0, ac, av, false, pos);" << "parser<V>::parse (v, " << (sp ? "dummy, " : "") << "s);" << "}" << "m[k] = v;" |