1 //
2 // Copyright (C) 2022 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 #include "host/commands/start/override_bool_arg.h"
16
17 #include <string>
18 #include <unordered_set>
19 #include <vector>
20
21 #include <android-base/strings.h>
22
23 namespace cuttlefish {
24 namespace {
25
26 struct BooleanFlag {
27 bool is_bool_flag;
28 bool bool_flag_value;
29 std::string name;
30 };
IsBoolArg(const std::string & argument,const std::unordered_set<std::string> & flag_set)31 BooleanFlag IsBoolArg(const std::string& argument,
32 const std::unordered_set<std::string>& flag_set) {
33 // Validate format
34 // we only deal with special bool case: -flag, --flag, -noflag, --noflag
35 // and convert to -flag=true, --flag=true, -flag=false, --flag=false
36 // others not in this format just return false
37 std::string_view name = argument;
38 if (!android::base::ConsumePrefix(&name, "-")) {
39 return {false, false, ""};
40 }
41 android::base::ConsumePrefix(&name, "-");
42 std::size_t found = name.find('=');
43 if (found != std::string::npos) {
44 // found "=", --flag=value case, it doesn't need convert
45 return {false, false, ""};
46 }
47
48 // Validate it is part of the set
49 std::string result_name(name);
50 std::string_view new_name = result_name;
51 if (result_name.length() == 0) {
52 return {false, false, ""};
53 }
54 if (flag_set.find(result_name) != flag_set.end()) {
55 // matched -flag, --flag
56 return {true, true, result_name};
57 } else if (android::base::ConsumePrefix(&new_name, "no")) {
58 // 2nd chance to check -noflag, --noflag
59 result_name = new_name;
60 if (flag_set.find(result_name) != flag_set.end()) {
61 // matched -noflag, --noflag
62 return {true, false, result_name};
63 }
64 }
65 // return status
66 return {false, false, ""};
67 }
68
FormatBoolString(const std::string & name_str,bool value)69 std::string FormatBoolString(const std::string& name_str, bool value) {
70 std::string new_flag = "--" + name_str;
71 if (value) {
72 new_flag += "=true";
73 } else {
74 new_flag += "=false";
75 }
76 return new_flag;
77 }
78
79 } // namespace
80
OverrideBoolArg(std::vector<std::string> args,const std::unordered_set<std::string> & flag_set)81 std::vector<std::string> OverrideBoolArg(
82 std::vector<std::string> args,
83 const std::unordered_set<std::string>& flag_set) {
84 for (int index = 0; index < args.size(); index++) {
85 const std::string curr_arg = args[index];
86 BooleanFlag value = IsBoolArg(curr_arg, flag_set);
87 if (value.is_bool_flag) {
88 // Override the value
89 args[index] = FormatBoolString(value.name, value.bool_flag_value);
90 }
91 }
92 return args;
93 }
94
95 } // namespace cuttlefish
96