Home | History | Annotate | Download | only in base
      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 
     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 
     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   UNREACHABLE();
     60 }
     61 
     62 
     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   UNREACHABLE();
     71   return NULL;
     72 }
     73 
     74 
     75 static void PrintFlagValue(Flag::Type type, FlagValue* p) {
     76   switch (type) {
     77     case Flag::BOOL:
     78       printf("%s", (p->b ? "true" : "false"));
     79       return;
     80     case Flag::INT:
     81       printf("%d", p->i);
     82       return;
     83     case Flag::FLOAT:
     84       printf("%f", p->f);
     85       return;
     86     case Flag::STRING:
     87       printf("%s", p->s);
     88       return;
     89   }
     90   UNREACHABLE();
     91 }
     92 
     93 
     94 void Flag::Print(bool print_current_value) {
     95   printf("  --%s (%s)  type: %s  default: ", name_, comment_,
     96           Type2String(type_));
     97   PrintFlagValue(type_, &default_);
     98   if (print_current_value) {
     99     printf("  current value: ");
    100     PrintFlagValue(type_, variable_);
    101   }
    102   printf("\n");
    103 }
    104 
    105 
    106 // -----------------------------------------------------------------------------
    107 // Implementation of FlagList
    108 
    109 Flag* FlagList::list_ = NULL;
    110 
    111 
    112 FlagList::FlagList() {
    113   list_ = NULL;
    114 }
    115 
    116 void FlagList::Print(const char* file, bool print_current_value) {
    117   // Since flag registration is likely by file (= C++ file),
    118   // we don't need to sort by file and still get grouped output.
    119   const char* current = NULL;
    120   for (Flag* f = list_; f != NULL; f = f->next()) {
    121     if (file == NULL || file == f->file()) {
    122       if (current != f->file()) {
    123         printf("Flags from %s:\n", f->file());
    124         current = f->file();
    125       }
    126       f->Print(print_current_value);
    127     }
    128   }
    129 }
    130 
    131 
    132 Flag* FlagList::Lookup(const char* name) {
    133   Flag* f = list_;
    134   while (f != NULL && strcmp(name, f->name()) != 0)
    135     f = f->next();
    136   return f;
    137 }
    138 
    139 
    140 void FlagList::SplitArgument(const char* arg,
    141                              char* buffer, int buffer_size,
    142                              const char** name, const char** value,
    143                              bool* is_bool) {
    144   *name = NULL;
    145   *value = NULL;
    146   *is_bool = false;
    147 
    148   if (*arg == '-') {
    149     // find the begin of the flag name
    150     arg++;  // remove 1st '-'
    151     if (*arg == '-')
    152       arg++;  // remove 2nd '-'
    153     if (arg[0] == 'n' && arg[1] == 'o') {
    154       arg += 2;  // remove "no"
    155       *is_bool = true;
    156     }
    157     *name = arg;
    158 
    159     // find the end of the flag name
    160     while (*arg != '\0' && *arg != '=')
    161       arg++;
    162 
    163     // get the value if any
    164     if (*arg == '=') {
    165       // make a copy so we can NUL-terminate flag name
    166       int n = static_cast<int>(arg - *name);
    167       if (n >= buffer_size)
    168         Fatal(__FILE__, __LINE__, "CHECK(%s) failed", "n < buffer_size");
    169       memcpy(buffer, *name, n * sizeof(char));
    170       buffer[n] = '\0';
    171       *name = buffer;
    172       // get the value
    173       *value = arg + 1;
    174     }
    175   }
    176 }
    177 
    178 
    179 int FlagList::SetFlagsFromCommandLine(int* argc, const char** argv,
    180                                       bool remove_flags) {
    181   // parse arguments
    182   for (int i = 1; i < *argc; /* see below */) {
    183     int j = i;  // j > 0
    184     const char* arg = argv[i++];
    185 
    186     // split arg into flag components
    187     char buffer[1024];
    188     const char* name;
    189     const char* value;
    190     bool is_bool;
    191     SplitArgument(arg, buffer, sizeof buffer, &name, &value, &is_bool);
    192 
    193     if (name != NULL) {
    194       // lookup the flag
    195       Flag* flag = Lookup(name);
    196       if (flag == NULL) {
    197         fprintf(stderr, "Error: unrecognized flag %s\n", arg);
    198         return j;
    199       }
    200 
    201       // if we still need a flag value, use the next argument if available
    202       if (flag->type() != Flag::BOOL && value == NULL) {
    203         if (i < *argc) {
    204           value = argv[i++];
    205         } else {
    206           fprintf(stderr, "Error: missing value for flag %s of type %s\n",
    207             arg, Type2String(flag->type()));
    208           return j;
    209         }
    210       }
    211 
    212       // set the flag
    213       char empty[] = { '\0' };
    214       char* endp = empty;
    215       switch (flag->type()) {
    216         case Flag::BOOL:
    217           *flag->bool_variable() = !is_bool;
    218           break;
    219         case Flag::INT:
    220           *flag->int_variable() = strtol(value, &endp, 10);
    221           break;
    222         case Flag::FLOAT:
    223           *flag->float_variable() = strtod(value, &endp);
    224           break;
    225         case Flag::STRING:
    226           *flag->string_variable() = value;
    227           break;
    228       }
    229 
    230       // handle errors
    231       if ((flag->type() == Flag::BOOL && value != NULL) ||
    232           (flag->type() != Flag::BOOL && is_bool) ||
    233           *endp != '\0') {
    234         fprintf(stderr, "Error: illegal value for flag %s of type %s\n",
    235           arg, Type2String(flag->type()));
    236         return j;
    237       }
    238 
    239       // remove the flag & value from the command
    240       if (remove_flags)
    241         while (j < i)
    242           argv[j++] = NULL;
    243     }
    244   }
    245 
    246   // shrink the argument list
    247   if (remove_flags) {
    248     int j = 1;
    249     for (int i = 1; i < *argc; i++) {
    250       if (argv[i] != NULL)
    251         argv[j++] = argv[i];
    252     }
    253     *argc = j;
    254   }
    255 
    256   // parsed all flags successfully
    257   return 0;
    258 }
    259 
    260 void FlagList::Register(Flag* flag) {
    261   assert(flag != NULL && strlen(flag->name()) > 0);
    262   if (Lookup(flag->name()) != NULL)
    263     Fatal(flag->file(), 0, "flag %s declared twice", flag->name());
    264   flag->next_ = list_;
    265   list_ = flag;
    266 }
    267 
    268 #if defined(WEBRTC_WIN)
    269 WindowsCommandLineArguments::WindowsCommandLineArguments() {
    270   // start by getting the command line.
    271   LPTSTR command_line = ::GetCommandLine();
    272    // now, convert it to a list of wide char strings.
    273   LPWSTR *wide_argv = ::CommandLineToArgvW(command_line, &argc_);
    274   // now allocate an array big enough to hold that many string pointers.
    275   argv_ = new char*[argc_];
    276 
    277   // iterate over the returned wide strings;
    278   for(int i = 0; i < argc_; ++i) {
    279     std::string s = rtc::ToUtf8(wide_argv[i], wcslen(wide_argv[i]));
    280     char *buffer = new char[s.length() + 1];
    281     rtc::strcpyn(buffer, s.length() + 1, s.c_str());
    282 
    283     // make sure the argv array has the right string at this point.
    284     argv_[i] = buffer;
    285   }
    286   LocalFree(wide_argv);
    287 }
    288 
    289 WindowsCommandLineArguments::~WindowsCommandLineArguments() {
    290   // need to free each string in the array, and then the array.
    291   for(int i = 0; i < argc_; i++) {
    292     delete[] argv_[i];
    293   }
    294 
    295   delete[] argv_;
    296 }
    297 #endif  // WEBRTC_WIN
    298 
    299 }  // namespace rtc
    300