diff options
Diffstat (limited to 'libbuild2/script/parser.cxx')
-rw-r--r-- | libbuild2/script/parser.cxx | 95 |
1 files changed, 70 insertions, 25 deletions
diff --git a/libbuild2/script/parser.cxx b/libbuild2/script/parser.cxx index d5cff1a..b4184ea 100644 --- a/libbuild2/script/parser.cxx +++ b/libbuild2/script/parser.cxx @@ -1027,7 +1027,9 @@ namespace build2 bool env (false); if (prog && tt == type::word && t.value == "env") { - c.variables = parse_env_builtin (t, tt); + parsed_env r (parse_env_builtin (t, tt)); + c.variables = move (r.variables); + c.timeout = r.timeout; env = true; } @@ -1287,7 +1289,7 @@ namespace build2 return make_pair (move (expr), move (hd)); } - environment_vars parser:: + parser::parsed_env parser:: parse_env_builtin (token& t, token_type& tt) { // enter: 'env' word token @@ -1295,11 +1297,10 @@ namespace build2 next (t, tt); // Skip 'env'. - // Note that the -u option and its value can belong to the different - // name chunks. That's why we parse the env builtin arguments in the - // chunking mode into the argument/location pair list up to the '--' - // separator and parse this list into the variable sets/unsets - // afterwords. + // Note that an option name and value can belong to different name + // chunks. That's why we parse the env builtin arguments in the chunking + // mode into the argument/location pair list up to the '--' separator + // and parse this list into the variable sets/unsets afterwords. // // Align the size with environment_vars (double because of -u <var> // which is two arguments). @@ -1352,13 +1353,13 @@ namespace build2 // Parse the env builtin options and arguments. // - environment_vars r; + parsed_env r; // Note: args is empty in the pre-parse mode. // auto i (as.begin ()), e (as.end ()); - // Parse the variable unsets (from options). + // Parse options (the timeout and variable unsets). // for (; i != e; ++i) { @@ -1372,32 +1373,76 @@ namespace build2 break; } - // Unset the variable, adding its name to the resulting variable list. + // We should probably switch to CLI if we need anything more + // elaborate. Note however, that we will have no precise error + // location then. // - auto unset = [&r, &i, this] (string&& v, const char* o) + + // If this is an option represented with its long or short name, then + // return its value as string and nullopt otherwise. In the former + // case strip the value assignment from the option, if it is in the + // <name>=<value> form, and fail if the option value is empty. + // + auto str = [&i, &e, &o, &l, this] (const char* lo, const char* so) { - if (v.empty ()) + optional<string> r; + + if (o == lo || o == so) + { + if (++i == e) + fail (l) << "env: missing value for option '" << o << "'"; + + r = move (i->first); + } + else + { + size_t n (string::traits_type::length (lo)); + + if (o.compare (0, n, lo) == 0 && o[n] == '=') + { + r = string (o, n + 1); + o.resize (n); + } + } + + if (r && r->empty ()) fail (i->second) << "env: empty value for option '" << o << "'"; - if (v.find ('=') != string::npos) - fail (i->second) << "env: invalid value '" << v << "' for " - << "option '" << o << "': contains '='"; + return r; + }; + + // As above but convert the option value to a number and fail on + // error. + // + auto num = [&i, &o, &str, this] (const char* ln, const char* sn) + { + optional<uint64_t> r; + if (optional<string> s = str (ln, sn)) + { + r = parse_number (*s); + + if (!r) + fail (i->second) << "env: invalid value '" << *s + << "' for option '" << o << "'"; + } - r.push_back (move (v)); + return r; }; - // If this is the --unset|-u option then add the variable unset and - // bail out to parsing the variable sets otherwise. + // Parse a known option or bail out to parsing the variable sets. // - if (o == "--unset" || o == "-u") + if (optional<uint64_t> v = num ("--timeout", "-t")) { - if (++i == e) - fail (l) << "env: missing value for option '" << o << "'"; + r.timeout = chrono::seconds (*v); + } + else if (optional<string> v = str ("--unset", "-u")) + { + if (v->find ('=') != string::npos) + fail (i->second) << "env: invalid value '" << *v << "' for " + << "option '" << o << "': contains '='"; - unset (move (i->first), o.c_str ()); + r.variables.push_back (move (*v)); } - else if (o.compare (0, 8, "--unset=") == 0) - unset (string (o, 8), "--unset"); else break; } @@ -1421,7 +1466,7 @@ namespace build2 // Add the variable set to the resulting list. // - r.push_back (move (a)); + r.variables.push_back (move (a)); } return r; |