GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_options-inl.h Lines: 172 174 98.9 %
Date: 2019-09-12 22:30:12 Branches: 235 426 55.2 %

Line Branch Exec Source
1
#ifndef SRC_NODE_OPTIONS_INL_H_
2
#define SRC_NODE_OPTIONS_INL_H_
3
4
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5
6
#include "node_options.h"
7
#include "util.h"
8
#include <cstdlib>
9
10
namespace node {
11
12
333784
PerIsolateOptions* PerProcessOptions::get_per_isolate_options() {
13
333784
  return per_isolate.get();
14
}
15
16
35912
DebugOptions* EnvironmentOptions::get_debug_options() {
17
35912
  return &debug_options_;
18
}
19
20
20420
const DebugOptions& EnvironmentOptions::debug_options() const {
21
20420
  return debug_options_;
22
}
23
24
292990
EnvironmentOptions* PerIsolateOptions::get_per_env_options() {
25
292990
  return per_env.get();
26
}
27
28
namespace options_parser {
29
30
template <typename Options>
31
257712
void OptionsParser<Options>::AddOption(const char* name,
32
                                       const char* help_text,
33
                                       bool Options::* field,
34
                                       OptionEnvvarSettings env_setting) {
35
257712
  options_.emplace(name,
36
                   OptionInfo{kBoolean,
37
                              std::make_shared<SimpleOptionField<bool>>(field),
38
                              env_setting,
39
                              help_text});
40
257712
}
41
42
template <typename Options>
43
14868
void OptionsParser<Options>::AddOption(const char* name,
44
                                       const char* help_text,
45
                                       uint64_t Options::* field,
46
                                       OptionEnvvarSettings env_setting) {
47
14868
  options_.emplace(
48
      name,
49
      OptionInfo{kUInteger,
50
                 std::make_shared<SimpleOptionField<uint64_t>>(field),
51
                 env_setting,
52
                 help_text});
53
14868
}
54
55
template <typename Options>
56
4956
void OptionsParser<Options>::AddOption(const char* name,
57
                                       const char* help_text,
58
                                       int64_t Options::* field,
59
                                       OptionEnvvarSettings env_setting) {
60
4956
  options_.emplace(
61
      name,
62
      OptionInfo{kInteger,
63
                 std::make_shared<SimpleOptionField<int64_t>>(field),
64
                 env_setting,
65
                 help_text});
66
4956
}
67
68
template <typename Options>
69
118944
void OptionsParser<Options>::AddOption(const char* name,
70
                                       const char* help_text,
71
                                       std::string Options::* field,
72
                                       OptionEnvvarSettings env_setting) {
73
118944
  options_.emplace(
74
      name,
75
      OptionInfo{kString,
76
                 std::make_shared<SimpleOptionField<std::string>>(field),
77
                 env_setting,
78
                 help_text});
79
118944
}
80
81
template <typename Options>
82
9912
void OptionsParser<Options>::AddOption(
83
    const char* name,
84
    const char* help_text,
85
    std::vector<std::string> Options::* field,
86
    OptionEnvvarSettings env_setting) {
87
9912
  options_.emplace(name, OptionInfo {
88
    kStringList,
89
    std::make_shared<SimpleOptionField<std::vector<std::string>>>(field),
90
    env_setting,
91
    help_text
92
  });
93
9912
}
94
95
template <typename Options>
96
4956
void OptionsParser<Options>::AddOption(const char* name,
97
                                       const char* help_text,
98
                                       HostPort Options::* field,
99
                                       OptionEnvvarSettings env_setting) {
100
4956
  options_.emplace(
101
      name,
102
      OptionInfo{kHostPort,
103
                 std::make_shared<SimpleOptionField<HostPort>>(field),
104
                 env_setting,
105
                 help_text});
106
4956
}
107
108
template <typename Options>
109
9912
void OptionsParser<Options>::AddOption(const char* name,
110
                                       const char* help_text,
111
                                       NoOp no_op_tag,
112
                                       OptionEnvvarSettings env_setting) {
113
9912
  options_.emplace(name, OptionInfo{kNoOp, nullptr, env_setting, help_text});
114
9912
}
115
116
template <typename Options>
117
39648
void OptionsParser<Options>::AddOption(const char* name,
118
                                       const char* help_text,
119
                                       V8Option v8_option_tag,
120
                                       OptionEnvvarSettings env_setting) {
121
39648
  options_.emplace(name,
122
                   OptionInfo{kV8Option, nullptr, env_setting, help_text});
123
39648
}
124
125
template <typename Options>
126
59472
void OptionsParser<Options>::AddAlias(const char* from,
127
                                      const char* to) {
128

59472
  aliases_[from] = { to };
129
59472
}
130
131
template <typename Options>
132
29736
void OptionsParser<Options>::AddAlias(const char* from,
133
                                      const std::vector<std::string>& to) {
134
29736
  aliases_[from] = to;
135
29736
}
136
137
template <typename Options>
138
29736
void OptionsParser<Options>::AddAlias(
139
    const char* from,
140
    const std::initializer_list<std::string>& to) {
141
29736
  AddAlias(from, std::vector<std::string>(to));
142
29736
}
143
144
template <typename Options>
145
34692
void OptionsParser<Options>::Implies(const char* from,
146
                                     const char* to) {
147
34692
  auto it = options_.find(to);
148


34692
  CHECK_NE(it, options_.end());
149


34692
  CHECK_EQ(it->second.type, kBoolean);
150
34692
  implications_.emplace(from, Implication {
151
34692
    it->second.field, true
152
  });
153
34692
}
154
155
template <typename Options>
156
4956
void OptionsParser<Options>::ImpliesNot(const char* from,
157
                                        const char* to) {
158
4956
  auto it = options_.find(to);
159
4956
  CHECK_NE(it, options_.end());
160
4956
  CHECK_EQ(it->second.type, kBoolean);
161
4956
  implications_.emplace(from, Implication {
162
4956
    it->second.field, false
163
  });
164
4956
}
165
166
template <typename Options>
167
template <typename OriginalField, typename ChildOptions>
168
763224
auto OptionsParser<Options>::Convert(
169
    std::shared_ptr<OriginalField> original,
170
    ChildOptions* (Options::* get_child)()) {
171
  // If we have a field on ChildOptions, and we want to access it from an
172
  // Options instance, we call get_child() on the original Options and then
173
  // access it, i.e. this class implements a kind of function chaining.
174

1526448
  struct AdaptedField : BaseOptionField {
175
662670
    void* LookupImpl(Options* options) const override {
176

662670
      return original->LookupImpl((options->*get_child)());
177
    }
178
179
763224
    AdaptedField(
180
        std::shared_ptr<OriginalField> original,
181
        ChildOptions* (Options::* get_child)())
182
763224
          : original(original), get_child(get_child) {}
183
184
    std::shared_ptr<OriginalField> original;
185
    ChildOptions* (Options::* get_child)();
186
  };
187
188
  return std::shared_ptr<BaseOptionField>(
189
763224
      new AdaptedField(original, get_child));
190
}
191
template <typename Options>
192
template <typename ChildOptions>
193
698796
auto OptionsParser<Options>::Convert(
194
    typename OptionsParser<ChildOptions>::OptionInfo original,
195
    ChildOptions* (Options::* get_child)()) {
196
  return OptionInfo{original.type,
197
                    Convert(original.field, get_child),
198
                    original.env_setting,
199
698796
                    original.help_text};
200
}
201
202
template <typename Options>
203
template <typename ChildOptions>
204
64428
auto OptionsParser<Options>::Convert(
205
    typename OptionsParser<ChildOptions>::Implication original,
206
    ChildOptions* (Options::* get_child)()) {
207
  return Implication {
208
    Convert(original.target_field, get_child),
209
    original.target_value
210
64428
  };
211
}
212
213
template <typename Options>
214
template <typename ChildOptions>
215
14868
void OptionsParser<Options>::Insert(
216
    const OptionsParser<ChildOptions>& child_options_parser,
217
    ChildOptions* (Options::* get_child)()) {
218
14868
  aliases_.insert(std::begin(child_options_parser.aliases_),
219
                  std::end(child_options_parser.aliases_));
220
221

713664
  for (const auto& pair : child_options_parser.options_)
222
698796
    options_.emplace(pair.first, Convert(pair.second, get_child));
223
224

79296
  for (const auto& pair : child_options_parser.implications_)
225
64428
    implications_.emplace(pair.first, Convert(pair.second, get_child));
226
14868
}
227
228
15
inline std::string NotAllowedInEnvErr(const std::string& arg) {
229
15
  return arg + " is not allowed in NODE_OPTIONS";
230
}
231
232
7
inline std::string RequiresArgumentErr(const std::string& arg) {
233
7
  return arg + " requires an argument";
234
}
235
236
// We store some of the basic information around a single Parse call inside
237
// this struct, to separate storage of command line arguments and their
238
// handling. In particular, this makes it easier to introduce 'synthetic'
239
// arguments that get inserted by expanding option aliases.
240
9755
struct ArgsInfo {
241
  // Generally, the idea here is that the first entry in `*underlying` stores
242
  // the "0th" argument (the program name), then `synthetic_args` are inserted,
243
  // followed by the remainder of `*underlying`.
244
  std::vector<std::string>* underlying;
245
  std::vector<std::string> synthetic_args;
246
247
  std::vector<std::string>* exec_args;
248
249
9755
  ArgsInfo(std::vector<std::string>* args,
250
           std::vector<std::string>* exec_args)
251
9755
    : underlying(args), exec_args(exec_args) {}
252
253
14403
  size_t remaining() const {
254
    // -1 to account for the program name.
255
14403
    return underlying->size() - 1 + synthetic_args.size();
256
  }
257
258
14403
  bool empty() const { return remaining() == 0; }
259
9755
  const std::string& program_name() const { return underlying->at(0); }
260
261
20025
  std::string& first() {
262
20025
    return synthetic_args.empty() ? underlying->at(1) : synthetic_args.front();
263
  }
264
265
3007
  std::string pop_first() {
266
3007
    std::string ret = std::move(first());
267
3007
    if (synthetic_args.empty()) {
268
      // Only push arguments to `exec_args` that were also originally passed
269
      // on the command line (i.e. not generated through alias expansion).
270
      // '--' is a special case here since its purpose is to end `exec_argv`,
271
      // which is why we do not include it.
272

2503
      if (exec_args != nullptr && ret != "--")
273
2390
        exec_args->push_back(ret);
274
2503
      underlying->erase(underlying->begin() + 1);
275
    } else {
276
504
      synthetic_args.erase(synthetic_args.begin());
277
    }
278
3007
    return ret;
279
  }
280
};
281
282
template <typename Options>
283
9755
void OptionsParser<Options>::Parse(
284
    std::vector<std::string>* const orig_args,
285
    std::vector<std::string>* const exec_args,
286
    std::vector<std::string>* const v8_args,
287
    Options* const options,
288
    OptionEnvvarSettings required_env_settings,
289
    std::vector<std::string>* const errors) const {
290
9755
  ArgsInfo args(orig_args, exec_args);
291
292
  // The first entry is the process name. Make sure it ends up in the V8 argv,
293
  // since V8::SetFlagsFromCommandLine() expects that to hold true for that
294
  // array as well.
295

9755
  if (v8_args->empty())
296
9755
    v8_args->push_back(args.program_name());
297
298




23607
  while (!args.empty() && errors->empty()) {
299




11244
    if (args.first().size() <= 1 || args.first()[0] != '-') break;
300
301
    // We know that we're either going to consume this
302
    // argument or fail completely.
303
2416
    const std::string arg = args.pop_first();
304
305

2416
    if (arg == "--") {
306

295
      if (required_env_settings == kAllowedInEnvironment)
307
1
        errors->push_back(NotAllowedInEnvErr("--"));
308
295
      break;
309
    }
310
311
    // Only allow --foo=bar notation for options starting with double dashes.
312
    // (E.g. -e=a is not allowed as shorthand for --eval=a, which would
313
    // otherwise be the result of alias expansion.)
314
    const std::string::size_type equals_index =
315



2121
        arg[0] == '-' && arg[1] == '-' ? arg.find('=') : std::string::npos;
316
    std::string name =
317



4118
      equals_index == std::string::npos ? arg : arg.substr(0, equals_index);
318
319
    // Store the 'original name' of the argument. This name differs from
320
    // 'name' in that it contains a possible '=' sign and is not affected
321
    // by alias expansion.
322


4118
    std::string original_name = name;
323

2121
    if (equals_index != std::string::npos)
324
160
      original_name += '=';
325
326
    // Normalize by replacing `_` with `-` in options.
327

25080
    for (std::string::size_type i = 2; i < name.size(); ++i) {
328

22959
      if (name[i] == '_')
329
58
        name[i] = '-';
330
    }
331
332
    {
333
2121
      auto it = aliases_.end();
334
      // Expand aliases:
335
      // - If `name` can be found in `aliases_`.
336
      // - If `name` + '=' can be found in `aliases_`.
337
      // - If `name` + " <arg>" can be found in `aliases_`, and we have
338
      //   a subsequent argument that does not start with '-' itself.
339













12288
      while ((it = aliases_.find(name)) != aliases_.end() ||
340
             (equals_index != std::string::npos &&
341



3297
              (it = aliases_.find(name + '=')) != aliases_.end()) ||
342
3792
             (!args.empty() &&
343
1840
                 !args.first().empty() &&
344
1837
                 args.first()[0] != '-' &&
345



5483
              (it = aliases_.find(name + " <arg>")) != aliases_.end())) {
346
1015
        const std::string prev_name = std::move(name);
347
1015
        const std::vector<std::string>& expansion = it->second;
348
349
        // Use the first entry in the expansion as the new 'name'.
350
1015
        name = expansion.front();
351
352

1015
        if (expansion.size() > 1) {
353
          // The other arguments, if any, are going to be handled later.
354
505
          args.synthetic_args.insert(
355
              args.synthetic_args.begin(),
356
              expansion.begin() + 1,
357
1010
              expansion.end());
358
        }
359
360



1015
        if (name == prev_name) break;
361
      }
362
    }
363
364
2121
    auto it = options_.find(name);
365
366







4139
    if ((it == options_.end() ||
367
2018
         it->second.env_setting == kDisallowedInEnvironment) &&
368
        required_env_settings == kAllowedInEnvironment) {
369
14
      errors->push_back(NotAllowedInEnvErr(original_name));
370
14
      break;
371
    }
372
373

2107
    if (it == options_.end()) {
374
103
      v8_args->push_back(arg);
375
103
      continue;
376
    }
377
378
    {
379
2004
      auto implications = implications_.equal_range(name);
380

2483
      for (auto it = implications.first; it != implications.second; ++it) {
381
958
        *it->second.target_field->template Lookup<bool>(options) =
382
479
            it->second.target_value;
383
      }
384
    }
385
386
2004
    const OptionInfo& info = it->second;
387


4001
    std::string value;
388




2004
    if (info.type != kBoolean && info.type != kNoOp && info.type != kV8Option) {
389

747
      if (equals_index != std::string::npos) {
390
151
        value = arg.substr(equals_index + 1);
391

151
        if (value.empty()) {
392
        missing_argument:
393
7
          errors->push_back(RequiresArgumentErr(original_name));
394
7
          break;
395
        }
396
      } else {
397

596
        if (args.empty())
398
5
          goto missing_argument;
399
400
591
        value = args.pop_first();
401
402




591
        if (!value.empty() && value[0] == '-') {
403
          goto missing_argument;
404
        } else {
405






591
          if (!value.empty() && value[0] == '\\' && value[1] == '-')
406
1
            value = value.substr(1);  // Treat \- as escaping an -.
407
        }
408
      }
409
    }
410
411






1997
    switch (info.type) {
412
      case kBoolean:
413
1224
        *Lookup<bool>(info.field, options) = true;
414
1224
        break;
415
      case kInteger:
416
1
        *Lookup<int64_t>(info.field, options) = std::atoll(value.c_str());
417
1
        break;
418
      case kUInteger:
419
27
        *Lookup<uint64_t>(info.field, options) = std::stoull(value);
420
27
        break;
421
      case kString:
422
575
        *Lookup<std::string>(info.field, options) = value;
423
575
        break;
424
      case kStringList:
425
39
        Lookup<std::vector<std::string>>(info.field, options)
426
39
            ->emplace_back(std::move(value));
427
39
        break;
428
      case kHostPort:
429
98
        Lookup<HostPort>(info.field, options)
430
            ->Update(SplitHostPort(value, errors));
431
98
        break;
432
      case kNoOp:
433
1
        break;
434
      case kV8Option:
435
32
        v8_args->push_back(arg);
436

32
        break;
437
      default:
438
        UNREACHABLE();
439
    }
440
  }
441
9755
  options->CheckOptions(errors);
442
9755
}
443
444
}  // namespace options_parser
445
}  // namespace node
446
447
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
448
449
#endif  // SRC_NODE_OPTIONS_INL_H_