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: 180 183 98.4 %
Date: 2020-05-27 22:15:15 Branches: 234 418 56.0 %

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 <cstdlib>
7
#include "node_options.h"
8
#include "util.h"
9
10
namespace node {
11
12
335362
PerIsolateOptions* PerProcessOptions::get_per_isolate_options() {
13
335362
  return per_isolate.get();
14
}
15
16
307960
EnvironmentOptions* PerIsolateOptions::get_per_env_options() {
17
307960
  return per_env.get();
18
}
19
20
namespace options_parser {
21
22
template <typename Options>
23
272538
void OptionsParser<Options>::AddOption(const char* name,
24
                                       const char* help_text,
25
                                       bool Options::* field,
26
                                       OptionEnvvarSettings env_setting) {
27
272538
  options_.emplace(name,
28
                   OptionInfo{kBoolean,
29
                              std::make_shared<SimpleOptionField<bool>>(field),
30
                              env_setting,
31
                              help_text});
32
272538
}
33
34
template <typename Options>
35
12978
void OptionsParser<Options>::AddOption(const char* name,
36
                                       const char* help_text,
37
                                       uint64_t Options::* field,
38
                                       OptionEnvvarSettings env_setting) {
39
12978
  options_.emplace(
40
      name,
41
      OptionInfo{kUInteger,
42
                 std::make_shared<SimpleOptionField<uint64_t>>(field),
43
                 env_setting,
44
                 help_text});
45
12978
}
46
47
template <typename Options>
48
4326
void OptionsParser<Options>::AddOption(const char* name,
49
                                       const char* help_text,
50
                                       int64_t Options::* field,
51
                                       OptionEnvvarSettings env_setting) {
52
4326
  options_.emplace(
53
      name,
54
      OptionInfo{kInteger,
55
                 std::make_shared<SimpleOptionField<int64_t>>(field),
56
                 env_setting,
57
                 help_text});
58
4326
}
59
60
template <typename Options>
61
116802
void OptionsParser<Options>::AddOption(const char* name,
62
                                       const char* help_text,
63
                                       std::string Options::* field,
64
                                       OptionEnvvarSettings env_setting) {
65
116802
  options_.emplace(
66
      name,
67
      OptionInfo{kString,
68
                 std::make_shared<SimpleOptionField<std::string>>(field),
69
                 env_setting,
70
                 help_text});
71
116802
}
72
73
template <typename Options>
74
8652
void OptionsParser<Options>::AddOption(
75
    const char* name,
76
    const char* help_text,
77
    std::vector<std::string> Options::* field,
78
    OptionEnvvarSettings env_setting) {
79
8652
  options_.emplace(name, OptionInfo {
80
    kStringList,
81
    std::make_shared<SimpleOptionField<std::vector<std::string>>>(field),
82
    env_setting,
83
    help_text
84
  });
85
8652
}
86
87
template <typename Options>
88
4326
void OptionsParser<Options>::AddOption(const char* name,
89
                                       const char* help_text,
90
                                       HostPort Options::* field,
91
                                       OptionEnvvarSettings env_setting) {
92
4326
  options_.emplace(
93
      name,
94
      OptionInfo{kHostPort,
95
                 std::make_shared<SimpleOptionField<HostPort>>(field),
96
                 env_setting,
97
                 help_text});
98
4326
}
99
100
template <typename Options>
101
17304
void OptionsParser<Options>::AddOption(const char* name,
102
                                       const char* help_text,
103
                                       NoOp no_op_tag,
104
                                       OptionEnvvarSettings env_setting) {
105
17304
  options_.emplace(name, OptionInfo{kNoOp, nullptr, env_setting, help_text});
106
17304
}
107
108
template <typename Options>
109
51912
void OptionsParser<Options>::AddOption(const char* name,
110
                                       const char* help_text,
111
                                       V8Option v8_option_tag,
112
                                       OptionEnvvarSettings env_setting) {
113
51912
  options_.emplace(name,
114
                   OptionInfo{kV8Option, nullptr, env_setting, help_text});
115
51912
}
116
117
template <typename Options>
118
56238
void OptionsParser<Options>::AddAlias(const char* from,
119
                                      const char* to) {
120

56238
  aliases_[from] = { to };
121
56238
}
122
123
template <typename Options>
124
25956
void OptionsParser<Options>::AddAlias(const char* from,
125
                                      const std::vector<std::string>& to) {
126
25956
  aliases_[from] = to;
127
25956
}
128
129
template <typename Options>
130
25956
void OptionsParser<Options>::AddAlias(
131
    const char* from,
132
    const std::initializer_list<std::string>& to) {
133
25956
  AddAlias(from, std::vector<std::string>(to));
134
25956
}
135
136
template <typename Options>
137
34608
void OptionsParser<Options>::Implies(const char* from,
138
                                     const char* to) {
139
34608
  auto it = options_.find(to);
140


34608
  CHECK_NE(it, options_.end());
141






34608
  CHECK(it->second.type == kBoolean || it->second.type == kV8Option);
142
69216
  implications_.emplace(
143
69216
      from, Implication{it->second.type, to, it->second.field, true});
144
34608
}
145
146
template <typename Options>
147
4326
void OptionsParser<Options>::ImpliesNot(const char* from,
148
                                        const char* to) {
149
4326
  auto it = options_.find(to);
150
4326
  CHECK_NE(it, options_.end());
151
4326
  CHECK_EQ(it->second.type, kBoolean);
152
8652
  implications_.emplace(
153
8652
      from, Implication{it->second.type, to, it->second.field, false});
154
4326
}
155
156
template <typename Options>
157
template <typename OriginalField, typename ChildOptions>
158
778680
auto OptionsParser<Options>::Convert(
159
    std::shared_ptr<OriginalField> original,
160
    ChildOptions* (Options::* get_child)()) {
161
  // If we have a field on ChildOptions, and we want to access it from an
162
  // Options instance, we call get_child() on the original Options and then
163
  // access it, i.e. this class implements a kind of function chaining.
164
1557360
  struct AdaptedField : BaseOptionField {
165
675514
    void* LookupImpl(Options* options) const override {
166

675514
      return original->LookupImpl((options->*get_child)());
167
    }
168
169
778680
    AdaptedField(
170
        std::shared_ptr<OriginalField> original,
171
        ChildOptions* (Options::* get_child)())
172
778680
          : original(original), get_child(get_child) {}
173
174
    std::shared_ptr<OriginalField> original;
175
    ChildOptions* (Options::* get_child)();
176
  };
177
178
  return std::shared_ptr<BaseOptionField>(
179
778680
      new AdaptedField(original, get_child));
180
}
181
template <typename Options>
182
template <typename ChildOptions>
183
722442
auto OptionsParser<Options>::Convert(
184
    typename OptionsParser<ChildOptions>::OptionInfo original,
185
    ChildOptions* (Options::* get_child)()) {
186
722442
  return OptionInfo{original.type,
187
                    Convert(original.field, get_child),
188
722442
                    original.env_setting,
189
1444884
                    original.help_text};
190
}
191
192
template <typename Options>
193
template <typename ChildOptions>
194
56238
auto OptionsParser<Options>::Convert(
195
    typename OptionsParser<ChildOptions>::Implication original,
196
    ChildOptions* (Options::* get_child)()) {
197
  return Implication{
198
56238
      original.type,
199
      original.name,
200
      Convert(original.target_field, get_child),
201
56238
      original.target_value,
202
112476
  };
203
}
204
205
template <typename Options>
206
template <typename ChildOptions>
207
12978
void OptionsParser<Options>::Insert(
208
    const OptionsParser<ChildOptions>& child_options_parser,
209
    ChildOptions* (Options::* get_child)()) {
210
12978
  aliases_.insert(std::begin(child_options_parser.aliases_),
211
                  std::end(child_options_parser.aliases_));
212
213

735420
  for (const auto& pair : child_options_parser.options_)
214
722442
    options_.emplace(pair.first, Convert(pair.second, get_child));
215
216

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

2133
      if (exec_args != nullptr && ret != "--")
265
2014
        exec_args->push_back(ret);
266
2133
      underlying->erase(underlying->begin() + 1);
267
    } else {
268
206
      synthetic_args.erase(synthetic_args.begin());
269
    }
270
2339
    return ret;
271
  }
272
};
273
274
template <typename Options>
275
8613
void OptionsParser<Options>::Parse(
276
    std::vector<std::string>* const orig_args,
277
    std::vector<std::string>* const exec_args,
278
    std::vector<std::string>* const v8_args,
279
    Options* const options,
280
    OptionEnvvarSettings required_env_settings,
281
    std::vector<std::string>* const errors) const {
282
17226
  ArgsInfo args(orig_args, exec_args);
283
284
  // The first entry is the process name. Make sure it ends up in the V8 argv,
285
  // since V8::SetFlagsFromCommandLine() expects that to hold true for that
286
  // array as well.
287

8613
  if (v8_args->empty())
288
8613
    v8_args->push_back(args.program_name());
289
290




12081
  while (!args.empty() && errors->empty()) {
291




9674
    if (args.first().size() <= 1 || args.first()[0] != '-') break;
292
293
    // We know that we're either going to consume this
294
    // argument or fail completely.
295
3376
    const std::string arg = args.pop_first();
296
297

1773
    if (arg == "--") {
298

16
      if (required_env_settings == kAllowedInEnvironment)
299
1
        errors->push_back(NotAllowedInEnvErr("--"));
300
16
      break;
301
    }
302
303
    // Only allow --foo=bar notation for options starting with double dashes.
304
    // (E.g. -e=a is not allowed as shorthand for --eval=a, which would
305
    // otherwise be the result of alias expansion.)
306
    const std::string::size_type equals_index =
307



1757
        arg[0] == '-' && arg[1] == '-' ? arg.find('=') : std::string::npos;
308
    std::string name =
309



3360
      equals_index == std::string::npos ? arg : arg.substr(0, equals_index);
310
311
    // Store the 'original name' of the argument. This name differs from
312
    // 'name' in that it contains a possible '=' sign and is not affected
313
    // by alias expansion.
314


3360
    std::string original_name = name;
315

1757
    if (equals_index != std::string::npos)
316
167
      original_name += '=';
317
318
7
    auto missing_argument = [&]() {
319
7
      errors->push_back(RequiresArgumentErr(original_name));
320
1764
    };
321
322
    // Normalize by replacing `_` with `-` in options.
323

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

19670
      if (name[i] == '_')
325
38
        name[i] = '-';
326
    }
327
328
    {
329
1757
      auto it = aliases_.end();
330
      // Expand aliases:
331
      // - If `name` can be found in `aliases_`.
332
      // - If `name` + '=' can be found in `aliases_`.
333
      // - If `name` + " <arg>" can be found in `aliases_`, and we have
334
      //   a subsequent argument that does not start with '-' itself.
335



9807
      while ((it = aliases_.find(name)) != aliases_.end() ||
336

230
             (equals_index != std::string::npos &&
337




9975
              (it = aliases_.find(name + '=')) != aliases_.end()) ||
338

3561
             (!args.empty() &&
339

3431
                 !args.first().empty() &&
340

2948
                 args.first()[0] != '-' &&
341

3648
              (it = aliases_.find(name + " <arg>")) != aliases_.end())) {
342
1316
        const std::string prev_name = std::move(name);
343
659
        const std::vector<std::string>& expansion = it->second;
344
345
        // Use the first entry in the expansion as the new 'name'.
346
659
        name = expansion.front();
347
348

659
        if (expansion.size() > 1) {
349
          // The other arguments, if any, are going to be handled later.
350
621
          args.synthetic_args.insert(
351
414
              args.synthetic_args.begin(),
352
414
              expansion.begin() + 1,
353
              expansion.end());
354
        }
355
356



659
        if (name == prev_name) break;
357
      }
358
    }
359
360
1757
    auto it = options_.find(name);
361
362



5140
    if ((it == options_.end() ||
363



2822
         it->second.env_setting == kDisallowedInEnvironment) &&
364
        required_env_settings == kAllowedInEnvironment) {
365
16
      errors->push_back(NotAllowedInEnvErr(original_name));
366
16
      break;
367
    }
368
369
    {
370
1741
      auto implications = implications_.equal_range(name);
371

2094
      for (auto it = implications.first; it != implications.second; ++it) {
372

353
        if (it->second.type == kV8Option) {
373
2
          v8_args->push_back(it->second.name);
374
        } else {
375
702
          *it->second.target_field->template Lookup<bool>(options) =
376
351
              it->second.target_value;
377
        }
378
      }
379
    }
380
381

1741
    if (it == options_.end()) {
382
131
      v8_args->push_back(arg);
383
131
      continue;
384
    }
385
386
1610
    const OptionInfo& info = it->second;
387


3213
    std::string value;
388




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

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

156
        if (value.empty()) {
392
2
          missing_argument();
393
2
          break;
394
        }
395
      } else {
396

571
        if (args.empty()) {
397
5
          missing_argument();
398
5
          break;
399
        }
400
401
566
        value = args.pop_first();
402
403




566
        if (!value.empty() && value[0] == '-') {
404
          missing_argument();
405
          break;
406
        } else {
407






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






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

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