• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libjingle
3  * Copyright 2006, Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 
33 #ifdef WIN32
34 #include "talk/base/win32.h"
35 #include <shellapi.h>
36 #endif
37 
38 #include "talk/base/flags.h"
39 
40 
41 // -----------------------------------------------------------------------------
42 // Implementation of Flag
43 
Flag(const char * file,const char * name,const char * comment,Type type,void * variable,FlagValue default__)44 Flag::Flag(const char* file, const char* name, const char* comment,
45            Type type, void* variable, FlagValue default__)
46     : file_(file),
47       name_(name),
48       comment_(comment),
49       type_(type),
50       variable_(reinterpret_cast<FlagValue*>(variable)),
51       default_(default__) {
52   FlagList::Register(this);
53 }
54 
55 
SetToDefault()56 void Flag::SetToDefault() {
57   // Note that we cannot simply do '*variable_ = default_;' since
58   // flag variables are not really of type FlagValue and thus may
59   // be smaller! The FlagValue union is simply 'overlayed' on top
60   // of a flag variable for convenient access. Since union members
61   // are guarantee to be aligned at the beginning, this works.
62   switch (type_) {
63     case Flag::BOOL:
64       variable_->b = default_.b;
65       return;
66     case Flag::INT:
67       variable_->i = default_.i;
68       return;
69     case Flag::FLOAT:
70       variable_->f = default_.f;
71       return;
72     case Flag::STRING:
73       variable_->s = default_.s;
74       return;
75   }
76   UNREACHABLE();
77 }
78 
79 
Type2String(Flag::Type type)80 static const char* Type2String(Flag::Type type) {
81   switch (type) {
82     case Flag::BOOL: return "bool";
83     case Flag::INT: return "int";
84     case Flag::FLOAT: return "float";
85     case Flag::STRING: return "string";
86   }
87   UNREACHABLE();
88   return NULL;
89 }
90 
91 
PrintFlagValue(Flag::Type type,FlagValue * p)92 static void PrintFlagValue(Flag::Type type, FlagValue* p) {
93   switch (type) {
94     case Flag::BOOL:
95       printf("%s", (p->b ? "true" : "false"));
96       return;
97     case Flag::INT:
98       printf("%d", p->i);
99       return;
100     case Flag::FLOAT:
101       printf("%f", p->f);
102       return;
103     case Flag::STRING:
104       printf("%s", p->s);
105       return;
106   }
107   UNREACHABLE();
108 }
109 
110 
Print(bool print_current_value)111 void Flag::Print(bool print_current_value) {
112   printf("  --%s (%s)  type: %s  default: ", name_, comment_,
113           Type2String(type_));
114   PrintFlagValue(type_, &default_);
115   if (print_current_value) {
116     printf("  current value: ");
117     PrintFlagValue(type_, variable_);
118   }
119   printf("\n");
120 }
121 
122 
123 // -----------------------------------------------------------------------------
124 // Implementation of FlagList
125 
126 Flag* FlagList::list_ = NULL;
127 
128 
FlagList()129 FlagList::FlagList() {
130   list_ = NULL;
131 }
132 
Print(const char * file,bool print_current_value)133 void FlagList::Print(const char* file, bool print_current_value) {
134   // Since flag registration is likely by file (= C++ file),
135   // we don't need to sort by file and still get grouped output.
136   const char* current = NULL;
137   for (Flag* f = list_; f != NULL; f = f->next()) {
138     if (file == NULL || file == f->file()) {
139       if (current != f->file()) {
140         printf("Flags from %s:\n", f->file());
141         current = f->file();
142       }
143       f->Print(print_current_value);
144     }
145   }
146 }
147 
148 
Lookup(const char * name)149 Flag* FlagList::Lookup(const char* name) {
150   Flag* f = list_;
151   while (f != NULL && strcmp(name, f->name()) != 0)
152     f = f->next();
153   return f;
154 }
155 
156 
SplitArgument(const char * arg,char * buffer,int buffer_size,const char ** name,const char ** value,bool * is_bool)157 void FlagList::SplitArgument(const char* arg,
158                              char* buffer, int buffer_size,
159                              const char** name, const char** value,
160                              bool* is_bool) {
161   *name = NULL;
162   *value = NULL;
163   *is_bool = false;
164 
165   if (*arg == '-') {
166     // find the begin of the flag name
167     arg++;  // remove 1st '-'
168     if (*arg == '-')
169       arg++;  // remove 2nd '-'
170     if (arg[0] == 'n' && arg[1] == 'o') {
171       arg += 2;  // remove "no"
172       *is_bool = true;
173     }
174     *name = arg;
175 
176     // find the end of the flag name
177     while (*arg != '\0' && *arg != '=')
178       arg++;
179 
180     // get the value if any
181     if (*arg == '=') {
182       // make a copy so we can NUL-terminate flag name
183       int n = static_cast<int>(arg - *name);
184       if (n >= buffer_size)
185         Fatal(__FILE__, __LINE__, "CHECK(%s) failed", "n < buffer_size");
186       memcpy(buffer, *name, n * sizeof(char));
187       buffer[n] = '\0';
188       *name = buffer;
189       // get the value
190       *value = arg + 1;
191     }
192   }
193 }
194 
195 
SetFlagsFromCommandLine(int * argc,const char ** argv,bool remove_flags)196 int FlagList::SetFlagsFromCommandLine(int* argc, const char** argv,
197                                       bool remove_flags) {
198   // parse arguments
199   for (int i = 1; i < *argc; /* see below */) {
200     int j = i;  // j > 0
201     const char* arg = argv[i++];
202 
203     // split arg into flag components
204     char buffer[1024];
205     const char* name;
206     const char* value;
207     bool is_bool;
208     SplitArgument(arg, buffer, sizeof buffer, &name, &value, &is_bool);
209 
210     if (name != NULL) {
211       // lookup the flag
212       Flag* flag = Lookup(name);
213       if (flag == NULL) {
214         fprintf(stderr, "Error: unrecognized flag %s\n", arg);
215         return j;
216       }
217 
218       // if we still need a flag value, use the next argument if available
219       if (flag->type() != Flag::BOOL && value == NULL) {
220         if (i < *argc) {
221           value = argv[i++];
222         } else {
223           fprintf(stderr, "Error: missing value for flag %s of type %s\n",
224             arg, Type2String(flag->type()));
225           return j;
226         }
227       }
228 
229       // set the flag
230       char empty[] = { '\0' };
231       char* endp = empty;
232       switch (flag->type()) {
233         case Flag::BOOL:
234           *flag->bool_variable() = !is_bool;
235           break;
236         case Flag::INT:
237           *flag->int_variable() = strtol(value, &endp, 10);
238           break;
239         case Flag::FLOAT:
240           *flag->float_variable() = strtod(value, &endp);
241           break;
242         case Flag::STRING:
243           *flag->string_variable() = value;
244           break;
245       }
246 
247       // handle errors
248       if ((flag->type() == Flag::BOOL && value != NULL) ||
249           (flag->type() != Flag::BOOL && is_bool) ||
250           *endp != '\0') {
251         fprintf(stderr, "Error: illegal value for flag %s of type %s\n",
252           arg, Type2String(flag->type()));
253         return j;
254       }
255 
256       // remove the flag & value from the command
257       if (remove_flags)
258         while (j < i)
259           argv[j++] = NULL;
260     }
261   }
262 
263   // shrink the argument list
264   if (remove_flags) {
265     int j = 1;
266     for (int i = 1; i < *argc; i++) {
267       if (argv[i] != NULL)
268         argv[j++] = argv[i];
269     }
270     *argc = j;
271   }
272 
273   // parsed all flags successfully
274   return 0;
275 }
276 
Register(Flag * flag)277 void FlagList::Register(Flag* flag) {
278   assert(flag != NULL && strlen(flag->name()) > 0);
279   if (Lookup(flag->name()) != NULL)
280     Fatal(flag->file(), 0, "flag %s declared twice", flag->name());
281   flag->next_ = list_;
282   list_ = flag;
283 }
284 
285 #ifdef WIN32
WindowsCommandLineArguments()286 WindowsCommandLineArguments::WindowsCommandLineArguments() {
287   // start by getting the command line.
288   LPTSTR command_line = ::GetCommandLine();
289    // now, convert it to a list of wide char strings.
290   LPWSTR *wide_argv = ::CommandLineToArgvW(command_line, &argc_);
291   // now allocate an array big enough to hold that many string pointers.
292   argv_ = new char*[argc_];
293 
294   // iterate over the returned wide strings;
295   for(int i = 0; i < argc_; ++i) {
296     std::string s = talk_base::ToUtf8(wide_argv[i], wcslen(wide_argv[i]));
297     char *buffer = new char[s.length() + 1];
298     talk_base::strcpyn(buffer, s.length() + 1, s.c_str());
299 
300     // make sure the argv array has the right string at this point.
301     argv_[i] = buffer;
302   }
303   LocalFree(wide_argv);
304 }
305 
~WindowsCommandLineArguments()306 WindowsCommandLineArguments::~WindowsCommandLineArguments() {
307   // need to free each string in the array, and then the array.
308   for(int i = 0; i < argc_; i++) {
309     delete[] argv_[i];
310   }
311 
312   delete[] argv_;
313 }
314 #endif  // WIN32
315 
316