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