• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "flutter/fml/command_line.h"
6 
7 namespace fml {
8 
9 // CommandLine -----------------------------------------------------------------
10 
Option(const std::string & name)11 CommandLine::Option::Option(const std::string& name) : name(name) {}
12 
Option(const std::string & name,const std::string & value)13 CommandLine::Option::Option(const std::string& name, const std::string& value)
14     : name(name), value(value) {}
15 
16 CommandLine::CommandLine() = default;
17 
18 CommandLine::CommandLine(const CommandLine& from) = default;
19 
20 CommandLine::CommandLine(CommandLine&& from) = default;
21 
CommandLine(const std::string & argv0,const std::vector<Option> & options,const std::vector<std::string> & positional_args)22 CommandLine::CommandLine(const std::string& argv0,
23                          const std::vector<Option>& options,
24                          const std::vector<std::string>& positional_args)
25     : has_argv0_(true),
26       argv0_(argv0),
27       options_(options),
28       positional_args_(positional_args) {
29   for (size_t i = 0; i < options_.size(); i++)
30     option_index_[options_[i].name] = i;
31 }
32 
33 CommandLine::~CommandLine() = default;
34 
35 CommandLine& CommandLine::operator=(const CommandLine& from) = default;
36 
37 CommandLine& CommandLine::operator=(CommandLine&& from) = default;
38 
HasOption(std::string_view name,size_t * index) const39 bool CommandLine::HasOption(std::string_view name, size_t* index) const {
40   auto it = option_index_.find(name.data());
41   if (it == option_index_.end())
42     return false;
43   if (index)
44     *index = it->second;
45   return true;
46 }
47 
GetOptionValue(std::string_view name,std::string * value) const48 bool CommandLine::GetOptionValue(std::string_view name,
49                                  std::string* value) const {
50   size_t index;
51   if (!HasOption(name, &index))
52     return false;
53   *value = options_[index].value;
54   return true;
55 }
56 
GetOptionValues(std::string_view name) const57 std::vector<std::string_view> CommandLine::GetOptionValues(
58     std::string_view name) const {
59   std::vector<std::string_view> ret;
60   for (const auto& option : options_) {
61     if (option.name == name)
62       ret.push_back(option.value);
63   }
64   return ret;
65 }
66 
GetOptionValueWithDefault(std::string_view name,std::string_view default_value) const67 std::string CommandLine::GetOptionValueWithDefault(
68     std::string_view name,
69     std::string_view default_value) const {
70   size_t index;
71   if (!HasOption(name, &index))
72     return {default_value.data(), default_value.size()};
73   return options_[index].value;
74 }
75 
76 // Factory functions (etc.) ----------------------------------------------------
77 
78 namespace internal {
79 
CommandLineBuilder()80 CommandLineBuilder::CommandLineBuilder() {}
~CommandLineBuilder()81 CommandLineBuilder::~CommandLineBuilder() {}
82 
ProcessArg(const std::string & arg)83 bool CommandLineBuilder::ProcessArg(const std::string& arg) {
84   if (!has_argv0_) {
85     has_argv0_ = true;
86     argv0_ = arg;
87     return false;
88   }
89 
90   // If we've seen a positional argument, then the remaining arguments are also
91   // positional.
92   if (started_positional_args_) {
93     bool rv = positional_args_.empty();
94     positional_args_.push_back(arg);
95     return rv;
96   }
97 
98   // Anything that doesn't start with "--" is a positional argument.
99   if (arg.size() < 2u || arg[0] != '-' || arg[1] != '-') {
100     bool rv = positional_args_.empty();
101     started_positional_args_ = true;
102     positional_args_.push_back(arg);
103     return rv;
104   }
105 
106   // "--" ends option processing, but isn't stored as a positional argument.
107   if (arg.size() == 2u) {
108     started_positional_args_ = true;
109     return false;
110   }
111 
112   // Note: The option name *must* be at least one character, so start at
113   // position 3 -- "--=foo" will yield a name of "=foo" and no value. (Passing a
114   // starting |pos| that's "too big" is OK.)
115   size_t equals_pos = arg.find('=', 3u);
116   if (equals_pos == std::string::npos) {
117     options_.push_back(CommandLine::Option(arg.substr(2u)));
118     return false;
119   }
120 
121   options_.push_back(CommandLine::Option(arg.substr(2u, equals_pos - 2u),
122                                          arg.substr(equals_pos + 1u)));
123   return false;
124 }
125 
Build() const126 CommandLine CommandLineBuilder::Build() const {
127   if (!has_argv0_)
128     return CommandLine();
129   return CommandLine(argv0_, options_, positional_args_);
130 }
131 
132 }  // namespace internal
133 
CommandLineToArgv(const CommandLine & command_line)134 std::vector<std::string> CommandLineToArgv(const CommandLine& command_line) {
135   if (!command_line.has_argv0())
136     return std::vector<std::string>();
137 
138   std::vector<std::string> argv;
139   const std::vector<CommandLine::Option>& options = command_line.options();
140   const std::vector<std::string>& positional_args =
141       command_line.positional_args();
142   // Reserve space for argv[0], options, maybe a "--" (if needed), and the
143   // positional arguments.
144   argv.reserve(1u + options.size() + 1u + positional_args.size());
145 
146   argv.push_back(command_line.argv0());
147   for (const auto& option : options) {
148     if (option.value.empty())
149       argv.push_back("--" + option.name);
150     else
151       argv.push_back("--" + option.name + "=" + option.value);
152   }
153 
154   if (!positional_args.empty()) {
155     // Insert a "--" if necessary.
156     if (positional_args[0].size() >= 2u && positional_args[0][0] == '-' &&
157         positional_args[0][1] == '-')
158       argv.push_back("--");
159 
160     argv.insert(argv.end(), positional_args.begin(), positional_args.end());
161   }
162 
163   return argv;
164 }
165 
166 }  // namespace fml
167