• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright 2006 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 
15 
16 #if defined(WEBRTC_WIN)
17 #include "webrtc/base/win32.h"
18 #include <shellapi.h>
19 #endif
20 
21 #include "webrtc/base/flags.h"
22 
23 namespace rtc {
24 // -----------------------------------------------------------------------------
25 // Implementation of Flag
26 
Flag(const char * file,const char * name,const char * comment,Type type,void * variable,FlagValue default__)27 Flag::Flag(const char* file, const char* name, const char* comment,
28            Type type, void* variable, FlagValue default__)
29     : file_(file),
30       name_(name),
31       comment_(comment),
32       type_(type),
33       variable_(reinterpret_cast<FlagValue*>(variable)),
34       default_(default__) {
35   FlagList::Register(this);
36 }
37 
38 
SetToDefault()39 void Flag::SetToDefault() {
40   // Note that we cannot simply do '*variable_ = default_;' since
41   // flag variables are not really of type FlagValue and thus may
42   // be smaller! The FlagValue union is simply 'overlayed' on top
43   // of a flag variable for convenient access. Since union members
44   // are guarantee to be aligned at the beginning, this works.
45   switch (type_) {
46     case Flag::BOOL:
47       variable_->b = default_.b;
48       return;
49     case Flag::INT:
50       variable_->i = default_.i;
51       return;
52     case Flag::FLOAT:
53       variable_->f = default_.f;
54       return;
55     case Flag::STRING:
56       variable_->s = default_.s;
57       return;
58   }
59   FATAL() << "unreachable code";
60 }
61 
62 
Type2String(Flag::Type type)63 static const char* Type2String(Flag::Type type) {
64   switch (type) {
65     case Flag::BOOL: return "bool";
66     case Flag::INT: return "int";
67     case Flag::FLOAT: return "float";
68     case Flag::STRING: return "string";
69   }
70   FATAL() << "unreachable code";
71 }
72 
73 
PrintFlagValue(Flag::Type type,FlagValue * p)74 static void PrintFlagValue(Flag::Type type, FlagValue* p) {
75   switch (type) {
76     case Flag::BOOL:
77       printf("%s", (p->b ? "true" : "false"));
78       return;
79     case Flag::INT:
80       printf("%d", p->i);
81       return;
82     case Flag::FLOAT:
83       printf("%f", p->f);
84       return;
85     case Flag::STRING:
86       printf("%s", p->s);
87       return;
88   }
89   FATAL() << "unreachable code";
90 }
91 
92 
Print(bool print_current_value)93 void Flag::Print(bool print_current_value) {
94   printf("  --%s (%s)  type: %s  default: ", name_, comment_,
95           Type2String(type_));
96   PrintFlagValue(type_, &default_);
97   if (print_current_value) {
98     printf("  current value: ");
99     PrintFlagValue(type_, variable_);
100   }
101   printf("\n");
102 }
103 
104 
105 // -----------------------------------------------------------------------------
106 // Implementation of FlagList
107 
108 Flag* FlagList::list_ = NULL;
109 
110 
FlagList()111 FlagList::FlagList() {
112   list_ = NULL;
113 }
114 
Print(const char * file,bool print_current_value)115 void FlagList::Print(const char* file, bool print_current_value) {
116   // Since flag registration is likely by file (= C++ file),
117   // we don't need to sort by file and still get grouped output.
118   const char* current = NULL;
119   for (Flag* f = list_; f != NULL; f = f->next()) {
120     if (file == NULL || file == f->file()) {
121       if (current != f->file()) {
122         printf("Flags from %s:\n", f->file());
123         current = f->file();
124       }
125       f->Print(print_current_value);
126     }
127   }
128 }
129 
130 
Lookup(const char * name)131 Flag* FlagList::Lookup(const char* name) {
132   Flag* f = list_;
133   while (f != NULL && strcmp(name, f->name()) != 0)
134     f = f->next();
135   return f;
136 }
137 
138 
SplitArgument(const char * arg,char * buffer,int buffer_size,const char ** name,const char ** value,bool * is_bool)139 void FlagList::SplitArgument(const char* arg,
140                              char* buffer, int buffer_size,
141                              const char** name, const char** value,
142                              bool* is_bool) {
143   *name = NULL;
144   *value = NULL;
145   *is_bool = false;
146 
147   if (*arg == '-') {
148     // find the begin of the flag name
149     arg++;  // remove 1st '-'
150     if (*arg == '-')
151       arg++;  // remove 2nd '-'
152     if (arg[0] == 'n' && arg[1] == 'o') {
153       arg += 2;  // remove "no"
154       *is_bool = true;
155     }
156     *name = arg;
157 
158     // find the end of the flag name
159     while (*arg != '\0' && *arg != '=')
160       arg++;
161 
162     // get the value if any
163     if (*arg == '=') {
164       // make a copy so we can NUL-terminate flag name
165       int n = static_cast<int>(arg - *name);
166       RTC_CHECK_LT(n, buffer_size);
167       memcpy(buffer, *name, n * sizeof(char));
168       buffer[n] = '\0';
169       *name = buffer;
170       // get the value
171       *value = arg + 1;
172     }
173   }
174 }
175 
176 
SetFlagsFromCommandLine(int * argc,const char ** argv,bool remove_flags)177 int FlagList::SetFlagsFromCommandLine(int* argc, const char** argv,
178                                       bool remove_flags) {
179   // parse arguments
180   for (int i = 1; i < *argc; /* see below */) {
181     int j = i;  // j > 0
182     const char* arg = argv[i++];
183 
184     // split arg into flag components
185     char buffer[1024];
186     const char* name;
187     const char* value;
188     bool is_bool;
189     SplitArgument(arg, buffer, sizeof buffer, &name, &value, &is_bool);
190 
191     if (name != NULL) {
192       // lookup the flag
193       Flag* flag = Lookup(name);
194       if (flag == NULL) {
195         fprintf(stderr, "Error: unrecognized flag %s\n", arg);
196         return j;
197       }
198 
199       // if we still need a flag value, use the next argument if available
200       if (flag->type() != Flag::BOOL && value == NULL) {
201         if (i < *argc) {
202           value = argv[i++];
203         } else {
204           fprintf(stderr, "Error: missing value for flag %s of type %s\n",
205             arg, Type2String(flag->type()));
206           return j;
207         }
208       }
209 
210       // set the flag
211       char empty[] = { '\0' };
212       char* endp = empty;
213       switch (flag->type()) {
214         case Flag::BOOL:
215           *flag->bool_variable() = !is_bool;
216           break;
217         case Flag::INT:
218           *flag->int_variable() = strtol(value, &endp, 10);
219           break;
220         case Flag::FLOAT:
221           *flag->float_variable() = strtod(value, &endp);
222           break;
223         case Flag::STRING:
224           *flag->string_variable() = value;
225           break;
226       }
227 
228       // handle errors
229       if ((flag->type() == Flag::BOOL && value != NULL) ||
230           (flag->type() != Flag::BOOL && is_bool) ||
231           *endp != '\0') {
232         fprintf(stderr, "Error: illegal value for flag %s of type %s\n",
233           arg, Type2String(flag->type()));
234         return j;
235       }
236 
237       // remove the flag & value from the command
238       if (remove_flags)
239         while (j < i)
240           argv[j++] = NULL;
241     }
242   }
243 
244   // shrink the argument list
245   if (remove_flags) {
246     int j = 1;
247     for (int i = 1; i < *argc; i++) {
248       if (argv[i] != NULL)
249         argv[j++] = argv[i];
250     }
251     *argc = j;
252   }
253 
254   // parsed all flags successfully
255   return 0;
256 }
257 
Register(Flag * flag)258 void FlagList::Register(Flag* flag) {
259   assert(flag != NULL && strlen(flag->name()) > 0);
260   RTC_CHECK(!Lookup(flag->name())) << "flag " << flag->name()
261                                    << " declared twice";
262   flag->next_ = list_;
263   list_ = flag;
264 }
265 
266 #if defined(WEBRTC_WIN)
WindowsCommandLineArguments()267 WindowsCommandLineArguments::WindowsCommandLineArguments() {
268   // start by getting the command line.
269   LPTSTR command_line = ::GetCommandLine();
270    // now, convert it to a list of wide char strings.
271   LPWSTR *wide_argv = ::CommandLineToArgvW(command_line, &argc_);
272   // now allocate an array big enough to hold that many string pointers.
273   argv_ = new char*[argc_];
274 
275   // iterate over the returned wide strings;
276   for(int i = 0; i < argc_; ++i) {
277     std::string s = rtc::ToUtf8(wide_argv[i], wcslen(wide_argv[i]));
278     char *buffer = new char[s.length() + 1];
279     rtc::strcpyn(buffer, s.length() + 1, s.c_str());
280 
281     // make sure the argv array has the right string at this point.
282     argv_[i] = buffer;
283   }
284   LocalFree(wide_argv);
285 }
286 
~WindowsCommandLineArguments()287 WindowsCommandLineArguments::~WindowsCommandLineArguments() {
288   // need to free each string in the array, and then the array.
289   for(int i = 0; i < argc_; i++) {
290     delete[] argv_[i];
291   }
292 
293   delete[] argv_;
294 }
295 #endif  // WEBRTC_WIN
296 
297 }  // namespace rtc
298