GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
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 |
381696 |
PerIsolateOptions* PerProcessOptions::get_per_isolate_options() { |
|
13 |
381696 |
return per_isolate.get(); |
|
14 |
} |
||
15 |
|||
16 |
351742 |
EnvironmentOptions* PerIsolateOptions::get_per_env_options() { |
|
17 |
351742 |
return per_env.get(); |
|
18 |
} |
||
19 |
|||
20 |
namespace options_parser { |
||
21 |
|||
22 |
template <typename Options> |
||
23 |
299392 |
void OptionsParser<Options>::AddOption(const char* name, |
|
24 |
const char* help_text, |
||
25 |
bool Options::* field, |
||
26 |
OptionEnvvarSettings env_setting) { |
||
27 |
299392 |
options_.emplace(name, |
|
28 |
OptionInfo{kBoolean, |
||
29 |
std::make_shared<SimpleOptionField<bool>>(field), |
||
30 |
env_setting, |
||
31 |
help_text}); |
||
32 |
299392 |
} |
|
33 |
|||
34 |
template <typename Options> |
||
35 |
14034 |
void OptionsParser<Options>::AddOption(const char* name, |
|
36 |
const char* help_text, |
||
37 |
uint64_t Options::* field, |
||
38 |
OptionEnvvarSettings env_setting) { |
||
39 |
14034 |
options_.emplace( |
|
40 |
name, |
||
41 |
OptionInfo{kUInteger, |
||
42 |
std::make_shared<SimpleOptionField<uint64_t>>(field), |
||
43 |
env_setting, |
||
44 |
help_text}); |
||
45 |
14034 |
} |
|
46 |
|||
47 |
template <typename Options> |
||
48 |
9356 |
void OptionsParser<Options>::AddOption(const char* name, |
|
49 |
const char* help_text, |
||
50 |
int64_t Options::* field, |
||
51 |
OptionEnvvarSettings env_setting) { |
||
52 |
9356 |
options_.emplace( |
|
53 |
name, |
||
54 |
OptionInfo{kInteger, |
||
55 |
std::make_shared<SimpleOptionField<int64_t>>(field), |
||
56 |
env_setting, |
||
57 |
help_text}); |
||
58 |
9356 |
} |
|
59 |
|||
60 |
template <typename Options> |
||
61 |
126306 |
void OptionsParser<Options>::AddOption(const char* name, |
|
62 |
const char* help_text, |
||
63 |
std::string Options::* field, |
||
64 |
OptionEnvvarSettings env_setting) { |
||
65 |
126306 |
options_.emplace( |
|
66 |
name, |
||
67 |
OptionInfo{kString, |
||
68 |
std::make_shared<SimpleOptionField<std::string>>(field), |
||
69 |
env_setting, |
||
70 |
help_text}); |
||
71 |
126306 |
} |
|
72 |
|||
73 |
template <typename Options> |
||
74 |
14034 |
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 |
14034 |
options_.emplace(name, OptionInfo { |
|
80 |
kStringList, |
||
81 |
std::make_shared<SimpleOptionField<std::vector<std::string>>>(field), |
||
82 |
env_setting, |
||
83 |
help_text |
||
84 |
}); |
||
85 |
14034 |
} |
|
86 |
|||
87 |
template <typename Options> |
||
88 |
4678 |
void OptionsParser<Options>::AddOption(const char* name, |
|
89 |
const char* help_text, |
||
90 |
HostPort Options::* field, |
||
91 |
OptionEnvvarSettings env_setting) { |
||
92 |
4678 |
options_.emplace( |
|
93 |
name, |
||
94 |
OptionInfo{kHostPort, |
||
95 |
std::make_shared<SimpleOptionField<HostPort>>(field), |
||
96 |
env_setting, |
||
97 |
help_text}); |
||
98 |
4678 |
} |
|
99 |
|||
100 |
template <typename Options> |
||
101 |
28068 |
void OptionsParser<Options>::AddOption(const char* name, |
|
102 |
const char* help_text, |
||
103 |
NoOp no_op_tag, |
||
104 |
OptionEnvvarSettings env_setting) { |
||
105 |
28068 |
options_.emplace(name, OptionInfo{kNoOp, nullptr, env_setting, help_text}); |
|
106 |
28068 |
} |
|
107 |
|||
108 |
template <typename Options> |
||
109 |
60814 |
void OptionsParser<Options>::AddOption(const char* name, |
|
110 |
const char* help_text, |
||
111 |
V8Option v8_option_tag, |
||
112 |
OptionEnvvarSettings env_setting) { |
||
113 |
60814 |
options_.emplace(name, |
|
114 |
OptionInfo{kV8Option, nullptr, env_setting, help_text}); |
||
115 |
60814 |
} |
|
116 |
|||
117 |
template <typename Options> |
||
118 |
70170 |
void OptionsParser<Options>::AddAlias(const char* from, |
|
119 |
const char* to) { |
||
120 |
✓✓✓✓ ✓✓ |
70170 |
aliases_[from] = { to }; |
121 |
70170 |
} |
|
122 |
|||
123 |
template <typename Options> |
||
124 |
28068 |
void OptionsParser<Options>::AddAlias(const char* from, |
|
125 |
const std::vector<std::string>& to) { |
||
126 |
28068 |
aliases_[from] = to; |
|
127 |
28068 |
} |
|
128 |
|||
129 |
template <typename Options> |
||
130 |
28068 |
void OptionsParser<Options>::AddAlias( |
|
131 |
const char* from, |
||
132 |
const std::initializer_list<std::string>& to) { |
||
133 |
28068 |
AddAlias(from, std::vector<std::string>(to)); |
|
134 |
28068 |
} |
|
135 |
|||
136 |
template <typename Options> |
||
137 |
46780 |
void OptionsParser<Options>::Implies(const char* from, |
|
138 |
const char* to) { |
||
139 |
46780 |
auto it = options_.find(to); |
|
140 |
✗✗✓✗ ✓✗✓✓ |
46780 |
CHECK_NE(it, options_.end()); |
141 |
✗✓✗✗ ✗✓✓✓ ✗✓✗✓ ✗✓✗✗ ✗✓✗✓ ✗✗✗✓ |
46780 |
CHECK(it->second.type == kBoolean || it->second.type == kV8Option); |
142 |
93560 |
implications_.emplace( |
|
143 |
93560 |
from, Implication{it->second.type, to, it->second.field, true}); |
|
144 |
46780 |
} |
|
145 |
|||
146 |
template <typename Options> |
||
147 |
9356 |
void OptionsParser<Options>::ImpliesNot(const char* from, |
|
148 |
const char* to) { |
||
149 |
9356 |
auto it = options_.find(to); |
|
150 |
✓✗✓✗ |
9356 |
CHECK_NE(it, options_.end()); |
151 |
✗✓✗✓ |
9356 |
CHECK_EQ(it->second.type, kBoolean); |
152 |
18712 |
implications_.emplace( |
|
153 |
18712 |
from, Implication{it->second.type, to, it->second.field, false}); |
|
154 |
9356 |
} |
|
155 |
|||
156 |
template <typename Options> |
||
157 |
template <typename OriginalField, typename ChildOptions> |
||
158 |
893498 |
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 |
1786996 |
struct AdaptedField : BaseOptionField { |
|
165 |
768626 |
void* LookupImpl(Options* options) const override { |
|
166 |
✗✓✗✓ ✗✓ |
768626 |
return original->LookupImpl((options->*get_child)()); |
167 |
} |
||
168 |
|||
169 |
893498 |
AdaptedField( |
|
170 |
std::shared_ptr<OriginalField> original, |
||
171 |
ChildOptions* (Options::* get_child)()) |
||
172 |
893498 |
: 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 |
893498 |
new AdaptedField(original, get_child)); |
|
180 |
} |
||
181 |
template <typename Options> |
||
182 |
template <typename ChildOptions> |
||
183 |
828006 |
auto OptionsParser<Options>::Convert( |
|
184 |
typename OptionsParser<ChildOptions>::OptionInfo original, |
||
185 |
ChildOptions* (Options::* get_child)()) { |
||
186 |
828006 |
return OptionInfo{original.type, |
|
187 |
Convert(original.field, get_child), |
||
188 |
828006 |
original.env_setting, |
|
189 |
1656012 |
original.help_text}; |
|
190 |
} |
||
191 |
|||
192 |
template <typename Options> |
||
193 |
template <typename ChildOptions> |
||
194 |
65492 |
auto OptionsParser<Options>::Convert( |
|
195 |
typename OptionsParser<ChildOptions>::Implication original, |
||
196 |
ChildOptions* (Options::* get_child)()) { |
||
197 |
return Implication{ |
||
198 |
65492 |
original.type, |
|
199 |
original.name, |
||
200 |
Convert(original.target_field, get_child), |
||
201 |
65492 |
original.target_value, |
|
202 |
130984 |
}; |
|
203 |
} |
||
204 |
|||
205 |
template <typename Options> |
||
206 |
template <typename ChildOptions> |
||
207 |
14034 |
void OptionsParser<Options>::Insert( |
|
208 |
const OptionsParser<ChildOptions>& child_options_parser, |
||
209 |
ChildOptions* (Options::* get_child)()) { |
||
210 |
14034 |
aliases_.insert(std::begin(child_options_parser.aliases_), |
|
211 |
std::end(child_options_parser.aliases_)); |
||
212 |
|||
213 |
✓✓✓✓ ✓✓ |
842040 |
for (const auto& pair : child_options_parser.options_) |
214 |
828006 |
options_.emplace(pair.first, Convert(pair.second, get_child)); |
|
215 |
|||
216 |
✓✓✓✓ ✓✓ |
79526 |
for (const auto& pair : child_options_parser.implications_) |
217 |
65492 |
implications_.emplace(pair.first, Convert(pair.second, get_child)); |
|
218 |
14034 |
} |
|
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 |
9410 |
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 |
9410 |
ArgsInfo(std::vector<std::string>* args, |
|
242 |
std::vector<std::string>* exec_args) |
||
243 |
9410 |
: underlying(args), exec_args(exec_args) {} |
|
244 |
|||
245 |
13748 |
size_t remaining() const { |
|
246 |
// -1 to account for the program name. |
||
247 |
13748 |
return underlying->size() - 1 + synthetic_args.size(); |
|
248 |
} |
||
249 |
|||
250 |
13748 |
bool empty() const { return remaining() == 0; } |
|
251 |
9410 |
const std::string& program_name() const { return underlying->at(0); } |
|
252 |
|||
253 |
18346 |
std::string& first() { |
|
254 |
✓✓ | 18346 |
return synthetic_args.empty() ? underlying->at(1) : synthetic_args.front(); |
255 |
} |
||
256 |
|||
257 |
2431 |
std::string pop_first() { |
|
258 |
2431 |
std::string ret = std::move(first()); |
|
259 |
✓✓ | 2431 |
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 |
✓✓✓✓ ✓✓ |
2235 |
if (exec_args != nullptr && ret != "--") |
265 |
2115 |
exec_args->push_back(ret); |
|
266 |
2235 |
underlying->erase(underlying->begin() + 1); |
|
267 |
} else { |
||
268 |
196 |
synthetic_args.erase(synthetic_args.begin()); |
|
269 |
} |
||
270 |
2431 |
return ret; |
|
271 |
} |
||
272 |
}; |
||
273 |
|||
274 |
template <typename Options> |
||
275 |
9410 |
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 |
18820 |
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 |
✓✗✓✗ ✗✗ |
9410 |
if (v8_args->empty()) |
288 |
9410 |
v8_args->push_back(args.program_name()); |
|
289 |
|||
290 |
✓✓✓✗ ✓✓✓✓ ✓✗✓✓ ✗✗✗✗ ✗✗ |
13096 |
while (!args.empty() && errors->empty()) { |
291 |
✓✓✓✓ ✓✓✓✗ ✗✓✗✓ ✗✗✗✗ ✗✗ |
10489 |
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 |
3608 |
const std::string arg = args.pop_first(); |
|
296 |
|||
297 |
✓✓✓✓ ✗✗ |
1882 |
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 |
✓✗✓✓ ✓✗✓✗ ✗✗✗✗ |
1866 |
arg[0] == '-' && arg[1] == '-' ? arg.find('=') : std::string::npos; |
308 |
std::string name = |
||
309 |
✓✓✓✓ ✓✓✓✓ ✓✓✗✗ ✗✗✗ |
3592 |
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 |
✓✓✓✓ ✓✓✗✗ ✗ |
3592 |
std::string original_name = name; |
315 |
✓✓✓✓ ✗✗ |
1866 |
if (equals_index != std::string::npos) |
316 |
192 |
original_name += '='; |
|
317 |
|||
318 |
7 |
auto missing_argument = [&]() { |
|
319 |
7 |
errors->push_back(RequiresArgumentErr(original_name)); |
|
320 |
1873 |
}; |
|
321 |
|||
322 |
// Normalize by replacing `_` with `-` in options. |
||
323 |
✓✓✓✓ ✗✗ |
22970 |
for (std::string::size_type i = 2; i < name.size(); ++i) { |
324 |
✓✓✓✓ ✗✗ |
21104 |
if (name[i] == '_') |
325 |
39 |
name[i] = '-'; |
|
326 |
} |
||
327 |
|||
328 |
{ |
||
329 |
1866 |
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 |
✓✓✓✓ ✓✓✗✓ ✗✗✗✗ |
10135 |
while ((it = aliases_.find(name)) != aliases_.end() || |
336 |
✓✓✓✗ ✗✗ |
255 |
(equals_index != std::string::npos && |
337 |
✓✓✓✓ ✓✓✓✗ ✓✓✓✓ ✗✗✗✗ ✗✗ |
10328 |
(it = aliases_.find(name + '=')) != aliases_.end()) || |
338 |
✓✓✓✗ ✗✗ |
3735 |
(!args.empty() && |
339 |
✓✓✓✓ ✗✗ |
3586 |
!args.first().empty() && |
340 |
✓✓✗✓ ✗✗ |
3097 |
args.first()[0] != '-' && |
341 |
✗✗✓✓ ✓✓ |
3804 |
(it = aliases_.find(name + " <arg>")) != aliases_.end())) { |
342 |
1268 |
const std::string prev_name = std::move(name); |
|
343 |
635 |
const std::vector<std::string>& expansion = it->second; |
|
344 |
|||
345 |
// Use the first entry in the expansion as the new 'name'. |
||
346 |
635 |
name = expansion.front(); |
|
347 |
|||
348 |
✓✓✗✗ ✗✗ |
635 |
if (expansion.size() > 1) { |
349 |
// The other arguments, if any, are going to be handled later. |
||
350 |
591 |
args.synthetic_args.insert( |
|
351 |
394 |
args.synthetic_args.begin(), |
|
352 |
394 |
expansion.begin() + 1, |
|
353 |
expansion.end()); |
||
354 |
} |
||
355 |
|||
356 |
✓✓✓✓ ✗✗✗✗ ✗✗✗✗ |
635 |
if (name == prev_name) break; |
357 |
} |
||
358 |
} |
||
359 |
|||
360 |
1866 |
auto it = options_.find(name); |
|
361 |
|||
362 |
✓✓✓✓ ✓✓✗✓ ✗✗✗✗ |
5481 |
if ((it == options_.end() || |
363 |
✓✓✓✓ ✓✓✗✓ ✗✗✗✗ |
2961 |
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 |
1850 |
auto implications = implications_.equal_range(name); |
|
371 |
✓✓✗✓ ✗✗ |
2196 |
for (auto it = implications.first; it != implications.second; ++it) { |
372 |
✗✓✗✗ ✗✗ |
346 |
if (it->second.type == kV8Option) { |
373 |
v8_args->push_back(it->second.name); |
||
374 |
} else { |
||
375 |
692 |
*it->second.target_field->template Lookup<bool>(options) = |
|
376 |
346 |
it->second.target_value; |
|
377 |
} |
||
378 |
} |
||
379 |
} |
||
380 |
|||
381 |
✓✓✓✓ ✗✗ |
1850 |
if (it == options_.end()) { |
382 |
117 |
v8_args->push_back(arg); |
|
383 |
117 |
continue; |
|
384 |
} |
||
385 |
|||
386 |
1733 |
const OptionInfo& info = it->second; |
|
387 |
✓✓✓✓ ✓✓✗✗ ✗ |
3459 |
std::string value; |
388 |
✓✓✓✓ ✓✓✓✓ ✓✗✓✓ ✗✗✗✗ ✗✗ |
1733 |
if (info.type != kBoolean && info.type != kNoOp && info.type != kV8Option) { |
389 |
✓✓✓✓ ✗✗ |
731 |
if (equals_index != std::string::npos) { |
390 |
177 |
value = arg.substr(equals_index + 1); |
|
391 |
✓✓✗✓ ✗✗ |
177 |
if (value.empty()) { |
392 |
2 |
missing_argument(); |
|
393 |
2 |
break; |
|
394 |
} |
||
395 |
} else { |
||
396 |
✓✓✓✓ ✗✗ |
554 |
if (args.empty()) { |
397 |
5 |
missing_argument(); |
|
398 |
5 |
break; |
|
399 |
} |
||
400 |
|||
401 |
549 |
value = args.pop_first(); |
|
402 |
|||
403 |
✓✓✗✓ ✗✓✓✗ ✗✓✗✓ ✗✗✗✗ ✗✗ |
549 |
if (!value.empty() && value[0] == '-') { |
404 |
missing_argument(); |
||
405 |
break; |
||
406 |
} else { |
||
407 |
✓✓✓✓ ✓✗✓✓ ✓✗✗✓ ✗✗✗✓ ✗✗✗✗ ✗✗✗✗ |
549 |
if (!value.empty() && value[0] == '\\' && value[1] == '-') |
408 |
1 |
value = value.substr(1); // Treat \- as escaping an -. |
|
409 |
} |
||
410 |
} |
||
411 |
} |
||
412 |
|||
413 |
✓✓✓✓ ✓✓✓✓ ✗✓✓✓ ✓✓✗✗ ✓✗✗✗ ✗✗✗✗ ✗✗✗ |
1726 |
switch (info.type) { |
414 |
case kBoolean: |
||
415 |
954 |
*Lookup<bool>(info.field, options) = true; |
|
416 |
954 |
break; |
|
417 |
case kInteger: |
||
418 |
4 |
*Lookup<int64_t>(info.field, options) = std::atoll(value.c_str()); |
|
419 |
4 |
break; |
|
420 |
case kUInteger: |
||
421 |
31 |
*Lookup<uint64_t>(info.field, options) = std::stoull(value); |
|
422 |
31 |
break; |
|
423 |
case kString: |
||
424 |
533 |
*Lookup<std::string>(info.field, options) = value; |
|
425 |
533 |
break; |
|
426 |
case kStringList: |
||
427 |
56 |
Lookup<std::vector<std::string>>(info.field, options) |
|
428 |
56 |
->emplace_back(std::move(value)); |
|
429 |
56 |
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 |
47 |
v8_args->push_back(arg); |
|
438 |
✓✓✓✓ ✗✗ |
47 |
break; |
439 |
default: |
||
440 |
UNREACHABLE(); |
||
441 |
} |
||
442 |
} |
||
443 |
9410 |
options->CheckOptions(errors); |
|
444 |
9410 |
} |
|
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_ |
Generated by: GCOVR (Version 3.4) |