1// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_BIN_OPTIONS_H_
6#define RUNTIME_BIN_OPTIONS_H_
7
8#include "bin/dartutils.h"
9#include "platform/globals.h"
10#include "platform/hashmap.h"
11#include "platform/syslog.h"
12
13namespace dart {
14namespace bin {
15
16typedef bool (*OptionProcessorCallback)(const char* arg,
17 CommandLineOptions* vm_options);
18
19class OptionProcessor {
20 public:
21 OptionProcessor() : next_(first_) { first_ = this; }
22
23 virtual ~OptionProcessor() {}
24
25 static bool IsValidFlag(const char* name,
26 const char* prefix,
27 intptr_t prefix_length);
28
29 virtual bool Process(const char* option, CommandLineOptions* options) = 0;
30
31 static bool TryProcess(const char* option, CommandLineOptions* options);
32
33 static const char* ProcessOption(const char* option, const char* name);
34
35 static bool ProcessEnvironmentOption(const char* arg,
36 CommandLineOptions* vm_options,
37 dart::SimpleHashMap** environment);
38
39 private:
40 static OptionProcessor* first_;
41 OptionProcessor* next_;
42
43 DISALLOW_ALLOCATION();
44 DISALLOW_COPY_AND_ASSIGN(OptionProcessor);
45};
46
47class CallbackOptionProcessor : public OptionProcessor {
48 public:
49 explicit CallbackOptionProcessor(OptionProcessorCallback cb) : cb_(cb) {}
50 virtual bool Process(const char* option, CommandLineOptions* vm_options) {
51 return cb_(option, vm_options);
52 }
53
54 private:
55 OptionProcessorCallback cb_;
56};
57
58#define DEFINE_CB_OPTION(callback) \
59 static CallbackOptionProcessor option_##callback(&callback);
60
61#define DEFINE_STRING_OPTION_CB(name, callback) \
62 class OptionProcessor_##name : public OptionProcessor { \
63 public: \
64 virtual bool Process(const char* option, CommandLineOptions* vm_options) { \
65 const char* value = \
66 OptionProcessor::ProcessOption(option, "--" #name "="); \
67 if (value == NULL) { \
68 return false; \
69 } \
70 if (*value == '\0') { \
71 Syslog::PrintErr("Empty value for option " #name "\n"); \
72 return false; \
73 } \
74 callback; \
75 return true; \
76 } \
77 }; \
78 static OptionProcessor_##name option_##name;
79
80#define DEFINE_STRING_OPTION(name, variable) \
81 DEFINE_STRING_OPTION_CB(name, { variable = value; })
82
83#define DEFINE_ENUM_OPTION(name, enum_name, variable) \
84 DEFINE_STRING_OPTION_CB(name, { \
85 const char** kNames = k##enum_name##Names; \
86 for (intptr_t i = 0; kNames[i] != NULL; i++) { \
87 if (strcmp(value, kNames[i]) == 0) { \
88 variable = static_cast<enum_name>(i); \
89 return true; \
90 } \
91 } \
92 Syslog::PrintErr( \
93 "Unrecognized value for " #name ": '%s'\nValid values are: ", value); \
94 for (intptr_t i = 0; kNames[i] != NULL; i++) { \
95 Syslog::PrintErr("%s%s", i > 0 ? ", " : "", kNames[i]); \
96 } \
97 Syslog::PrintErr("\n"); \
98 })
99
100#define DEFINE_BOOL_OPTION_CB(name, callback) \
101 class OptionProcessor_##name : public OptionProcessor { \
102 public: \
103 virtual bool Process(const char* option, CommandLineOptions* vm_options) { \
104 const char* value = OptionProcessor::ProcessOption(option, "--" #name); \
105 if (value == NULL) { \
106 return false; \
107 } \
108 if (*value == '=') { \
109 Syslog::PrintErr("Non-empty value for option " #name "\n"); \
110 return false; \
111 } \
112 if (*value != '\0') { \
113 return false; \
114 } \
115 callback(vm_options); \
116 return true; \
117 } \
118 }; \
119 static OptionProcessor_##name option_##name;
120
121#define DEFINE_BOOL_OPTION(name, variable) \
122 class OptionProcessor_##name : public OptionProcessor { \
123 public: \
124 virtual bool Process(const char* option, CommandLineOptions* vm_options) { \
125 const char* value = OptionProcessor::ProcessOption(option, "--" #name); \
126 if (value == NULL) { \
127 return false; \
128 } \
129 if (*value == '=') { \
130 Syslog::PrintErr("Non-empty value for option " #name "\n"); \
131 return false; \
132 } \
133 if (*value != '\0') { \
134 return false; \
135 } \
136 variable = true; \
137 return true; \
138 } \
139 }; \
140 static OptionProcessor_##name option_##name;
141
142#define DEFINE_BOOL_OPTION_SHORT(short_name, long_name, variable) \
143 class OptionProcessor_##long_name : public OptionProcessor { \
144 public: \
145 virtual bool Process(const char* option, CommandLineOptions* vm_options) { \
146 const char* value = \
147 OptionProcessor::ProcessOption(option, "-" #short_name); \
148 if (value == NULL) { \
149 value = OptionProcessor::ProcessOption(option, "--" #long_name); \
150 } \
151 if (value == NULL) { \
152 return false; \
153 } \
154 if (*value == '=') { \
155 Syslog::PrintErr("Non-empty value for option " #long_name "\n"); \
156 return false; \
157 } \
158 if (*value != '\0') { \
159 return false; \
160 } \
161 variable = true; \
162 return true; \
163 } \
164 }; \
165 static OptionProcessor_##long_name option_##long_name;
166
167} // namespace bin
168} // namespace dart
169
170#endif // RUNTIME_BIN_OPTIONS_H_
171