diff --git a/src/scan.l b/src/scan.l index b359a5f593..3f68ade6c1 100644 --- a/src/scan.l +++ b/src/scan.l @@ -984,34 +984,54 @@ int yywrap() for ( unsigned int i = 0; i < params.size(); ++i ) { - char* param = copy_string(params[i].c_str()); - char* eq = strchr(param, '='); - char* val = eq + 1; + std::string pi = params[i]; + auto first_non_id_char = 0; - *eq = '\0'; - - if ( strlen(val) == 0 ) + for ( size_t j = 0; j < pi.size(); ++j ) { - delete [] param; + if ( ! isalnum(pi[j]) && pi[j] != '_' && pi[j] != ':' ) + break; + + ++first_non_id_char; + } + + auto eq_idx = pi.find('=', first_non_id_char); + // Omit the '=' from op just to make fmt string below clearer. + auto op = pi.substr(first_non_id_char, eq_idx - first_non_id_char); + auto id_str = pi.substr(0, first_non_id_char); + auto val_str = pi.substr(eq_idx + 1); + const auto& id = zeek::id::find(id_str); + + if ( ! id ) + { + reporter->Error("unknown identifier '%s' in command-line options", + id_str.data()); continue; } - // Try to find the type of the param, and interpret - // the value intelligently for that type. (So far, - // that just means quoting the value if it's a - // string type.) If no type is found, the value - // is left unchanged. - std::string opt_quote; // no optional quote by default - const auto& param_id = lookup_ID(param, GLOBAL_MODULE_NAME); - Val* v = param_id ? param_id->GetVal().get() : nullptr; + // Interpret the value based on the identifier's type. + // So far, that just means quoting the value for strings types. + const auto& type = id->GetType(); - if ( v && v->GetType() && v->GetType()->Tag() == zeek::TYPE_STRING ) - opt_quote = "\""; // use quotes + if ( ! type ) + { + reporter->Error("can't set value of '%s' in command-line " + "options: unknown type", id_str.data()); + continue; + } - policy += std::string("redef ") + param + "=" - + opt_quote + val + opt_quote + ";"; + if ( val_str.empty() && ! zeek::IsString(type->Tag()) ) + { + reporter->Error("must assign non-empty value to '%s' in " + "command-line options", id_str.data()); + continue; + } - delete [] param; + auto use_quotes = zeek::IsString(type->Tag()); + auto fmt_str = use_quotes ? "redef %s %s= \"%s\";" + : "redef %s %s= %s;"; + + policy += fmt(fmt_str, id_str.data(), op.data(), val_str.data()); } params.clear(); diff --git a/testing/btest/Baseline/core.command-line-option-redefs/1.out b/testing/btest/Baseline/core.command-line-option-redefs/1.out new file mode 100644 index 0000000000..3e63dcb37f --- /dev/null +++ b/testing/btest/Baseline/core.command-line-option-redefs/1.out @@ -0,0 +1,4 @@ +mystr, +mynum, 0 +mytable, {"one":"1"} +MyMod::str, Good diff --git a/testing/btest/Baseline/core.command-line-option-redefs/2.out b/testing/btest/Baseline/core.command-line-option-redefs/2.out new file mode 100644 index 0000000000..3896a1f1a6 --- /dev/null +++ b/testing/btest/Baseline/core.command-line-option-redefs/2.out @@ -0,0 +1,4 @@ +mystr, default +mynum, 0 +mytable, {"zero":"0","one":"1"} +MyMod::str, def diff --git a/testing/btest/Baseline/core.command-line-option-redefs/3.out b/testing/btest/Baseline/core.command-line-option-redefs/3.out new file mode 100644 index 0000000000..6df6a7a040 --- /dev/null +++ b/testing/btest/Baseline/core.command-line-option-redefs/3.out @@ -0,0 +1 @@ +error: unknown identifier 'no_such_var' in command-line options diff --git a/testing/btest/Baseline/core.command-line-option-redefs/4.out b/testing/btest/Baseline/core.command-line-option-redefs/4.out new file mode 100644 index 0000000000..1a362205c0 --- /dev/null +++ b/testing/btest/Baseline/core.command-line-option-redefs/4.out @@ -0,0 +1,2 @@ +error: must assign non-empty value to 'mynum' in command-line options +error: must assign non-empty value to 'mytable' in command-line options diff --git a/testing/btest/core/command-line-option-redefs.zeek b/testing/btest/core/command-line-option-redefs.zeek new file mode 100644 index 0000000000..e50186b19d --- /dev/null +++ b/testing/btest/core/command-line-option-redefs.zeek @@ -0,0 +1,27 @@ +# @TEST-EXEC: zeek -b %INPUT mynum=0 mytable='{["one"] = "1"}' mystr="" MyMod::str="Good" >1.out +# @TEST-EXEC: zeek -b %INPUT mynum=0 mytable+='{["one"] = "1"}' >2.out + +# @TEST-EXEC-FAIL: zeek -b %INPUT no_such_var=13 >3.out 2>&1 +# @TEST-EXEC-FAIL: zeek -b %INPUT mynum="" mytable="" >4.out 2>&1 + +# @TEST-EXEC: btest-diff 1.out +# @TEST-EXEC: btest-diff 2.out +# @TEST-EXEC: btest-diff 3.out +# @TEST-EXEC: btest-diff 4.out + +const mynum: count &redef; +const mytable: table[string] of string = {["zero"] = "0"} &redef; +option mystr="default"; + +module MyMod; +export { option str="def"; } +module GLOBAL; + +event zeek_init() + { + print "mystr", mystr; + print "mynum", mynum; + print "mytable", to_json(mytable); + print "MyMod::str", MyMod::str; + } +