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   FATAL() << "unreachable code";
     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   FATAL() << "unreachable code";
     71 }
     72 
     73 
     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 
     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 
    111 FlagList::FlagList() {
    112   list_ = NULL;
    113 }
    114 
    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 
    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 
    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 
    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 
    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)
    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 
    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