aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2018-04-13 11:32:28 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2018-04-13 11:32:28 +0200
commit030c9ed901dc38b7f6cafa6250435d67f19cfe8b (patch)
tree5302777895010664b53ff06ab2aa386ae4544652
parent8c48171d626d3a84d5ddb99ba04a1de646221005 (diff)
Regenerate option parser (adds support for combined flags and values)
-rw-r--r--build2/b-options.cxx194
1 files changed, 155 insertions, 39 deletions
diff --git a/build2/b-options.cxx b/build2/b-options.cxx
index 231299f..3cfb708 100644
--- a/build2/b-options.cxx
+++ b/build2/b-options.cxx
@@ -224,24 +224,45 @@ namespace build2
// See if the next argument is the file option.
//
const char* a (base::peek ());
- const option_info* oi;
+ const option_info* oi = 0;
+ const char* ov = 0;
- if (!skip_ && (oi = find (a)))
+ if (!skip_)
{
- base::next ();
+ if ((oi = find (a)) != 0)
+ {
+ base::next ();
+
+ if (!base::more ())
+ throw missing_value (a);
- if (!base::more ())
- throw missing_value (oi->option);
+ ov = base::next ();
+ }
+ else if (std::strncmp (a, "-", 1) == 0)
+ {
+ if ((ov = std::strchr (a, '=')) != 0)
+ {
+ std::string o (a, 0, ov - a);
+ if ((oi = find (o.c_str ())) != 0)
+ {
+ base::next ();
+ ++ov;
+ }
+ }
+ }
+ }
+ if (oi != 0)
+ {
if (oi->search_func != 0)
{
- std::string f (oi->search_func (base::next (), oi->arg));
+ std::string f (oi->search_func (ov, oi->arg));
if (!f.empty ())
load (f);
}
else
- load (base::next ());
+ load (ov);
if (!args_.empty ())
return true;
@@ -936,6 +957,10 @@ namespace build2
::build2::cl::unknown_mode opt_mode,
::build2::cl::unknown_mode arg_mode)
{
+ // Can't skip combined flags (--no-combined-flags).
+ //
+ assert (opt_mode != ::build2::cl::unknown_mode::skip);
+
bool r = false;
bool opt = true;
@@ -948,52 +973,143 @@ namespace build2
opt = false;
}
- if (opt && _parse (o, s))
- r = true;
- else if (opt && std::strncmp (o, "-", 1) == 0 && o[1] != '\0')
+ if (opt)
{
- switch (opt_mode)
+ if (_parse (o, s))
{
- case ::build2::cl::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::cl::unknown_mode::stop:
- {
- break;
- }
- case ::build2::cl::unknown_mode::fail:
- {
- throw ::build2::cl::unknown_option (o);
- }
+ r = true;
+ continue;
}
- break;
- }
- else
- {
- switch (arg_mode)
+ if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0')
{
- case ::build2::cl::unknown_mode::skip:
+ // Handle combined option values.
+ //
+ std::string co;
+ if (const char* v = std::strchr (o, '='))
{
- s.skip ();
- r = true;
- continue;
+ co.assign (o, 0, v - o);
+ ++v;
+
+ int ac (2);
+ char* av[] =
+ {
+ const_cast<char*> (co.c_str ()),
+ const_cast<char*> (v)
+ };
+
+ ::build2::cl::argv_scanner ns (0, ac, av);
+
+ if (_parse (co.c_str (), ns))
+ {
+ // Parsed the option but not its value?
+ //
+ if (ns.end () != 2)
+ throw ::build2::cl::invalid_value (co, v);
+
+ s.next ();
+ r = true;
+ continue;
+ }
+ else
+ {
+ // Set the unknown option and fall through.
+ //
+ o = co.c_str ();
+ }
}
- case ::build2::cl::unknown_mode::stop:
+
+ // Handle combined flags.
+ //
+ char cf[3];
{
- break;
+ const char* p = o + 1;
+ for (; *p != '\0'; ++p)
+ {
+ if (!((*p >= 'a' && *p <= 'z') ||
+ (*p >= 'A' && *p <= 'Z') ||
+ (*p >= '0' && *p <= '9')))
+ break;
+ }
+
+ if (*p == '\0')
+ {
+ for (p = o + 1; *p != '\0'; ++p)
+ {
+ std::strcpy (cf, "-");
+ cf[1] = *p;
+ cf[2] = '\0';
+
+ int ac (1);
+ char* av[] =
+ {
+ cf
+ };
+
+ ::build2::cl::argv_scanner ns (0, ac, av);
+
+ if (!_parse (cf, ns))
+ break;
+ }
+
+ if (*p == '\0')
+ {
+ // All handled.
+ //
+ s.next ();
+ r = true;
+ continue;
+ }
+ else
+ {
+ // Set the unknown option and fall through.
+ //
+ o = cf;
+ }
+ }
}
- case ::build2::cl::unknown_mode::fail:
+
+ switch (opt_mode)
{
- throw ::build2::cl::unknown_argument (o);
+ case ::build2::cl::unknown_mode::skip:
+ {
+ s.skip ();
+ r = true;
+ continue;
+ }
+ case ::build2::cl::unknown_mode::stop:
+ {
+ break;
+ }
+ case ::build2::cl::unknown_mode::fail:
+ {
+ throw ::build2::cl::unknown_option (o);
+ }
}
+
+ break;
}
+ }
- break;
+ switch (arg_mode)
+ {
+ case ::build2::cl::unknown_mode::skip:
+ {
+ s.skip ();
+ r = true;
+ continue;
+ }
+ case ::build2::cl::unknown_mode::stop:
+ {
+ break;
+ }
+ case ::build2::cl::unknown_mode::fail:
+ {
+ throw ::build2::cl::unknown_argument (o);
+ }
}
+
+ break;
}
return r;