summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2009-12-10 09:47:29 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2009-12-10 09:47:29 +0200
commitf8edfd22cb45b554a573d2722900196758e9e958 (patch)
treeb2c800c8793f08be287a67ed72517f9cc2831fda /cli
parenteddefea6ea39e64e9eb5adf74a279a230a63cf5b (diff)
Scanner-based parsing with support for element erasing
Also implement argv_file_scanner which provides support for reading command line arguments from the argv array as well as files specified with command line options. New examples: file. New tests: ctor, erase, file.
Diffstat (limited to 'cli')
-rw-r--r--cli/header.cxx17
-rw-r--r--cli/options.cli11
-rw-r--r--cli/options.cxx84
-rw-r--r--cli/options.hxx30
-rw-r--r--cli/options.ixx14
-rw-r--r--cli/runtime-header.cxx82
-rw-r--r--cli/runtime-inline.cxx63
-rw-r--r--cli/runtime-source.cxx228
-rw-r--r--cli/source.cxx49
9 files changed, 521 insertions, 57 deletions
diff --git a/cli/header.cxx b/cli/header.cxx
index 0cc9ede..012933d 100644
--- a/cli/header.cxx
+++ b/cli/header.cxx
@@ -73,30 +73,39 @@ namespace
//
string um ("::cli::unknown_mode");
- os << name << " (int argc," << endl
+ os << name << " (int& argc," << endl
<< "char** argv," << endl
+ << "bool erase = false," << endl
<< um << " option = " << um << "::fail," << endl
<< um << " argument = " << um << "::stop);"
<< endl;
os << name << " (int start," << endl
- << "int argc," << endl
+ << "int& argc," << endl
<< "char** argv," << endl
+ << "bool erase = false," << endl
<< um << " option = " << um << "::fail," << endl
<< um << " argument = " << um << "::stop);"
<< endl;
- os << name << " (int argc," << endl
+ os << name << " (int& argc," << endl
<< "char** argv," << endl
<< "int& end," << endl
+ << "bool erase = false," << endl
<< um << " option = " << um << "::fail," << endl
<< um << " argument = " << um << "::stop);"
<< endl;
os << name << " (int start," << endl
- << "int argc," << endl
+ << "int& argc," << endl
<< "char** argv," << endl
<< "int& end," << endl
+ << "bool erase = false," << endl
+ << um << " option = " << um << "::fail," << endl
+ << um << " argument = " << um << "::stop);"
+ << endl;
+
+ os << name << " (::cli::scanner&," << endl
<< um << " option = " << um << "::fail," << endl
<< um << " argument = " << um << "::stop);"
<< endl;
diff --git a/cli/options.cli b/cli/options.cli
index b9df64f..afd0f98 100644
--- a/cli/options.cli
+++ b/cli/options.cli
@@ -3,8 +3,8 @@
// copyright : Copyright (c) 2009 Code Synthesis Tools CC
// license : MIT; see accompanying LICENSE file
-// NOTE: Make sure you have a working CLI compiler around
-// before modifying this file.
+// NOTE: Make sure you have a working CLI compiler around before
+// modifying this file.
//
include <map>;
@@ -28,6 +28,13 @@ class options
"Generate option value modifiers in addition to accessors."
};
+ bool --generate-file-scanner
+ {
+ "Generate the \c{argv_file_scanner} implementation. This scanner is
+ capable of reading command line arguments from the \c{argv} array as
+ well as files specified with command line options."
+ };
+
bool --suppress-inline
{
"Generate all functions non-inline. By default simple functions are
diff --git a/cli/options.cxx b/cli/options.cxx
index 399069e..6d4ee87 100644
--- a/cli/options.cxx
+++ b/cli/options.cxx
@@ -132,7 +132,22 @@ namespace cli
next ()
{
if (i_ < argc_)
- return argv_[i_++];
+ {
+ const char* r (argv_[i_]);
+
+ if (erase_)
+ {
+ for (int i (i_ + 1); i < argc_; ++i)
+ argv_[i - 1] = argv_[i];
+
+ --argc_;
+ argv_[argc_] = 0;
+ }
+ else
+ ++i_;
+
+ return r;
+ }
else
throw eos_reached ();
}
@@ -141,7 +156,7 @@ namespace cli
skip ()
{
if (i_ < argc_)
- i_++;
+ ++i_;
else
throw eos_reached ();
}
@@ -289,14 +304,16 @@ namespace cli
//
options::
-options (int argc,
+options (int& argc,
char** argv,
+ bool erase,
::cli::unknown_mode opt,
::cli::unknown_mode arg)
: help_ (),
version_ (),
output_dir_ (),
generate_modifier_ (),
+ generate_file_scanner_ (),
suppress_inline_ (),
suppress_usage_ (),
long_usage_ (),
@@ -322,20 +339,22 @@ options (int argc,
guard_prefix_ (),
reserved_name_ ()
{
- ::cli::argv_scanner s (argc, argv);
+ ::cli::argv_scanner s (argc, argv, erase);
_parse (s, opt, arg);
}
options::
options (int start,
- int argc,
+ int& argc,
char** argv,
+ bool erase,
::cli::unknown_mode opt,
::cli::unknown_mode arg)
: help_ (),
version_ (),
output_dir_ (),
generate_modifier_ (),
+ generate_file_scanner_ (),
suppress_inline_ (),
suppress_usage_ (),
long_usage_ (),
@@ -361,20 +380,22 @@ options (int start,
guard_prefix_ (),
reserved_name_ ()
{
- ::cli::argv_scanner s (start, argc, argv);
+ ::cli::argv_scanner s (start, argc, argv, erase);
_parse (s, opt, arg);
}
options::
-options (int argc,
+options (int& argc,
char** argv,
int& end,
+ bool erase,
::cli::unknown_mode opt,
::cli::unknown_mode arg)
: help_ (),
version_ (),
output_dir_ (),
generate_modifier_ (),
+ generate_file_scanner_ (),
suppress_inline_ (),
suppress_usage_ (),
long_usage_ (),
@@ -400,22 +421,24 @@ options (int argc,
guard_prefix_ (),
reserved_name_ ()
{
- ::cli::argv_scanner s (argc, argv);
+ ::cli::argv_scanner s (argc, argv, erase);
_parse (s, opt, arg);
end = s.end ();
}
options::
options (int start,
- int argc,
+ int& argc,
char** argv,
int& end,
+ bool erase,
::cli::unknown_mode opt,
::cli::unknown_mode arg)
: help_ (),
version_ (),
output_dir_ (),
generate_modifier_ (),
+ generate_file_scanner_ (),
suppress_inline_ (),
suppress_usage_ (),
long_usage_ (),
@@ -441,11 +464,48 @@ options (int start,
guard_prefix_ (),
reserved_name_ ()
{
- ::cli::argv_scanner s (start, argc, argv);
+ ::cli::argv_scanner s (start, argc, argv, erase);
_parse (s, opt, arg);
end = s.end ();
}
+options::
+options (::cli::scanner& s,
+ ::cli::unknown_mode opt,
+ ::cli::unknown_mode arg)
+: help_ (),
+ version_ (),
+ output_dir_ (),
+ generate_modifier_ (),
+ generate_file_scanner_ (),
+ suppress_inline_ (),
+ suppress_usage_ (),
+ long_usage_ (),
+ option_length_ (0),
+ generate_cxx_ (),
+ generate_man_ (),
+ generate_html_ (),
+ man_prologue_ (),
+ man_epilogue_ (),
+ html_prologue_ (),
+ html_epilogue_ (),
+ class__ (),
+ stdout_ (),
+ hxx_suffix_ (".hxx"),
+ ixx_suffix_ (".ixx"),
+ cxx_suffix_ (".cxx"),
+ man_suffix_ (".1"),
+ html_suffix_ (".html"),
+ option_prefix_ ("-"),
+ option_separator_ ("--"),
+ include_with_brackets_ (),
+ include_prefix_ (),
+ guard_prefix_ (),
+ reserved_name_ ()
+{
+ _parse (s, opt, arg);
+}
+
void options::
print_usage (::std::ostream& os)
{
@@ -459,6 +519,8 @@ print_usage (::std::ostream& os)
os << "--generate-modifier Generate option value modifiers in addition to" << ::std::endl
<< " accessors." << ::std::endl;
+ os << "--generate-file-scanner Generate the 'argv_file_scanner' implementation." << ::std::endl;
+
os << "--suppress-inline Generate all functions non-inline." << ::std::endl;
os << "--suppress-usage Suppress the generation of the usage printing code." << ::std::endl;
@@ -547,6 +609,8 @@ struct _cli_options_map_init
&::cli::thunk< options, std::string, &options::output_dir_ >;
_cli_options_map_["--generate-modifier"] =
&::cli::thunk< options, bool, &options::generate_modifier_ >;
+ _cli_options_map_["--generate-file-scanner"] =
+ &::cli::thunk< options, bool, &options::generate_file_scanner_ >;
_cli_options_map_["--suppress-inline"] =
&::cli::thunk< options, bool, &options::suppress_inline_ >;
_cli_options_map_["--suppress-usage"] =
diff --git a/cli/options.hxx b/cli/options.hxx
index 2be8e91..54143b9 100644
--- a/cli/options.hxx
+++ b/cli/options.hxx
@@ -166,8 +166,8 @@ namespace cli
class argv_scanner: public scanner
{
public:
- argv_scanner (int argc, char** argv);
- argv_scanner (int start, int argc, char** argv);
+ argv_scanner (int& argc, char** argv, bool erase = false);
+ argv_scanner (int start, int& argc, char** argv, bool erase = false);
int
end () const;
@@ -184,9 +184,11 @@ namespace cli
virtual void
skip ();
- private:int i_;
- int argc_;
+ private:
+ int i_;
+ int& argc_;
char** argv_;
+ bool erase_;
};
}
@@ -202,27 +204,35 @@ class options
{
public:
- options (int argc,
+ options (int& argc,
char** argv,
+ bool erase = false,
::cli::unknown_mode option = ::cli::unknown_mode::fail,
::cli::unknown_mode argument = ::cli::unknown_mode::stop);
options (int start,
- int argc,
+ int& argc,
char** argv,
+ bool erase = false,
::cli::unknown_mode option = ::cli::unknown_mode::fail,
::cli::unknown_mode argument = ::cli::unknown_mode::stop);
- options (int argc,
+ options (int& argc,
char** argv,
int& end,
+ bool erase = false,
::cli::unknown_mode option = ::cli::unknown_mode::fail,
::cli::unknown_mode argument = ::cli::unknown_mode::stop);
options (int start,
- int argc,
+ int& argc,
char** argv,
int& end,
+ bool erase = false,
+ ::cli::unknown_mode option = ::cli::unknown_mode::fail,
+ ::cli::unknown_mode argument = ::cli::unknown_mode::stop);
+
+ options (::cli::scanner&,
::cli::unknown_mode option = ::cli::unknown_mode::fail,
::cli::unknown_mode argument = ::cli::unknown_mode::stop);
@@ -242,6 +252,9 @@ class options
generate_modifier () const;
const bool&
+ generate_file_scanner () const;
+
+ const bool&
suppress_inline () const;
const bool&
@@ -329,6 +342,7 @@ class options
bool version_;
std::string output_dir_;
bool generate_modifier_;
+ bool generate_file_scanner_;
bool suppress_inline_;
bool suppress_usage_;
bool long_usage_;
diff --git a/cli/options.ixx b/cli/options.ixx
index 6fcc80f..74d7b15 100644
--- a/cli/options.ixx
+++ b/cli/options.ixx
@@ -87,14 +87,14 @@ namespace cli
// argv_scanner
//
inline argv_scanner::
- argv_scanner (int argc, char** argv)
- : i_ (1), argc_ (argc), argv_ (argv)
+ argv_scanner (int& argc, char** argv, bool erase)
+ : i_ (1), argc_ (argc), argv_ (argv), erase_ (erase)
{
}
inline argv_scanner::
- argv_scanner (int start, int argc, char** argv)
- : i_ (start), argc_ (argc), argv_ (argv)
+ argv_scanner (int start, int& argc, char** argv, bool erase)
+ : i_ (start), argc_ (argc), argv_ (argv), erase_ (erase)
{
}
@@ -133,6 +133,12 @@ generate_modifier () const
}
inline const bool& options::
+generate_file_scanner () const
+{
+ return this->generate_file_scanner_;
+}
+
+inline const bool& options::
suppress_inline () const
{
return this->suppress_inline_;
diff --git a/cli/runtime-header.cxx b/cli/runtime-header.cxx
index cf3ebd3..5da33c0 100644
--- a/cli/runtime-header.cxx
+++ b/cli/runtime-header.cxx
@@ -12,6 +12,9 @@ generate_runtime_header (context& ctx)
{
ostream& os (ctx.os);
+ if (ctx.options.generate_file_scanner ())
+ os << "#include <deque>" << endl;
+
os << "#include <iosfwd>" << endl
<< "#include <string>" << endl
<< "#include <exception>" << endl
@@ -155,6 +158,30 @@ generate_runtime_header (context& ctx)
<< "what () const throw ();"
<< "};";
+ if (ctx.options.generate_file_scanner ())
+ {
+ os << "class file_io_failure: public exception"
+ << "{"
+ << "public:" << endl
+ << "virtual" << endl
+ << "~file_io_failure () throw ();"
+ << endl
+ << "file_io_failure (const std::string& file);"
+ << endl
+ << "const std::string&" << endl
+ << "file () const;"
+ << endl
+ << "virtual void" << endl
+ << "print (std::ostream&) const;"
+ << endl
+ << "virtual const char*" << endl
+ << "what () const throw ();"
+ << endl
+ << "private:" << endl
+ << "std::string file_;"
+ << "};";
+ }
+
// scanner
//
os << "class scanner"
@@ -181,8 +208,8 @@ generate_runtime_header (context& ctx)
os << "class argv_scanner: public scanner"
<< "{"
<< "public:" << endl
- << "argv_scanner (int argc, char** argv);"
- << "argv_scanner (int start, int argc, char** argv);"
+ << "argv_scanner (int& argc, char** argv, bool erase = false);"
+ << "argv_scanner (int start, int& argc, char** argv, bool erase = false);"
<< endl
<< "int" << endl
<< "end () const;"
@@ -199,11 +226,58 @@ generate_runtime_header (context& ctx)
<< "virtual void" << endl
<< "skip ();"
<< endl
- << "private:"
+ << "private:" << endl
<< "int i_;"
- << "int argc_;"
+ << "int& argc_;"
<< "char** argv_;"
+ << "bool erase_;"
<< "};";
+ // argv_file_scanner
+ //
+ if (ctx.options.generate_file_scanner ())
+ {
+ os << "class argv_file_scanner: public argv_scanner"
+ << "{"
+ << "public:" << endl
+ << "argv_file_scanner (int& argc," << endl
+ << "char** argv," << endl
+ << "const std::string& file_option," << endl
+ << "bool erase = false);"
+ << endl
+ << "argv_file_scanner (int start," << endl
+ << "int& argc," << endl
+ << "char** argv," << endl
+ << "const std::string& file_option," << endl
+ << "bool erase = false);"
+ << endl
+ << "virtual bool" << endl
+ << "more ();"
+ << endl
+ << "virtual const char*" << endl
+ << "peek ();"
+ << endl
+ << "virtual const char*" << endl
+ << "next ();"
+ << endl
+ << "virtual void" << endl
+ << "skip ();"
+ << endl
+ << "private:" << endl
+ << "void" << endl
+ << "load (const char* file);"
+ << endl
+ << "typedef argv_scanner base;"
+ << endl
+ << "const std::string option_;"
+ << "std::string hold_;"
+ << "std::deque<std::string> args_;";
+
+ if (!ctx.opt_sep.empty ())
+ os << "bool skip_;";
+
+ os << "};";
+ }
+
os << "}"; // namespace cli
}
diff --git a/cli/runtime-inline.cxx b/cli/runtime-inline.cxx
index d4ce3ec..c99739c 100644
--- a/cli/runtime-inline.cxx
+++ b/cli/runtime-inline.cxx
@@ -103,18 +103,36 @@ generate_runtime_inline (context& ctx)
<< "return value_;"
<< "}";
+ if (ctx.options.generate_file_scanner ())
+ {
+ os << "// file_io_failure" << endl
+ << "//" << endl
+
+ << inl << "file_io_failure::" << endl
+ << "file_io_failure (const std::string& file)" << endl
+ << ": file_ (file)"
+ << "{"
+ << "}"
+
+ << inl << "const std::string& file_io_failure::" << endl
+ << "file () const"
+ << "{"
+ << "return file_;"
+ << "}";
+ }
+
os << "// argv_scanner" << endl
<< "//" << endl;
os << inl << "argv_scanner::" << endl
- << "argv_scanner (int argc, char** argv)" << endl
- << ": i_ (1), argc_ (argc), argv_ (argv)"
+ << "argv_scanner (int& argc, char** argv, bool erase)" << endl
+ << ": i_ (1), argc_ (argc), argv_ (argv), erase_ (erase)"
<< "{"
<< "}";
os << inl << "argv_scanner::" << endl
- << "argv_scanner (int start, int argc, char** argv)" << endl
- << ": i_ (start), argc_ (argc), argv_ (argv)"
+ << "argv_scanner (int start, int& argc, char** argv, bool erase)" << endl
+ << ": i_ (start), argc_ (argc), argv_ (argv), erase_ (erase)"
<< "{"
<< "}";
@@ -124,5 +142,42 @@ generate_runtime_inline (context& ctx)
<< "return i_;"
<< "}";
+ // argv_file_scanner
+ //
+ if (ctx.options.generate_file_scanner ())
+ {
+ bool sep (!ctx.opt_sep.empty ());
+
+ os << "// argv_file_scanner" << endl
+ << "//" << endl;
+
+ os << inl << "argv_file_scanner::" << endl
+ << "argv_file_scanner (int& argc," << endl
+ << "char** argv," << endl
+ << "const std::string& option," << endl
+ << "bool erase)" << endl
+ << ": argv_scanner (argc, argv, erase)," << endl
+ << " option_ (option)";
+ if (sep)
+ os << "," << endl
+ << " skip_ (false)";
+ os << "{"
+ << "}";
+
+ os << inl << "argv_file_scanner::" << endl
+ << "argv_file_scanner (int start," << endl
+ << "int& argc," << endl
+ << "char** argv," << endl
+ << "const std::string& option," << endl
+ << "bool erase)" << endl
+ << ": argv_scanner (start, argc, argv, erase)," << endl
+ << " option_ (option)";
+ if (sep)
+ os << "," << endl
+ << " skip_ (false)";
+ os << "{"
+ << "}";
+ }
+
os << "}"; // namespace cli
}
diff --git a/cli/runtime-source.cxx b/cli/runtime-source.cxx
index 3003b6b..323b604 100644
--- a/cli/runtime-source.cxx
+++ b/cli/runtime-source.cxx
@@ -17,8 +17,13 @@ generate_runtime_source (context& ctx)
<< "#include <string>" << endl
<< "#include <vector>" << endl
<< "#include <ostream>" << endl
- << "#include <sstream>" << endl
- << endl;
+ << "#include <sstream>" << endl;
+
+ if (ctx.options.generate_file_scanner ())
+ os << "#include <cstring>" << endl
+ << "#include <fstream>" << endl;
+
+ os << endl;
os << "namespace cli"
<< "{";
@@ -31,11 +36,13 @@ generate_runtime_source (context& ctx)
<< "~unknown_option () throw ()"
<< "{"
<< "}"
+
<< "void unknown_option::" << endl
<< "print (std::ostream& os) const"
<< "{"
<< "os << \"unknown option '\" << option () << \"'\";"
<< "}"
+
<< "const char* unknown_option::" << endl
<< "what () const throw ()"
<< "{"
@@ -50,11 +57,13 @@ generate_runtime_source (context& ctx)
<< "~unknown_argument () throw ()"
<< "{"
<< "}"
+
<< "void unknown_argument::" << endl
<< "print (std::ostream& os) const"
<< "{"
<< "os << \"unknown argument '\" << argument () << \"'\";"
<< "}"
+
<< "const char* unknown_argument::" << endl
<< "what () const throw ()"
<< "{"
@@ -69,11 +78,13 @@ generate_runtime_source (context& ctx)
<< "~missing_value () throw ()"
<< "{"
<< "}"
+
<< "void missing_value::" << endl
<< "print (std::ostream& os) const"
<< "{"
<< "os << \"missing value for option '\" << option () << \"'\";"
<< "}"
+
<< "const char* missing_value::" << endl
<< "what () const throw ()"
<< "{"
@@ -88,12 +99,14 @@ generate_runtime_source (context& ctx)
<< "~invalid_value () throw ()"
<< "{"
<< "}"
+
<< "void invalid_value::" << endl
<< "print (std::ostream& os) const"
<< "{"
<< "os << \"invalid value '\" << value () << \"' for option '\"" << endl
<< " << option () << \"'\";"
<< "}"
+
<< "const char* invalid_value::" << endl
<< "what () const throw ()"
<< "{"
@@ -109,12 +122,37 @@ generate_runtime_source (context& ctx)
<< "{"
<< "os << what ();"
<< "}"
+
<< "const char* eos_reached::" << endl
<< "what () const throw ()"
<< "{"
<< "return \"end of argument stream reached\";"
<< "}";
+ // file_io_failure
+ //
+ if (ctx.options.generate_file_scanner ())
+ {
+ os << "// file_io_failure" << endl
+ << "//" << endl
+ << "file_io_failure::" << endl
+ << "~file_io_failure () throw ()"
+ << "{"
+ << "}"
+
+ << "void file_io_failure::" << endl
+ << "print (std::ostream& os) const"
+ << "{"
+ << "os << \"unable to open file '\" << file () << \"' or read failure\";"
+ << "}"
+
+ << "const char* file_io_failure::" << endl
+ << "what () const throw ()"
+ << "{"
+ << "return \"unable to open file or read failure\";"
+ << "}";
+ }
+
// scanner
//
os << "// scanner" << endl
@@ -147,8 +185,23 @@ generate_runtime_source (context& ctx)
<< "const char* argv_scanner::" << endl
<< "next ()"
<< "{"
- << "if (i_ < argc_)" << endl
- << "return argv_[i_++];"
+ << "if (i_ < argc_)"
+ << "{"
+ << "const char* r (argv_[i_]);"
+ << endl
+ << "if (erase_)"
+ << "{"
+ << "for (int i (i_ + 1); i < argc_; ++i)" << endl
+ << "argv_[i - 1] = argv_[i];"
+ << endl
+ << "--argc_;"
+ << "argv_[argc_] = 0;"
+ << "}"
+ << "else" << endl
+ << "++i_;"
+ << endl
+ << "return r;"
+ << "}"
<< "else" << endl
<< "throw eos_reached ();"
<< "}"
@@ -157,11 +210,176 @@ generate_runtime_source (context& ctx)
<< "skip ()"
<< "{"
<< "if (i_ < argc_)" << endl
- << "i_++;"
+ << "++i_;"
<< "else" << endl
<< "throw eos_reached ();"
<< "}";
+ // argv_file_scanner
+ //
+ if (ctx.options.generate_file_scanner ())
+ {
+ bool sep (!ctx.opt_sep.empty ());
+
+ os << "// argv_file_scanner" << endl
+ << "//" << endl
+
+ << "bool argv_file_scanner::" << endl
+ << "more ()"
+ << "{"
+ << "if (!args_.empty ())" << endl
+ << "return true;"
+ << endl
+ << "while (base::more ())"
+ << "{"
+ << "// See if the next argument is the file option." << endl
+ << "//" << endl
+ << "const char* a (base::peek ());"
+ << endl
+ << "if (" << (sep ? "!skip_ && " : "") << "a == option_)"
+ << "{"
+ << "base::next ();"
+ << endl
+ << "if (!base::more ())" << endl
+ << "throw missing_value (option_);"
+ << endl
+ << "load (base::next ());"
+ << endl
+ << "if (!args_.empty ())" << endl
+ << "return true;"
+ << "}"
+ << "else"
+ << "{";
+ if (sep)
+ os << "if (!skip_)" << endl
+ << "skip_ = (std::strcmp (a, \"" << ctx.opt_sep << "\") == 0);"
+ << endl;
+ os << "return true;"
+ << "}"
+ << "}" // while
+ << "return false;"
+ << "}"
+
+ << "const char* argv_file_scanner::" << endl
+ << "peek ()"
+ << "{"
+ << "if (!more ())" << endl
+ << "throw eos_reached ();"
+ << endl
+ << "return args_.empty () ? base::peek () : args_.front ().c_str ();"
+ << "}"
+
+ << "const char* argv_file_scanner::" << endl
+ << "next ()"
+ << "{"
+ << "if (!more ())" << endl
+ << "throw eos_reached ();"
+ << endl
+ << "if (args_.empty ())" << endl
+ << "return base::next ();"
+ << "else"
+ << "{"
+ << "hold_.swap (args_.front ());"
+ << "args_.pop_front ();"
+ << "return hold_.c_str ();"
+ << "}"
+ << "}"
+
+ << "void argv_file_scanner::" << endl
+ << "skip ()"
+ << "{"
+ << "if (!more ())" << endl
+ << "throw eos_reached ();"
+ << endl
+ << "if (args_.empty ())" << endl
+ << "return base::skip ();"
+ << "else" << endl
+ << "args_.pop_front ();"
+ << "}"
+
+ << "void argv_file_scanner::" << endl
+ << "load (const char* file)"
+ << "{"
+ << "using namespace std;"
+ << endl
+ << "ifstream is (file);"
+ << endl
+ << "if (!is.is_open ())" << endl
+ << "throw file_io_failure (file);"
+ << endl
+ << "while (!is.eof ())"
+ << "{"
+ << "string line;"
+ << "getline (is, line);"
+ << endl
+ << "if (is.fail () && !is.eof ())" << endl
+ << "throw file_io_failure (file);"
+ << endl
+ << "string::size_type n (line.size ());"
+ << endl
+ << "// Trim the line from leading and trailing whitespaces." << endl
+ << "//" << endl
+ << "if (n != 0)"
+ << "{"
+ << "const char* f (line.c_str ());"
+ << "const char* l (f + n);"
+ << endl
+ << "const char* of (f);"
+ << "while (f < l && (*f == ' ' || *f == '\\t' || *f == '\\r'))" << endl
+ << "++f;"
+ << endl
+ << "--l;"
+ << endl
+ << "const char* ol (l);"
+ << "while (l > f && (*l == ' ' || *l == '\\t' || *l == '\\r'))" << endl
+ << "--l;"
+ << endl
+ << "if (f != of || l != ol)" << endl
+ << "line = f <= l ? string (f, l - f + 1) : string ();"
+ << "}"
+ << "// Ignore empty lines, those that start with #." << endl
+ << "//" << endl
+ << "if (line.empty () || line[0] == '#')" << endl
+ << "continue;"
+ << endl
+ << "string::size_type p (line.find (' '));"
+ << endl
+ << "if (p == string::npos)"
+ << "{";
+ if (sep)
+ os << "if (!skip_)" << endl
+ << "skip_ = (line == \"" << ctx.opt_sep << "\");"
+ << endl;
+ os << "args_.push_back (line);"
+ << "}"
+ << "else"
+ << "{"
+ << "string s1 (line, 0, p);"
+ << endl
+ << "// Skip leading whitespaces in the argument." << endl
+ << "//" << endl
+ << "n = line.size ();"
+ << "for (++p; p < n; ++p)"
+ << "{"
+ << "char c (line[p]);"
+ << endl
+ << "if (c != ' ' && c != '\\t' && c != '\\r')" << endl
+ << "break;"
+ << "}"
+ << "string s2 (line, p);"
+ << endl
+ << "if (" << (sep ? "!skip_ && " : "") << "s1 == option_)" << endl
+ << "load (s2.c_str ());"
+ << "else"
+ << "{"
+ << "args_.push_back (s1);"
+ << "args_.push_back (s2);"
+ << "}"
+ << "}"
+ << "}" // while
+ << "}";
+ }
+
// parser class template & its specializations
//
os << "template <typename X>" << endl
diff --git a/cli/source.cxx b/cli/source.cxx
index 5f0b199..1c0b890 100644
--- a/cli/source.cxx
+++ b/cli/source.cxx
@@ -24,7 +24,11 @@ namespace
os << "," << endl
<< " ";
else
+ {
+ os << endl
+ << ": ";
comma_ = true;
+ }
os << emember (o);
@@ -356,75 +360,88 @@ namespace
string um ("::cli::unknown_mode");
os << name << "::" << endl
- << name << " (int argc," << endl
+ << name << " (int& argc," << endl
<< "char** argv," << endl
+ << "bool erase," << endl
<< um << " opt," << endl
- << um << " arg)" << endl
- << ": ";
+ << um << " arg)";
{
option_init init (*this);
traversal::names names_init (init);
names (c, names_init);
}
os << "{"
- << "::cli::argv_scanner s (argc, argv);"
+ << "::cli::argv_scanner s (argc, argv, erase);"
<< "_parse (s, opt, arg);"
<< "}";
os << name << "::" << endl
<< name << " (int start," << endl
- << "int argc," << endl
+ << "int& argc," << endl
<< "char** argv," << endl
+ << "bool erase," << endl
<< um << " opt," << endl
- << um << " arg)" << endl
- << ": ";
+ << um << " arg)";
{
option_init init (*this);
traversal::names names_init (init);
names (c, names_init);
}
os << "{"
- << "::cli::argv_scanner s (start, argc, argv);"
+ << "::cli::argv_scanner s (start, argc, argv, erase);"
<< "_parse (s, opt, arg);"
<< "}";
os << name << "::" << endl
- << name << " (int argc," << endl
+ << name << " (int& argc," << endl
<< "char** argv," << endl
<< "int& end," << endl
+ << "bool erase," << endl
<< um << " opt," << endl
- << um << " arg)" << endl
- << ": ";
+ << um << " arg)";
{
option_init init (*this);
traversal::names names_init (init);
names (c, names_init);
}
os << "{"
- << "::cli::argv_scanner s (argc, argv);"
+ << "::cli::argv_scanner s (argc, argv, erase);"
<< "_parse (s, opt, arg);"
<< "end = s.end ();"
<< "}";
os << name << "::" << endl
<< name << " (int start," << endl
- << "int argc," << endl
+ << "int& argc," << endl
<< "char** argv," << endl
<< "int& end," << endl
+ << "bool erase," << endl
<< um << " opt," << endl
- << um << " arg)" << endl
- << ": ";
+ << um << " arg)";
{
option_init init (*this);
traversal::names names_init (init);
names (c, names_init);
}
os << "{"
- << "::cli::argv_scanner s (start, argc, argv);"
+ << "::cli::argv_scanner s (start, argc, argv, erase);"
<< "_parse (s, opt, arg);"
<< "end = s.end ();"
<< "}";
+ os << name << "::" << endl
+ << name << " (::cli::scanner& s," << endl
+ << um << " opt," << endl
+ << um << " arg)";
+ {
+ option_init init (*this);
+ traversal::names names_init (init);
+ names (c, names_init);
+ }
+ os << "{"
+ << "_parse (s, opt, arg);"
+ << "}";
+
// usage
//
if (usage)