| // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| #ifndef RUNTIME_BIN_OPTIONS_H_ | |
| #define RUNTIME_BIN_OPTIONS_H_ | |
| #include "bin/dartutils.h" | |
| #include "platform/globals.h" | |
| #include "platform/hashmap.h" | |
| #include "platform/syslog.h" | |
| #include "platform/utils.h" | |
| namespace dart { | |
| namespace bin { | |
| typedef bool (*OptionProcessorCallback)(const char* arg, | |
| CommandLineOptions* vm_options); | |
| class OptionProcessor { | |
| public: | |
| OptionProcessor() : next_(first_) { first_ = this; } | |
| virtual ~OptionProcessor() {} | |
| // Returns true if name starts with "--". | |
| static bool IsValidFlag(const char* name); | |
| // Returns true if name starts with "-". | |
| static bool IsValidShortFlag(const char* name); | |
| virtual bool Process(const char* option, CommandLineOptions* options) = 0; | |
| static bool TryProcess(const char* option, CommandLineOptions* options); | |
| static const char* ProcessOption(const char* option, const char* name); | |
| static bool ProcessEnvironmentOption(const char* arg, | |
| CommandLineOptions* vm_options, | |
| dart::SimpleHashMap** environment); | |
| private: | |
| static OptionProcessor* first_; | |
| OptionProcessor* next_; | |
| DISALLOW_ALLOCATION(); | |
| DISALLOW_COPY_AND_ASSIGN(OptionProcessor); | |
| }; | |
| class CallbackOptionProcessor : public OptionProcessor { | |
| public: | |
| explicit CallbackOptionProcessor(OptionProcessorCallback cb) : cb_(cb) {} | |
| virtual bool Process(const char* option, CommandLineOptions* vm_options) { | |
| return cb_(option, vm_options); | |
| } | |
| private: | |
| OptionProcessorCallback cb_; | |
| }; | |
| #define DEFINE_CB_OPTION(callback) \ | |
| static CallbackOptionProcessor option_##callback(&callback); | |
| #define DEFINE_STRING_OPTION_CB(name, callback) \ | |
| class OptionProcessor_##name : public OptionProcessor { \ | |
| public: \ | |
| virtual bool Process(const char* option, CommandLineOptions* vm_options) { \ | |
| const char* value = \ | |
| OptionProcessor::ProcessOption(option, "--" #name "="); \ | |
| if (value == nullptr) { \ | |
| return false; \ | |
| } \ | |
| if (*value == '\0') { \ | |
| Syslog::PrintErr("Empty value for option " #name "\n"); \ | |
| return false; \ | |
| } \ | |
| callback; \ | |
| return true; \ | |
| } \ | |
| }; \ | |
| static OptionProcessor_##name option_##name; | |
| #define DEFINE_STRING_OPTION(name, variable) \ | |
| DEFINE_STRING_OPTION_CB(name, { variable = value; }) | |
| #define DEFINE_STRING_LIST_OPTION(name, variable) \ | |
| DEFINE_STRING_OPTION_CB(name, { \ | |
| const char* token = value; \ | |
| while (true) { \ | |
| const char* comma = strchr(token, ','); \ | |
| if (comma != nullptr) { \ | |
| if (comma > token) { \ | |
| variable.Add(Utils::StrNDup(token, comma - token)); \ | |
| } \ | |
| token = comma + 1; \ | |
| } else { \ | |
| if (*token != '\0') { \ | |
| variable.Add(Utils::StrDup(token)); \ | |
| } \ | |
| break; \ | |
| } \ | |
| } \ | |
| }) | |
| #define DEFINE_ENUM_OPTION(name, enum_name, variable) \ | |
| DEFINE_STRING_OPTION_CB(name, { \ | |
| const char* const* kNames = k##enum_name##Names; \ | |
| for (intptr_t i = 0; kNames[i] != nullptr; i++) { \ | |
| if (strcmp(value, kNames[i]) == 0) { \ | |
| variable = static_cast<enum_name>(i); \ | |
| return true; \ | |
| } \ | |
| } \ | |
| Syslog::PrintErr( \ | |
| "Unrecognized value for " #name ": '%s'\nValid values are: ", value); \ | |
| for (intptr_t i = 0; kNames[i] != nullptr; i++) { \ | |
| Syslog::PrintErr("%s%s", i > 0 ? ", " : "", kNames[i]); \ | |
| } \ | |
| Syslog::PrintErr("\n"); \ | |
| }) | |
| #define DEFINE_BOOL_OPTION_CB(name, callback) \ | |
| class OptionProcessor_##name : public OptionProcessor { \ | |
| public: \ | |
| virtual bool Process(const char* option, CommandLineOptions* vm_options) { \ | |
| const char* value = OptionProcessor::ProcessOption(option, "--" #name); \ | |
| if (value == nullptr) { \ | |
| return false; \ | |
| } \ | |
| if (*value == '=') { \ | |
| Syslog::PrintErr("Non-empty value for option " #name "\n"); \ | |
| return false; \ | |
| } \ | |
| if (*value != '\0') { \ | |
| return false; \ | |
| } \ | |
| callback(vm_options); \ | |
| return true; \ | |
| } \ | |
| }; \ | |
| static OptionProcessor_##name option_##name; | |
| #define DEFINE_BOOL_OPTION(name, variable) \ | |
| class OptionProcessor_##name : public OptionProcessor { \ | |
| public: \ | |
| virtual bool Process(const char* option, CommandLineOptions* vm_options) { \ | |
| const char* value = OptionProcessor::ProcessOption(option, "--" #name); \ | |
| if (value == nullptr) { \ | |
| return false; \ | |
| } \ | |
| if (*value == '=') { \ | |
| Syslog::PrintErr("Non-empty value for option " #name "\n"); \ | |
| return false; \ | |
| } \ | |
| if (*value != '\0') { \ | |
| return false; \ | |
| } \ | |
| variable = true; \ | |
| return true; \ | |
| } \ | |
| }; \ | |
| static OptionProcessor_##name option_##name; | |
| #define DEFINE_BOOL_OPTION_SHORT(short_name, long_name, variable) \ | |
| class OptionProcessor_##long_name : public OptionProcessor { \ | |
| public: \ | |
| virtual bool Process(const char* option, CommandLineOptions* vm_options) { \ | |
| const char* value = \ | |
| OptionProcessor::ProcessOption(option, "-" #short_name); \ | |
| if (value == nullptr) { \ | |
| value = OptionProcessor::ProcessOption(option, "--" #long_name); \ | |
| } \ | |
| if (value == nullptr) { \ | |
| return false; \ | |
| } \ | |
| if (*value == '=') { \ | |
| Syslog::PrintErr("Non-empty value for option " #long_name "\n"); \ | |
| return false; \ | |
| } \ | |
| if (*value != '\0') { \ | |
| return false; \ | |
| } \ | |
| variable = true; \ | |
| return true; \ | |
| } \ | |
| }; \ | |
| static OptionProcessor_##long_name option_##long_name; | |
| } // namespace bin | |
| } // namespace dart | |
| #endif // RUNTIME_BIN_OPTIONS_H_ |