LCOV - code coverage report
Current view: top level - ipc/chromium/src/base - command_line.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 41 110 37.3 %
Date: 2017-07-14 16:53:18 Functions: 5 18 27.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
       4             : // Use of this source code is governed by a BSD-style license that can be
       5             : // found in the LICENSE file.
       6             : 
       7             : #include "base/command_line.h"
       8             : 
       9             : #if defined(OS_WIN)
      10             : #include <windows.h>
      11             : #include <shellapi.h>
      12             : #endif
      13             : 
      14             : #include <algorithm>
      15             : 
      16             : #include "base/logging.h"
      17             : #include "base/singleton.h"
      18             : #include "base/string_piece.h"
      19             : #include "base/string_util.h"
      20             : #include "base/sys_string_conversions.h"
      21             : 
      22             : CommandLine* CommandLine::current_process_commandline_ = NULL;
      23             : 
      24             : // Since we use a lazy match, make sure that longer versions (like L"--")
      25             : // are listed before shorter versions (like L"-") of similar prefixes.
      26             : #if defined(OS_WIN)
      27             : const wchar_t* const kSwitchPrefixes[] = {L"--", L"-", L"/"};
      28             : const wchar_t kSwitchTerminator[] = L"--";
      29             : const wchar_t kSwitchValueSeparator[] = L"=";
      30             : #elif defined(OS_POSIX)
      31             : // Unixes don't use slash as a switch.
      32             : const char* const kSwitchPrefixes[] = {"--", "-"};
      33             : const char kSwitchTerminator[] = "--";
      34             : const char kSwitchValueSeparator[] = "=";
      35             : #endif
      36             : 
      37             : #if defined(OS_WIN)
      38             : // Lowercase a string.  This is used to lowercase switch names.
      39             : // Is this what we really want?  It seems crazy to me.  I've left it in
      40             : // for backwards compatibility on Windows.
      41             : static void Lowercase(std::wstring* parameter) {
      42             :   transform(parameter->begin(), parameter->end(), parameter->begin(),
      43             :             tolower);
      44             : }
      45             : #endif
      46             : 
      47             : #if defined(OS_WIN)
      48             : void CommandLine::ParseFromString(const std::wstring& command_line) {
      49             :   TrimWhitespace(command_line, TRIM_ALL, &command_line_string_);
      50             : 
      51             :   if (command_line_string_.empty())
      52             :     return;
      53             : 
      54             :   int num_args = 0;
      55             :   wchar_t** args = NULL;
      56             : 
      57             :   args = CommandLineToArgvW(command_line_string_.c_str(), &num_args);
      58             : 
      59             :   // Populate program_ with the trimmed version of the first arg.
      60             :   TrimWhitespace(args[0], TRIM_ALL, &program_);
      61             : 
      62             :   bool parse_switches = true;
      63             :   for (int i = 1; i < num_args; ++i) {
      64             :     std::wstring arg;
      65             :     TrimWhitespace(args[i], TRIM_ALL, &arg);
      66             : 
      67             :     if (!parse_switches) {
      68             :       loose_values_.push_back(arg);
      69             :       continue;
      70             :     }
      71             : 
      72             :     if (arg == kSwitchTerminator) {
      73             :       parse_switches = false;
      74             :       continue;
      75             :     }
      76             : 
      77             :     std::string switch_string;
      78             :     std::wstring switch_value;
      79             :     if (IsSwitch(arg, &switch_string, &switch_value)) {
      80             :       switches_[switch_string] = switch_value;
      81             :     } else {
      82             :       loose_values_.push_back(arg);
      83             :     }
      84             :   }
      85             : 
      86             :   if (args)
      87             :     LocalFree(args);
      88             : }
      89             : CommandLine::CommandLine(const std::wstring& program) {
      90             :   if (!program.empty()) {
      91             :     program_ = program;
      92             :     command_line_string_ = L'"' + program + L'"';
      93             :   }
      94             : }
      95             : #elif defined(OS_POSIX)
      96           3 : CommandLine::CommandLine(int argc, const char* const* argv) {
      97          33 :   for (int i = 0; i < argc; ++i)
      98          30 :     argv_.push_back(argv[i]);
      99           3 :   InitFromArgv();
     100           3 : }
     101           0 : CommandLine::CommandLine(const std::vector<std::string>& argv) {
     102           0 :   argv_ = argv;
     103           0 :   InitFromArgv();
     104           0 : }
     105             : 
     106           3 : void CommandLine::InitFromArgv() {
     107           3 :   bool parse_switches = true;
     108          30 :   for (size_t i = 1; i < argv_.size(); ++i) {
     109          27 :     const std::string& arg = argv_[i];
     110             : 
     111          27 :     if (!parse_switches) {
     112           0 :       loose_values_.push_back(arg);
     113           0 :       continue;
     114             :     }
     115             : 
     116          27 :     if (arg == kSwitchTerminator) {
     117           0 :       parse_switches = false;
     118           0 :       continue;
     119             :     }
     120             : 
     121          54 :     std::string switch_string;
     122          54 :     std::string switch_value;
     123          27 :     if (IsSwitch(arg, &switch_string, &switch_value)) {
     124          15 :       switches_[switch_string] = switch_value;
     125             :     } else {
     126          12 :       loose_values_.push_back(arg);
     127             :     }
     128             :   }
     129           3 : }
     130             : 
     131           0 : CommandLine::CommandLine(const std::wstring& program) {
     132           0 :   argv_.push_back(WideToASCII(program));
     133           0 : }
     134             : #endif
     135             : 
     136             : // static
     137          27 : bool CommandLine::IsSwitch(const StringType& parameter_string,
     138             :                            std::string* switch_string,
     139             :                            StringType* switch_value) {
     140          27 :   switch_string->clear();
     141          27 :   switch_value->clear();
     142             : 
     143          66 :   for (size_t i = 0; i < arraysize(kSwitchPrefixes); ++i) {
     144          54 :     StringType prefix(kSwitchPrefixes[i]);
     145          54 :     if (parameter_string.find(prefix) != 0)
     146          39 :       continue;
     147             : 
     148          15 :     const size_t switch_start = prefix.length();
     149             :     const size_t equals_position = parameter_string.find(
     150          15 :         kSwitchValueSeparator, switch_start);
     151          30 :     StringType switch_native;
     152          15 :     if (equals_position == StringType::npos) {
     153          15 :       switch_native = parameter_string.substr(switch_start);
     154             :     } else {
     155           0 :       switch_native = parameter_string.substr(
     156           0 :           switch_start, equals_position - switch_start);
     157           0 :       *switch_value = parameter_string.substr(equals_position + 1);
     158             :     }
     159             : #if defined(OS_WIN)
     160             :     Lowercase(&switch_native);
     161             :     *switch_string = WideToASCII(switch_native);
     162             : #else
     163          15 :     *switch_string = switch_native;
     164             : #endif
     165             : 
     166          15 :     return true;
     167             :   }
     168             : 
     169          12 :   return false;
     170             : }
     171             : 
     172             : // static
     173           3 : void CommandLine::Init(int argc, const char* const* argv) {
     174           3 :   DCHECK(current_process_commandline_ == NULL);
     175             : #if defined(OS_WIN)
     176             :   current_process_commandline_ = new CommandLine;
     177             :   current_process_commandline_->ParseFromString(::GetCommandLineW());
     178             : #elif defined(OS_POSIX)
     179           3 :   current_process_commandline_ = new CommandLine(argc, argv);
     180             : #endif
     181           3 : }
     182             : 
     183           0 : void CommandLine::Terminate() {
     184           0 :   DCHECK(current_process_commandline_ != NULL);
     185           0 :   delete current_process_commandline_;
     186           0 :   current_process_commandline_ = NULL;
     187           0 : }
     188             : 
     189           0 : bool CommandLine::HasSwitch(const std::wstring& switch_string) const {
     190           0 :   std::wstring lowercased_switch(switch_string);
     191             : #if defined(OS_WIN)
     192             :   Lowercase(&lowercased_switch);
     193             : #endif
     194           0 :   return switches_.find(WideToASCII(lowercased_switch)) != switches_.end();
     195             : }
     196             : 
     197           2 : std::wstring CommandLine::GetSwitchValue(
     198             :     const std::wstring& switch_string) const {
     199           4 :   std::wstring lowercased_switch(switch_string);
     200             : #if defined(OS_WIN)
     201             :   Lowercase(&lowercased_switch);
     202             : #endif
     203             : 
     204             :   std::map<std::string, StringType>::const_iterator result =
     205           2 :       switches_.find(WideToASCII(lowercased_switch));
     206             : 
     207           2 :   if (result == switches_.end()) {
     208           2 :     return L"";
     209             :   } else {
     210             : #if defined(OS_WIN)
     211             :     return result->second;
     212             : #else
     213           0 :     return ASCIIToWide(result->second);
     214             : #endif
     215             :   }
     216             : }
     217             : 
     218             : #if defined(OS_WIN)
     219             : std::vector<std::wstring> CommandLine::GetLooseValues() const {
     220             :   return loose_values_;
     221             : }
     222             : std::wstring CommandLine::program() const {
     223             :   return program_;
     224             : }
     225             : #else
     226           0 : std::vector<std::wstring> CommandLine::GetLooseValues() const {
     227           0 :   std::vector<std::wstring> values;
     228           0 :   for (size_t i = 0; i < loose_values_.size(); ++i)
     229           0 :     values.push_back(ASCIIToWide(loose_values_[i]));
     230           0 :   return values;
     231             : }
     232           0 : std::wstring CommandLine::program() const {
     233           0 :   DCHECK(argv_.size() > 0);
     234           0 :   return ASCIIToWide(argv_[0]);
     235             : }
     236             : #endif
     237             : 
     238             : 
     239             : // static
     240           0 : std::wstring CommandLine::PrefixedSwitchString(
     241             :     const std::wstring& switch_string) {
     242             :   return StringPrintf(L"%ls%ls",
     243           0 :                       kSwitchPrefixes[0],
     244           0 :                       switch_string.c_str());
     245             : }
     246             : 
     247             : // static
     248           0 : std::wstring CommandLine::PrefixedSwitchStringWithValue(
     249             :     const std::wstring& switch_string, const std::wstring& value_string) {
     250           0 :   if (value_string.empty()) {
     251           0 :     return PrefixedSwitchString(switch_string);
     252             :   }
     253             : 
     254             :   return StringPrintf(L"%ls%ls%ls%ls",
     255           0 :                       kSwitchPrefixes[0],
     256             :                       switch_string.c_str(),
     257             :                       kSwitchValueSeparator,
     258           0 :                       value_string.c_str());
     259             : }
     260             : 
     261             : #if defined(OS_WIN)
     262             : void CommandLine::AppendSwitch(const std::wstring& switch_string) {
     263             :   std::wstring prefixed_switch_string = PrefixedSwitchString(switch_string);
     264             :   command_line_string_.append(L" ");
     265             :   command_line_string_.append(prefixed_switch_string);
     266             :   switches_[WideToASCII(switch_string)] = L"";
     267             : }
     268             : 
     269             : // Quote a string if necessary, such that CommandLineToArgvW() will
     270             : // always process it as a single argument.
     271             : static std::wstring WindowsStyleQuote(const std::wstring& arg) {
     272             :   // We follow the quoting rules of CommandLineToArgvW.
     273             :   // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
     274             :   if (arg.find_first_of(L" \\\"\t") == std::wstring::npos) {
     275             :     // No quoting necessary.
     276             :     return arg;
     277             :   }
     278             : 
     279             :   std::wstring out;
     280             :   out.push_back(L'"');
     281             :   for (size_t i = 0; i < arg.size(); ++i) {
     282             :     if (arg[i] == '\\') {
     283             :       // Find the extent of this run of backslashes.
     284             :       size_t start = i, end = start + 1;
     285             :       for (; end < arg.size() && arg[end] == '\\'; ++end)
     286             :         /* empty */;
     287             :       size_t backslash_count = end - start;
     288             : 
     289             :       // Backslashes are escapes only if the run is followed by a double quote.
     290             :       // Since we also will end the string with a double quote, we escape for
     291             :       // either a double quote or the end of the string.
     292             :       if (end == arg.size() || arg[end] == '"') {
     293             :         // To quote, we need to output 2x as many backslashes.
     294             :         backslash_count *= 2;
     295             :       }
     296             :       for (size_t j = 0; j < backslash_count; ++j)
     297             :         out.push_back('\\');
     298             : 
     299             :       // Advance i to one before the end to balance i++ in loop.
     300             :       i = end - 1;
     301             :     } else if (arg[i] == '"') {
     302             :       out.push_back('\\');
     303             :       out.push_back('"');
     304             :     } else {
     305             :       out.push_back(arg[i]);
     306             :     }
     307             :   }
     308             :   out.push_back('"');
     309             : 
     310             :   return out;
     311             : }
     312             : 
     313             : void CommandLine::AppendSwitchWithValue(const std::wstring& switch_string,
     314             :                                         const std::wstring& value_string) {
     315             :   std::wstring quoted_value_string = WindowsStyleQuote(value_string);
     316             :   std::wstring combined_switch_string =
     317             :     PrefixedSwitchStringWithValue(switch_string, quoted_value_string);
     318             : 
     319             :   command_line_string_.append(L" ");
     320             :   command_line_string_.append(combined_switch_string);
     321             : 
     322             :   switches_[WideToASCII(switch_string)] = value_string;
     323             : }
     324             : 
     325             : void CommandLine::AppendLooseValue(const std::wstring& value) {
     326             :   command_line_string_.append(L" ");
     327             :   command_line_string_.append(WindowsStyleQuote(value));
     328             : }
     329             : 
     330             : void CommandLine::AppendArguments(const CommandLine& other,
     331             :                                   bool include_program) {
     332             :   // Verify include_program is used correctly.
     333             :   // Logic could be shorter but this is clearer.
     334             :   DCHECK(include_program ? !other.program().empty() : other.program().empty());
     335             :   command_line_string_ += L" " + other.command_line_string_;
     336             :   std::map<std::string, StringType>::const_iterator i;
     337             :   for (i = other.switches_.begin(); i != other.switches_.end(); ++i)
     338             :     switches_[i->first] = i->second;
     339             : }
     340             : 
     341             : void CommandLine::PrependWrapper(const std::wstring& wrapper) {
     342             :   // The wrapper may have embedded arguments (like "gdb --args"). In this case,
     343             :   // we don't pretend to do anything fancy, we just split on spaces.
     344             :   std::vector<std::wstring> wrapper_and_args;
     345             :   SplitString(wrapper, ' ', &wrapper_and_args);
     346             :   program_ = wrapper_and_args[0];
     347             :   command_line_string_ = wrapper + L" " + command_line_string_;
     348             : }
     349             : 
     350             : #elif defined(OS_POSIX)
     351           0 : void CommandLine::AppendSwitch(const std::wstring& switch_string) {
     352           0 :   std::string ascii_switch = WideToASCII(switch_string);
     353           0 :   argv_.push_back(kSwitchPrefixes[0] + ascii_switch);
     354           0 :   switches_[ascii_switch] = "";
     355           0 : }
     356             : 
     357           0 : void CommandLine::AppendSwitchWithValue(const std::wstring& switch_string,
     358             :                                         const std::wstring& value_string) {
     359           0 :   std::string ascii_switch = WideToASCII(switch_string);
     360           0 :   std::string ascii_value = WideToASCII(value_string);
     361             : 
     362           0 :   argv_.push_back(kSwitchPrefixes[0] + ascii_switch +
     363           0 :                   kSwitchValueSeparator + ascii_value);
     364           0 :   switches_[ascii_switch] = ascii_value;
     365           0 : }
     366             : 
     367           0 : void CommandLine::AppendLooseValue(const std::wstring& value) {
     368           0 :   argv_.push_back(WideToASCII(value));
     369           0 : }
     370             : 
     371           0 : void CommandLine::AppendArguments(const CommandLine& other,
     372             :                                   bool include_program) {
     373             :   // Verify include_program is used correctly.
     374             :   // Logic could be shorter but this is clearer.
     375           0 :   DCHECK(include_program ? !other.program().empty() : other.program().empty());
     376             : 
     377           0 :   size_t first_arg = include_program ? 0 : 1;
     378           0 :   for (size_t i = first_arg; i < other.argv_.size(); ++i)
     379           0 :     argv_.push_back(other.argv_[i]);
     380           0 :   std::map<std::string, StringType>::const_iterator i;
     381           0 :   for (i = other.switches_.begin(); i != other.switches_.end(); ++i)
     382           0 :     switches_[i->first] = i->second;
     383           0 : }
     384             : 
     385           0 : void CommandLine::PrependWrapper(const std::wstring& wrapper_wide) {
     386             :   // The wrapper may have embedded arguments (like "gdb --args"). In this case,
     387             :   // we don't pretend to do anything fancy, we just split on spaces.
     388           0 :   const std::string wrapper = WideToASCII(wrapper_wide);
     389           0 :   std::vector<std::string> wrapper_and_args;
     390           0 :   SplitString(wrapper, ' ', &wrapper_and_args);
     391           0 :   argv_.insert(argv_.begin(), wrapper_and_args.begin(), wrapper_and_args.end());
     392           0 : }
     393             : 
     394             : #endif

Generated by: LCOV version 1.13