/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ // Generic command line flags system for NSS BoGo shim. This class // could actually in principle handle other programs. The flags are // defined in the consumer code. #ifndef config_h_ #define config_h_ #include <cassert> #include <iostream> #include <map> #include <memory> #include <queue> #include <string> #include <typeinfo> // Abstract base class for a given config flag. class ConfigEntryBase { public: ConfigEntryBase(const std::string& nm, const std::string& typ) : name_(nm), type_(typ) {} virtual ~ConfigEntryBase() {} const std::string& type() const { return type_; } virtual bool Parse(std::queue<const char*>& args) = 0; protected: bool ParseInternal(std::queue<const char*>& args, std::vector<int>& out); bool ParseInternal(std::queue<const char*>& args, std::string& out); bool ParseInternal(std::queue<const char*>& args, int& out); bool ParseInternal(std::queue<const char*>& args, bool& out); const std::string name_; const std::string type_; }; // Template specializations for the concrete flag types. template <typename T> class ConfigEntry : public ConfigEntryBase { public: ConfigEntry(const std::string& name, T init) : ConfigEntryBase(name, typeid(T).name()), value_(init) {} T get() const { return value_; } bool Parse(std::queue<const char*>& args) { return ParseInternal(args, value_); } private: T value_; }; // The overall configuration (I.e., the total set of flags). class Config { public: enum Status { kOK, kUnknownFlag, kMalformedArgument, kMissingValue }; Config() : entries_() {} template <typename T> void AddEntry(const std::string& name, T init) { entries_[name] = std::unique_ptr<ConfigEntryBase>(new ConfigEntry<T>(name, init)); } Status ParseArgs(int argc, char** argv); template <typename T> T get(const std::string& key) const { auto e = entry(key); assert(e->type() == typeid(T).name()); return static_cast<const ConfigEntry<T>*>(e)->get(); } private: static std::string XformFlag(const std::string& arg); std::map<std::string, std::unique_ptr<ConfigEntryBase>> entries_; const ConfigEntryBase* entry(const std::string& key) const { auto e = entries_.find(key); if (e == entries_.end()) return nullptr; return e->second.get(); } }; #endif // config_h_