1 /* 2 * Copyright (C) 2015 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 */ 16 17 #pragma once 18 19 #include <map> 20 #include <string> 21 #include <vector> 22 23 #include "result.h" 24 25 namespace android { 26 namespace init { 27 28 // Every init builtin, init service option, and ueventd option has a minimum and maximum number of 29 // arguments. These must be checked both at run time for safety and also at build time for 30 // correctness in host_init_verifier. Instead of copying and pasting the boiler plate code that 31 // does this check into each function, it is abstracted in KeywordMap<>. This class maps keywords 32 // to functions and checks that the number of arguments provided falls in the correct range or 33 // returns an error otherwise. 34 35 // Value is the return value of Find(), which is typically either a single function or a struct with 36 // additional information. 37 template <typename Value> 38 class KeywordMap { 39 public: 40 struct MapValue { 41 size_t min_args; 42 size_t max_args; 43 Value value; 44 }; 45 KeywordMap()46 KeywordMap() {} KeywordMap(std::initializer_list<std::pair<const std::string,MapValue>> init)47 KeywordMap(std::initializer_list<std::pair<const std::string, MapValue>> init) : map_(init) {} 48 Find(const std::vector<std::string> & args)49 Result<Value> Find(const std::vector<std::string>& args) const { 50 if (args.empty()) return Error() << "Keyword needed, but not provided"; 51 52 auto& keyword = args[0]; 53 auto num_args = args.size() - 1; 54 55 auto result_it = map_.find(keyword); 56 if (result_it == map_.end()) { 57 return Errorf("Invalid keyword '{}'", keyword); 58 } 59 60 auto result = result_it->second; 61 62 auto min_args = result.min_args; 63 auto max_args = result.max_args; 64 if (min_args == max_args && num_args != min_args) { 65 return Errorf("{} requires {} argument{}", keyword, min_args, 66 (min_args > 1 || min_args == 0) ? "s" : ""); 67 } 68 69 if (num_args < min_args || num_args > max_args) { 70 if (max_args == std::numeric_limits<decltype(max_args)>::max()) { 71 return Errorf("{} requires at least {} argument{}", keyword, min_args, 72 min_args > 1 ? "s" : ""); 73 } else { 74 return Errorf("{} requires between {} and {} arguments", keyword, min_args, 75 max_args); 76 } 77 } 78 79 return result.value; 80 } 81 82 private: 83 std::map<std::string, MapValue> map_; 84 }; 85 86 } // namespace init 87 } // namespace android 88