1 // Copyright (C) 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef FIXED_ARGV_H_
16 #define FIXED_ARGV_H_
17 
18 #include <array>
19 #include <tuple>
20 #include <utility>
21 #include <vector>
22 
23 #include <assert.h>
24 #include <string.h>
25 
26 
27 namespace header_checker {
28 namespace dumper {
29 
30 
31 class FixedArgvAccess;
32 
33 
34 class FixedArgv {
35   friend FixedArgvAccess;
36 
37  private:
38   std::vector<const char *> argv_;
39 
40  public:
FixedArgv(int argc,const char ** argv)41   FixedArgv(int argc, const char **argv) : argv_(argv, argv + argc) {}
42 
GetArgc()43   int GetArgc() const {
44     return argv_.size();
45   }
46 
GetArgv()47   const char *const *GetArgv() const {
48     return argv_.data();
49   }
50 
Resize(int argc)51   void Resize(int argc) {
52     assert(argc <= argv_.size());
53     argv_.resize(argc);
54   }
55 
56   template <typename... T>
GetLastArg(T &&...options)57   const char *GetLastArg(T&& ...options) const {
58     std::array<const char *, sizeof...(options)> opts{
59         std::forward<T&&>(options)...};
60     for (std::vector<const char *>::const_reverse_iterator it = argv_.rbegin(),
61          end = argv_.rend(); it != end; ++it) {
62       for (const char *opt : opts) {
63         if (::strcmp(*it, opt) == 0) {
64           return opt;
65         }
66       }
67     }
68     return nullptr;
69   }
70 
71   template <typename... T>
IsLastArgEqualFirstOption(const char * expected,T &&...others)72   bool IsLastArgEqualFirstOption(const char *expected, T&& ...others) const {
73     const char *last = GetLastArg(expected, others...);
74     // Since GetLastArg() returns the address in {expected, others...}, pointer
75     // comparison is sufficient.
76     return last == expected;
77   }
78 
79   template<typename... T>
PushForwardArgs(T &&...arguments)80   void PushForwardArgs(T&& ...arguments) {
81     std::array<const char *, sizeof...(arguments)> args{
82         std::forward<T&&>(arguments)...};
83     if (!GetLastArg("--")) {
84       argv_.push_back("--");
85     }
86     argv_.insert(argv_.end(), args.begin(), args.end());
87   }
88 };
89 
90 
91 class FixedArgvAccess {
92  private:
93   FixedArgv &fixed_argv_;
94 
95  public:
96   int argc_;
97   const char **argv_;
98 
99  public:
FixedArgvAccess(FixedArgv & fixed_argv)100   explicit FixedArgvAccess(FixedArgv &fixed_argv)
101       : fixed_argv_(fixed_argv), argc_(fixed_argv.GetArgc()),
102         argv_(fixed_argv.argv_.data()) {
103   }
104 
~FixedArgvAccess()105   ~FixedArgvAccess() {
106     fixed_argv_.Resize(argc_);
107   }
108 
109  private:
110   FixedArgvAccess(const FixedArgvAccess &) = delete;
111   FixedArgvAccess& operator=(const FixedArgvAccess &rhs) = delete;
112 };
113 
114 
115 class FixedArgvRegistry {
116  public:
117   typedef void (Function)(FixedArgv &);
118 
119  private:
120   static FixedArgvRegistry *head_;
121 
122   Function *func_;
123   FixedArgvRegistry *next_;
124 
125  public:
FixedArgvRegistry(Function * func)126   FixedArgvRegistry(Function *func) : func_(func), next_(head_) {
127     head_ = this;
128   }
129 
Apply(FixedArgv & fixed_argv)130   static void Apply(FixedArgv &fixed_argv) {
131     for (FixedArgvRegistry *ptr = head_; ptr; ptr = ptr->next_) {
132       ptr->func_(fixed_argv);
133     }
134   }
135 };
136 
137 
138 }  // namespace dumper
139 }  // namespace header_checker
140 
141 
142 #endif  // FIXED_ARGV_H_
143