text: /*
  * (C) 2009,2010,2014,2015 Jack Lloyd
  * (C) 2017 René Korthaus, Rohde & Schwarz Cybersecurity
  *
  * Botan is released under the Simplified BSD License (see license.txt)
  */
  
  #include "cli.h"
  
  #include <botan/version.h>
  #include <botan/cpuid.h>
  #include <botan/internal/stl_util.h>
  #include <sstream>
  #include <iomanip>
  
  #if defined(BOTAN_HAS_HTTP_UTIL)
     #include <botan/http_util.h>
  #endif
  
  namespace Botan_CLI {
  
  class Print_Help final : public Command
     {
     public:
        Print_Help() : Command("help") {}
  
        std::string help_text() const override
           {
           std::map<std::string, std::vector<std::unique_ptr<Command>>> grouped_commands;
  
           auto reg_commands = Command::registered_cmds();
           for(const auto& cmd_name : reg_commands)
              {
              auto cmd = Command::get_cmd(cmd_name);
              if(cmd)
                 {
                 grouped_commands[cmd->group()].push_back(std::move(cmd));
                 }
              }
  
           const std::map<std::string, std::string> groups_description {
              { "encryption", "Encryption" },
              { "compression", "Compression" },
              { "codec", "Encoders/Decoders" },
              { "hash", "Hash Functions" },
              { "hmac", "HMAC" },
              { "info", "Informational" },
              { "numtheory", "Number Theory" },
              { "passhash", "Password Hashing" },
              { "psk", "PSK Database" },
              { "pubkey", "Public Key Cryptography" },
              { "tls", "TLS" },
              { "tss", "Secret Sharing" },
              { "x509", "X.509" },
              { "misc", "Miscellaneous" }
           };
  
        std::ostringstream oss;
  
        oss << "Usage: botan <cmd> <cmd-options>\n";
        oss << "All commands support --verbose --help --output= --error-output= --rng-type= --drbg-seed=\n\n";
        oss << "Available commands:\n\n";
  
        for(const auto& commands : grouped_commands)
           {
           std::string desc = commands.first;
           if(desc.empty())
              {
              continue;
              }
  
           oss << Botan::search_map(groups_description, desc, desc) << ":\n";
           for(auto& cmd : commands.second)
              {
              oss << "   " << std::setw(16) << std::left << cmd->cmd_name() << "   " << cmd->description() << "\n";
              }
           oss << "\n";
           }
  
        return oss.str();
        }
  
        std::string group() const override
           {
           return "";
           }
  
        std::string description() const override
           {
           return "Prints a help string";
           }
  
        void go() override
           {
           this->set_return_code(1);
           output() << help_text();
           }
     };
  
  BOTAN_REGISTER_COMMAND("help", Print_Help);
  
  class Has_Command final : public Command
     {
     public:
        Has_Command() : Command("has_command cmd") {}
  
        std::string group() const override
           {
           return "info";
           }
  
        std::string description() const override
           {
           return "Test if a command is available";
           }
  
        void go() override
           {
           const std::string cmd = get_arg("cmd");
  
           bool exists = false;
           for(auto registered_cmd : Command::registered_cmds())
              {
              if(cmd == registered_cmd)
                 {
                 exists = true;
                 break;
                 }
              }
  
           if(verbose())
              {
              output() << "Command '" << cmd << "' is "
                       << (exists ? "": "not ") << "available\n";
              }
  
           if(exists == false)
              this->set_return_code(1);
           }
     };
  
  BOTAN_REGISTER_COMMAND("has_command", Has_Command);
  
  class Config_Info final : public Command
     {
     public:
        Config_Info() : Command("config info_type") {}
  
        std::string help_text() const override
           {
           return "Usage: config info_type\n"
                  "   prefix: Print install prefix\n"
                  "   cflags: Print include params\n"
                  "   ldflags: Print linker params\n"
                  "   libs: Print libraries\n";
           }
  
        std::string group() const override
           {
           return "info";
           }
  
        std::string description() const override
           {
           return "Print the used prefix, cflags, ldflags or libs";
           }
  
        void go() override
           {
           const std::string arg = get_arg("info_type");
  
           if(arg == "prefix")
              {
              output() << BOTAN_INSTALL_PREFIX << "\n";
              }
           else if(arg == "cflags")
              {
              output() << "-I" << BOTAN_INSTALL_PREFIX << "/" << BOTAN_INSTALL_HEADER_DIR << "\n";
              }
           else if(arg == "ldflags")
              {
              if(*BOTAN_LINK_FLAGS)
                 output() << BOTAN_LINK_FLAGS << ' ';
              output() << "-L" << BOTAN_INSTALL_PREFIX << "/" << BOTAN_INSTALL_LIB_DIR << "\n";
              }
           else if(arg == "libs")
              {
              output() << "-lbotan-" << Botan::version_major() << " " << BOTAN_LIB_LINK << "\n";
              }
           else
              {
              throw CLI_Usage_Error("Unknown option to botan config " + arg);
              }
           }
     };
  
  BOTAN_REGISTER_COMMAND("config", Config_Info);
  
  class Version_Info final : public Command
     {
     public:
        Version_Info() : Command("version --full") {}
  
        std::string group() const override
           {
           return "info";
           }
  
        std::string description() const override
           {
           return "Print version info";
           }
  
        void go() override
           {
           if(flag_set("full"))
              {
              output() << Botan::version_string() << "\n";
              }
           else
              {
              output() << Botan::short_version_string() << "\n";
              }
           }
     };
  
  BOTAN_REGISTER_COMMAND("version", Version_Info);
  
  class Print_Cpuid final : public Command
     {
     public:
        Print_Cpuid() : Command("cpuid") {}
  
        std::string group() const override
           {
           return "info";
           }
  
        std::string description() const override
           {
           return "List available processor flags (aes_ni, SIMD extensions, ...)";
           }
  
        void go() override
           {
           output() << "CPUID flags: " << Botan::CPUID::to_string() << "\n";
           }
     };
  
  BOTAN_REGISTER_COMMAND("cpuid", Print_Cpuid);
  
  #if defined(BOTAN_HAS_HTTP_UTIL)
  
  class HTTP_Get final : public Command
     {
     public:
        HTTP_Get() : Command("http_get --redirects=1 --timeout=3000 url") {}
  
        std::string group() const override
           {
           return "misc";
           }
  
        std::string description() const override
           {
           return "Retrieve resource from the passed http/https url";
           }
  
        void go() override
           {
           const std::string url = get_arg("url");
           const std::chrono::milliseconds timeout(get_arg_sz("timeout"));
           const size_t redirects = get_arg_sz("redirects");
  
           output() << Botan::HTTP::GET_sync(url, redirects, timeout) << "\n";
           }
     };
  
  BOTAN_REGISTER_COMMAND("http_get", HTTP_Get);
  
  #endif // http_util
  
  }
  