<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <iostream>

#include "ast/Printer.hpp"

#include "variant.hpp"
#include "assert.hpp"
#include "VisitorUtils.hpp"
#include "Variable.hpp"

using namespace eddic;

namespace {

std::string toStringType(ast::Type type){
    if(auto* ptr = boost::get<ast::SimpleType>(&type)){
        return ptr->type;
    } else if(auto* ptr = boost::get<ast::ArrayType>(&type)){
        return ptr->type + "[]";
    } else if(auto* ptr = boost::get<ast::PointerType>(&type)){
        return ptr->type + "*";
    } else {
        ASSERT_PATH_NOT_TAKEN("Unhandled type");
    }
}

struct DebugVisitor : public boost::static_visitor<> {
    mutable int level = 0;

    std::string indent() const {
        std::string acc = "";
        for(int i = 0; i < level; ++i){
            acc += "    ";
        }
        return acc;
    }

    template<typename Container>
    void print_each_sub(Container& container) const {
        level++;
        visit_each(*this, container);
        level--;
    }

    template<typename Container>
    void print_each_sub(Container& container, const std::string& title) const {
        std::cout << indent() << title << std::endl;
        print_each_sub(container);
    }

    template<typename Container>
    void print_each_sub_non_variant(Container& container) const {
        level++;
        visit_each_non_variant(*this, container);
        level--;
    }

    template<typename Container>
    void print_each_sub_non_variant(Container& container, const std::string& title) const {
        std::cout << indent() << title << std::endl;
        print_each_sub_non_variant(container);
    }

    template<typename Container>
    void print_sub(Container& container) const {
        level++;
        visit(*this, container);
        level--;
    }

    template<typename Container>
    void print_sub(Container& container, const std::string& title) const {
        std::cout << indent() << title << std::endl;
        print_sub(container);
    }

    void operator()(ast::SourceFile& program) const {
        print_each_sub(program.Content->blocks, "SourceFile");
    }

    void operator()(ast::Import& import) const {
        std::cout << indent() << "include \"" << import.file << "\"" << std::endl;
    }

    void operator()(ast::StandardImport& import) const {
        std::cout << indent() << "include <" << import.header << ">" << std::endl;
    }

    void operator()(ast::TemplateFunctionDeclaration& declaration) const {
        std::cout << indent() << "Template Function <";

        for(auto type : declaration.Content->template_types){
            std::cout << type << ", ";
        }

        std::cout << ">" << declaration.Content->functionName << std::endl;
    }

    void operator()(ast::FunctionDeclaration& declaration) const {
        std::cout << indent() << "Function " << declaration.Content->functionName << std::endl;

        std::cout << indent() << "Parameters:" << std::endl;
        level++;
        for(auto param : declaration.Content->parameters){
            std::cout << indent() << param.parameterName << std::endl;
        }
        level--;

        print_each_sub(declaration.Content->instructions, "Instructions:");
    }

    void operator()(ast::Constructor& declaration) const {
        std::cout << indent() << "Constructor" << std::endl;

        std::cout << indent() << "Parameters:" << std::endl;
        level++;
        for(auto param : declaration.Content->parameters){
            std::cout << indent() << param.parameterName << std::endl;
        }
        level--;

        print_each_sub(declaration.Content->instructions, "Instructions:");
    }

    void operator()(ast::Destructor& declaration) const {
        std::cout << indent() << "Destructor" << std::endl;
        print_each_sub(declaration.Content->instructions, "Instructions:");
    }

    void operator()(ast::Struct& struct_) const {
        std::cout << indent() << "Structure declaration: " << struct_.Content->name << std::endl;
        level++;

        print_each_sub_non_variant(struct_.Content->members, "Members");
        print_each_sub_non_variant(struct_.Content->constructors, "Constructors");
        print_each_sub_non_variant(struct_.Content->destructors, "Destructors");
        print_each_sub_non_variant(struct_.Content->functions, "Functions");

        level--;
    }

    void operator()(ast::MemberDeclaration& declaration) const {
        std::cout << indent() << toStringType(declaration.Content->type)  << " " << declaration.Content->name << std::endl;
    }

    void operator()(ast::GlobalVariableDeclaration&) const {
        std::cout << indent() << "Global Variable" << std::endl;
    }

    void operator()(ast::GlobalArrayDeclaration&) const {
        std::cout << indent() << "Global Array" << std::endl;
    }

    void operator()(ast::New& new_) const {
        std::cout << indent() << "New " << toStringType(new_.Content->type) << std::endl;
        print_each_sub(new_.Content->values, "Value");
    }

    void operator()(ast::Delete& delete_) const {
        std::cout << indent() << "Delete " << delete_.Content->variable_name << std::endl;
    }

    void operator()(ast::For& for_) const {
        print_each_sub(for_.Content->instructions, "For");
    }

    void operator()(ast::Foreach& for_) const {
        print_each_sub(for_.Content->instructions, "Foreach");
    }

    void operator()(ast::ForeachIn& for_) const {
        print_each_sub(for_.Content->instructions, "Foreach In");
    }

    void operator()(ast::Switch& switch_) const {
        std::cout << indent() << "Switch " << std::endl;

        ++level;

        print_sub(switch_.Content->value, "Value");

        for(auto& case_ : switch_.Content->cases){
            visit_non_variant(*this, case_);
        }

        if(switch_.Content->default_case){
            visit_non_variant(*this, *switch_.Content->default_case);
        }

        --level;
    }

    void operator()(ast::SwitchCase& switch_case) const {
        std::cout << indent() << "Case" << std::endl;

        ++level;

        print_sub(switch_case.value, "Value");
        print_each_sub(switch_case.instructions, "Instructions");

        --level;
    }

    void operator()(ast::DefaultCase& default_case) const {
        print_each_sub(default_case.instructions, "Default Case");
    }

    void operator()(ast::While& while_) const {
        std::cout << indent() << "While" << std::endl;
        print_sub(while_.Content->condition, "Condition:");
        print_each_sub(while_.Content->instructions, "Instructions:");
    }

    void operator()(ast::DoWhile& while_) const {
        std::cout << indent() << "Do while" << std::endl;
        print_sub(while_.Content->condition, "Condition:");
        print_each_sub(while_.Content->instructions, "Instructions:");
    }

    void operator()(ast::Swap&) const {
        std::cout << indent() << "Swap" << std::endl;
    }

    void operator()(ast::If& if_) const {
        std::cout << indent() << "If" << std::endl;

        print_sub(if_.Content->condition, "Condition");
        print_each_sub(if_.Content->instructions, "Instructions");

        for(auto& else_if : if_.Content->elseIfs){
            std::cout << indent() << "ElseIf" << std::endl;

            print_sub(else_if.condition, "Condition");
            print_each_sub(else_if.instructions, "Instructions");
        }

        if(if_.Content->else_){
            std::cout << indent() << "Else" << std::endl;

            print_each_sub((*if_.Content->else_).instructions, "Instructions");
        }
    }

    void operator()(ast::FunctionCall& call) const {
        std::cout << indent() << "FunctionCall " << call.Content->functionName << std::endl;
        print_each_sub(call.Content->values);
    }

    void operator()(ast::MemberFunctionCall& call) const {
        std::cout << indent() << "Member FunctionCall " << call.Content->object_name << "." << call.Content->function_name << std::endl;
        print_each_sub(call.Content->values);
    }

    void operator()(ast::BuiltinOperator& builtin) const {
        std::cout << indent() << "Builtin Operator " << (int) builtin.Content->type << std::endl;
        print_each_sub(builtin.Content->values);
    }

    void operator()(ast::StructDeclaration& declaration) const {
        std::cout << indent() << "Struct declaration [" << declaration.Content->variableName << "]" << std::endl;

        print_each_sub(declaration.Content->values, "Values");
    }

    void operator()(ast::VariableDeclaration& declaration) const {
        std::cout << indent() << "Variable declaration [" << declaration.Content->variableName << "]" << std::endl;

        if(declaration.Content->value){
            print_sub(*declaration.Content->value);
        }
    }

    void operator()(ast::ArrayDeclaration&) const {
        std::cout << indent() << "Array declaration" << std::endl;
    }

    void operator()(ast::SuffixOperation& op) const {
        std::cout << indent() << "(suffix)" << (int)op.Content->op << std::endl;

        print_sub(op.Content->left_value, "Left Value");
    }

    void operator()(ast::PrefixOperation& op) const {
        std::cout << indent() << (int)op.Content->op << "(prefix)" << std::endl;

        print_sub(op.Content->left_value, "Left Value");
    }

    void operator()(ast::Assignment& assign) const {
        std::cout << indent() << "Assignment [operator = " << static_cast<int>(assign.Content->op) << " ] " << std::endl;

        print_sub(assign.Content->left_value, "Left Value");
        print_sub(assign.Content->value, "Right Value");
    }

    void operator()(ast::Ternary& ternary) const {
        std::cout << indent() << "Ternary" << std::endl;

        print_sub(ternary.Content->condition, "Condition");
        print_sub(ternary.Content->true_value, "True Value");
        print_sub(ternary.Content->false_value, "False Value");
    }

    void operator()(ast::Return& return_) const {
        print_sub(return_.Content->value, "Function Return");
    }

    void operator()(ast::Literal& literal) const {
        std::cout << indent() << "Literal [" << literal.value << "]" << std::endl;
    }

    void operator()(ast::CharLiteral& literal) const {
        std::cout << indent() << "Char Literal [" << literal.value << "]" << std::endl;
    }

    void operator()(ast::Integer& integer) const {
        std::cout << indent() << "Integer [" << integer.value << "]" << std::endl;
    }

    void operator()(ast::IntegerSuffix& integer) const {
        std::cout << indent() << "Float (suffix) [" << integer.value << "f]" << std::endl;
    }

    void operator()(ast::Float& float_) const {
        std::cout << indent() << "Float [" << float_.value << "]" << std::endl;
    }

    void operator()(ast::True&) const {
        std::cout << indent() << "true" << std::endl;
    }

    void operator()(ast::Null&) const {
        std::cout << indent() << "null" << std::endl;
    }

    void operator()(ast::False&) const {
        std::cout << indent() << "false" << std::endl;
    }

    void operator()(ast::VariableValue& value) const {
        std::cout << indent() << "Variable " << value.Content->var->name() << std::endl;
    }

    void operator()(ast::MemberValue& value) const {
        std::cout << indent() << "Member Value ";

        for(auto& member : value.Content->memberNames){
            std::cout << "." << member;
        }

        std::cout << std::endl;

        print_sub(value.Content->location, "Location");
    }

    void operator()(ast::DereferenceValue& value) const {
        std::cout << indent() << "Dereference Variable Value" << std::endl;;

        print_sub(value.Content->ref, "Left Value");
    }

    void operator()(ast::ArrayValue& value) const {
        std::cout << indent() << "Array value [" << value.Content->arrayName << "]" << std::endl;
        print_sub(value.Content->indexValue);
    }

    void operator()(ast::Expression& value) const {
        std::cout << indent() << "Expression [" << value.Content->operations.size() << "]" << std::endl;
        ++level;
        visit(*this, value.Content->first);
        for(auto& operation : value.Content->operations){
            std::cout << indent() << (int) operation.get<0>() << std::endl;
            visit(*this, operation.get<1>());
        }
        --level;
    }

    void operator()(ast::Unary& value) const {
        std::cout << indent() << "Unary " << static_cast<int>(value.Content->op) << std::endl;
        print_sub(value.Content->value);
    }

    void operator()(ast::Cast& cast) const {
        std::cout << indent() << "Cast " << std::endl;
        std::cout << indent() << "\tType: " << toStringType(cast.Content->type) << std::endl;
        print_sub(cast.Content->value);
    }
};

} //end of anonymous namespace

void ast::Printer::print(SourceFile& program){
    DebugVisitor visitor;
    visit_non_variant(visitor, program);
}
<commit_msg>Cleanup output of the AST Printer<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <iostream>

#include "ast/Printer.hpp"

#include "variant.hpp"
#include "assert.hpp"
#include "VisitorUtils.hpp"
#include "Variable.hpp"

using namespace eddic;

namespace {

std::string toStringType(ast::Type type){
    if(auto* ptr = boost::get<ast::SimpleType>(&type)){
        return ptr->type;
    } else if(auto* ptr = boost::get<ast::ArrayType>(&type)){
        return ptr->type + "[]";
    } else if(auto* ptr = boost::get<ast::PointerType>(&type)){
        return ptr->type + "*";
    } else {
        ASSERT_PATH_NOT_TAKEN("Unhandled type");
    }
}

struct DebugVisitor : public boost::static_visitor<> {
    mutable int level = 0;

    std::string indent() const {
        std::string acc = "";
        for(int i = 0; i < level; ++i){
            acc += "    ";
        }
        return acc;
    }

    template<typename Container>
    void print_each_sub(Container& container) const {
        level++;
        visit_each(*this, container);
        level--;
    }

    template<typename Container>
    void print_each_sub(Container& container, const std::string& title) const {
        std::cout << indent() << title << std::endl;
        print_each_sub(container);
    }

    template<typename Container>
    void print_each_sub_non_variant(Container& container) const {
        level++;
        visit_each_non_variant(*this, container);
        level--;
    }

    template<typename Container>
    void print_each_sub_non_variant(Container& container, const std::string& title) const {
        std::cout << indent() << title << std::endl;
        print_each_sub_non_variant(container);
    }

    template<typename Container>
    void print_sub(Container& container) const {
        level++;
        visit(*this, container);
        level--;
    }

    template<typename Container>
    void print_sub(Container& container, const std::string& title) const {
        std::cout << indent() << title << std::endl;
        print_sub(container);
    }

    void operator()(ast::SourceFile& program) const {
        print_each_sub(program.Content->blocks, "SourceFile");
    }

    void operator()(ast::Import& import) const {
        std::cout << indent() << "include \"" << import.file << "\"" << std::endl;
    }

    void operator()(ast::StandardImport& import) const {
        std::cout << indent() << "include <" << import.header << ">" << std::endl;
    }

    void operator()(ast::TemplateFunctionDeclaration& declaration) const {
        std::cout << indent() << "Template Function <";

        for(auto type : declaration.Content->template_types){
            std::cout << type << ", ";
        }

        std::cout << ">" << declaration.Content->functionName << std::endl;
        std::cout << std::endl;
    }

    void operator()(ast::FunctionDeclaration& declaration) const {
        std::cout << indent() << "Function " << declaration.Content->functionName << std::endl;

        std::cout << indent() << "Parameters:" << std::endl;
        level++;
        for(auto param : declaration.Content->parameters){
            std::cout << indent() << param.parameterName << std::endl;
        }
        level--;

        print_each_sub(declaration.Content->instructions, "Instructions:");
        std::cout << std::endl;
    }

    void operator()(ast::Constructor& declaration) const {
        std::cout << indent() << "Constructor" << std::endl;

        std::cout << indent() << "Parameters:" << std::endl;
        level++;
        for(auto param : declaration.Content->parameters){
            std::cout << indent() << param.parameterName << std::endl;
        }
        level--;

        print_each_sub(declaration.Content->instructions, "Instructions:");
    }

    void operator()(ast::Destructor& declaration) const {
        std::cout << indent() << "Destructor" << std::endl;
        print_each_sub(declaration.Content->instructions, "Instructions:");
    }

    void operator()(ast::Struct& struct_) const {
        std::cout << indent() << "Structure declaration: " << struct_.Content->name << std::endl;
        level++;

        print_each_sub_non_variant(struct_.Content->members, "Members");
        print_each_sub_non_variant(struct_.Content->constructors, "Constructors");
        print_each_sub_non_variant(struct_.Content->destructors, "Destructors");
        print_each_sub_non_variant(struct_.Content->functions, "Functions");

        level--;
    }

    void operator()(ast::MemberDeclaration& declaration) const {
        std::cout << indent() << toStringType(declaration.Content->type)  << " " << declaration.Content->name << std::endl;
    }

    void operator()(ast::GlobalVariableDeclaration&) const {
        std::cout << indent() << "Global Variable" << std::endl;
    }

    void operator()(ast::GlobalArrayDeclaration&) const {
        std::cout << indent() << "Global Array" << std::endl;
    }

    void operator()(ast::New& new_) const {
        std::cout << indent() << "New " << toStringType(new_.Content->type) << std::endl;
        print_each_sub(new_.Content->values, "Value");
    }

    void operator()(ast::Delete& delete_) const {
        std::cout << indent() << "Delete " << delete_.Content->variable_name << std::endl;
    }

    void operator()(ast::For& for_) const {
        print_each_sub(for_.Content->instructions, "For");
    }

    void operator()(ast::Foreach& for_) const {
        print_each_sub(for_.Content->instructions, "Foreach");
    }

    void operator()(ast::ForeachIn& for_) const {
        print_each_sub(for_.Content->instructions, "Foreach In");
    }

    void operator()(ast::Switch& switch_) const {
        std::cout << indent() << "Switch " << std::endl;

        ++level;

        print_sub(switch_.Content->value, "Value");

        for(auto& case_ : switch_.Content->cases){
            visit_non_variant(*this, case_);
        }

        if(switch_.Content->default_case){
            visit_non_variant(*this, *switch_.Content->default_case);
        }

        --level;
    }

    void operator()(ast::SwitchCase& switch_case) const {
        std::cout << indent() << "Case" << std::endl;

        ++level;

        print_sub(switch_case.value, "Value");
        print_each_sub(switch_case.instructions, "Instructions");

        --level;
    }

    void operator()(ast::DefaultCase& default_case) const {
        print_each_sub(default_case.instructions, "Default Case");
    }

    void operator()(ast::While& while_) const {
        std::cout << indent() << "While" << std::endl;
        print_sub(while_.Content->condition, "Condition:");
        print_each_sub(while_.Content->instructions, "Instructions:");
    }

    void operator()(ast::DoWhile& while_) const {
        std::cout << indent() << "Do while" << std::endl;
        print_sub(while_.Content->condition, "Condition:");
        print_each_sub(while_.Content->instructions, "Instructions:");
    }

    void operator()(ast::Swap&) const {
        std::cout << indent() << "Swap" << std::endl;
    }

    void operator()(ast::If& if_) const {
        std::cout << indent() << "If" << std::endl;

        print_sub(if_.Content->condition, "Condition");
        print_each_sub(if_.Content->instructions, "Instructions");

        for(auto& else_if : if_.Content->elseIfs){
            std::cout << indent() << "ElseIf" << std::endl;

            print_sub(else_if.condition, "Condition");
            print_each_sub(else_if.instructions, "Instructions");
        }

        if(if_.Content->else_){
            std::cout << indent() << "Else" << std::endl;

            print_each_sub((*if_.Content->else_).instructions, "Instructions");
        }
    }

    void operator()(ast::FunctionCall& call) const {
        std::cout << indent() << "FunctionCall " << call.Content->functionName << std::endl;
        print_each_sub(call.Content->values);
    }

    void operator()(ast::MemberFunctionCall& call) const {
        std::cout << indent() << "Member FunctionCall " << call.Content->object_name << "." << call.Content->function_name << std::endl;
        print_each_sub(call.Content->values);
    }

    void operator()(ast::BuiltinOperator& builtin) const {
        std::cout << indent() << "Builtin Operator " << (int) builtin.Content->type << std::endl;
        print_each_sub(builtin.Content->values);
    }

    void operator()(ast::StructDeclaration& declaration) const {
        std::cout << indent() << "Struct declaration [" << declaration.Content->variableName << "]" << std::endl;

        print_each_sub(declaration.Content->values, "Values");
    }

    void operator()(ast::VariableDeclaration& declaration) const {
        std::cout << indent() << "Variable declaration [" << declaration.Content->variableName << "]" << std::endl;

        if(declaration.Content->value){
            print_sub(*declaration.Content->value);
        }
    }

    void operator()(ast::ArrayDeclaration&) const {
        std::cout << indent() << "Array declaration" << std::endl;
    }

    void operator()(ast::SuffixOperation& op) const {
        std::cout << indent() << "(suffix)" << (int)op.Content->op << std::endl;

        print_sub(op.Content->left_value, "Left Value");
    }

    void operator()(ast::PrefixOperation& op) const {
        std::cout << indent() << (int)op.Content->op << "(prefix)" << std::endl;

        print_sub(op.Content->left_value, "Left Value");
    }

    void operator()(ast::Assignment& assign) const {
        std::cout << indent() << "Assignment [operator = " << static_cast<int>(assign.Content->op) << " ] " << std::endl;

        print_sub(assign.Content->left_value, "Left Value");
        print_sub(assign.Content->value, "Right Value");
    }

    void operator()(ast::Ternary& ternary) const {
        std::cout << indent() << "Ternary" << std::endl;

        print_sub(ternary.Content->condition, "Condition");
        print_sub(ternary.Content->true_value, "True Value");
        print_sub(ternary.Content->false_value, "False Value");
    }

    void operator()(ast::Return& return_) const {
        print_sub(return_.Content->value, "Function Return");
    }

    void operator()(ast::Literal& literal) const {
        std::cout << indent() << "Literal [" << literal.value << "]" << std::endl;
    }

    void operator()(ast::CharLiteral& literal) const {
        std::cout << indent() << "Char Literal [" << literal.value << "]" << std::endl;
    }

    void operator()(ast::Integer& integer) const {
        std::cout << indent() << "Integer [" << integer.value << "]" << std::endl;
    }

    void operator()(ast::IntegerSuffix& integer) const {
        std::cout << indent() << "Float (suffix) [" << integer.value << "f]" << std::endl;
    }

    void operator()(ast::Float& float_) const {
        std::cout << indent() << "Float [" << float_.value << "]" << std::endl;
    }

    void operator()(ast::True&) const {
        std::cout << indent() << "true" << std::endl;
    }

    void operator()(ast::Null&) const {
        std::cout << indent() << "null" << std::endl;
    }

    void operator()(ast::False&) const {
        std::cout << indent() << "false" << std::endl;
    }

    void operator()(ast::VariableValue& value) const {
        std::cout << indent() << "Variable " << value.Content->var->name() << std::endl;
    }

    void operator()(ast::MemberValue& value) const {
        std::cout << indent() << "Member Value ";

        for(auto& member : value.Content->memberNames){
            std::cout << "." << member;
        }

        std::cout << std::endl;

        print_sub(value.Content->location, "Location");
    }

    void operator()(ast::DereferenceValue& value) const {
        std::cout << indent() << "Dereference Variable Value" << std::endl;;

        print_sub(value.Content->ref, "Left Value");
    }

    void operator()(ast::ArrayValue& value) const {
        std::cout << indent() << "Array value [" << value.Content->arrayName << "]" << std::endl;
        print_sub(value.Content->indexValue);
    }

    void operator()(ast::Expression& value) const {
        std::cout << indent() << "Expression [" << value.Content->operations.size() << "]" << std::endl;
        ++level;
        visit(*this, value.Content->first);
        for(auto& operation : value.Content->operations){
            std::cout << indent() << (int) operation.get<0>() << std::endl;
            visit(*this, operation.get<1>());
        }
        --level;
    }

    void operator()(ast::Unary& value) const {
        std::cout << indent() << "Unary " << static_cast<int>(value.Content->op) << std::endl;
        print_sub(value.Content->value);
    }

    void operator()(ast::Cast& cast) const {
        std::cout << indent() << "Cast " << std::endl;
        std::cout << indent() << "\tType: " << toStringType(cast.Content->type) << std::endl;
        print_sub(cast.Content->value);
    }
};

} //end of anonymous namespace

void ast::Printer::print(SourceFile& program){
    DebugVisitor visitor;
    visit_non_variant(visitor, program);
}
<|endoftext|>


<commit_before>/*
* Runtime CPU detection for ARM
* (C) 2009,2010,2013,2017 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/cpuid.h>

#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)

#if defined(BOTAN_TARGET_OS_IS_IOS)
  #include <sys/types.h>
  #include <sys/sysctl.h>

#else
  #include <botan/internal/os_utils.h>

#endif

#endif

namespace Botan {

#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)

#if defined(BOTAN_TARGET_OS_IS_IOS)

namespace {

uint64_t flags_by_ios_machine_type(const std::string& machine)
   {
   /*
   * This relies on a map of known machine names to features. This
   * will quickly grow out of date as new products are introduced, but
   * is apparently the best we can do for iOS.
   */

   struct version_info {
      std::string name;
      size_t min_version_neon;
      size_t min_version_armv8;
      };

   static const version_info min_versions[] = {
      { "iPhone", 2, 6 },
      { "iPad", 1, 4 },
      { "iPod", 4, 7 },
      { "AppleTV", 2, 5 },
   };

   if(machine.size() < 3)
      return 0;

   auto comma = machine.find(',');

   // Simulator, or something we don't know about
   if(comma == std::string::npos)
      return 0;

   std::string product = machine.substr(0, comma);

   size_t version = 0;
   size_t place = 1;
   while(product.size() > 1 && ::isdigit(product.back()))
      {
      const size_t digit = product.back() - '0';
      version += digit * place;
      place *= 10;
      product.pop_back();
      }

   if(version == 0)
      return 0;

   for(const version_info& info : min_versions)
      {
      if(info.name != product)
         continue;

      if(version >= info.min_version_armv8)
         {
         return CPUID::CPUID_ARM_AES_BIT |
                CPUID::CPUID_ARM_PMULL_BIT |
                CPUID::CPUID_ARM_SHA1_BIT |
                CPUID::CPUID_ARM_SHA2_BIT |
                CPUID::CPUID_ARM_NEON_BIT;
         }

      if(version >= info.min_version_neon)
         return CPUID::CPUID_ARM_NEON_BIT;
      }

   // Some other product we don't know about
   return 0;
   }

}

#endif

uint64_t CPUID::CPUID_Data::detect_cpu_features(size_t* cache_line_size)
   {
   uint64_t detected_features = 0;

#if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) || defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO)
   /*
   * On systems with getauxval these bits should normally be defined
   * in bits/auxv.h but some buggy? glibc installs seem to miss them.
   * These following values are all fixed, for the Linux ELF format,
   * so we just hardcode them in ARM_hwcap_bit enum.
   */

   enum ARM_hwcap_bit {
#if defined(BOTAN_TARGET_ARCH_IS_ARM32)
      NEON_bit  = (1 << 12),
      AES_bit   = (1 << 0),
      PMULL_bit = (1 << 1),
      SHA1_bit  = (1 << 2),
      SHA2_bit  = (1 << 3),

      ARCH_hwcap_neon   = 16, // AT_HWCAP
      ARCH_hwcap_crypto = 26, // AT_HWCAP2
#elif defined(BOTAN_TARGET_ARCH_IS_ARM64)
      NEON_bit  = (1 << 1),
      AES_bit   = (1 << 3),
      PMULL_bit = (1 << 4),
      SHA1_bit  = (1 << 5),
      SHA2_bit  = (1 << 6),
      SHA3_bit  = (1 << 17),
      SM3_bit  = (1 << 18),
      SM4_bit  = (1 << 19),
      SHA2_512_bit  = (1 << 21),
      SVE_bit = (1 << 22),

      ARCH_hwcap_neon   = 16, // AT_HWCAP
      ARCH_hwcap_crypto = 16, // AT_HWCAP
#endif
   };

#if defined(AT_DCACHEBSIZE)
   // Exists only on Linux
   const unsigned long dcache_line = ::getauxval(AT_DCACHEBSIZE);

   // plausibility check
   if(dcache_line == 32 || dcache_line == 64 || dcache_line == 128)
      *cache_line_size = static_cast<size_t>(dcache_line);
#else
   BOTAN_UNUSED(cache_line_size);
#endif

   const unsigned long hwcap_neon = OS::get_auxval(ARM_hwcap_bit::ARCH_hwcap_neon);
   if(hwcap_neon & ARM_hwcap_bit::NEON_bit)
      detected_features |= CPUID::CPUID_ARM_NEON_BIT;

   /*
   On aarch64 this ends up calling getauxval twice with AT_HWCAP
   It doesn't seem worth optimizing this out, since getauxval is
   just reading a field in the ELF header.
   */
   const unsigned long hwcap_crypto = OS::get_auxval(ARM_hwcap_bit::ARCH_hwcap_crypto);
   if(hwcap_crypto & ARM_hwcap_bit::AES_bit)
      detected_features |= CPUID::CPUID_ARM_AES_BIT;
   if(hwcap_crypto & ARM_hwcap_bit::PMULL_bit)
      detected_features |= CPUID::CPUID_ARM_PMULL_BIT;
   if(hwcap_crypto & ARM_hwcap_bit::SHA1_bit)
      detected_features |= CPUID::CPUID_ARM_SHA1_BIT;
   if(hwcap_crypto & ARM_hwcap_bit::SHA2_bit)
      detected_features |= CPUID::CPUID_ARM_SHA2_BIT;

#if defined(BOTAN_TARGET_ARCH_IS_ARM64)
   if(hwcap_crypto & ARM_hwcap_bit::SHA3_bit)
      detected_features |= CPUID::CPUID_ARM_SHA3_BIT;
   if(hwcap_crypto & ARM_hwcap_bit::SM3_bit)
      detected_features |= CPUID::CPUID_ARM_SM3_BIT;
   if(hwcap_crypto & ARM_hwcap_bit::SM4_bit)
      detected_features |= CPUID::CPUID_ARM_SM4_BIT;
   if(hwcap_crypto & ARM_hwcap_bit::SHA2_512_bit)
      detected_features |= CPUID::CPUID_ARM_SHA2_512_BIT;
   if(hwcap_crypto & ARM_hwcap_bit::SVE_bit)
      detected_features |= CPUID::CPUID_ARM_SVE_BIT;
#endif

#elif defined(BOTAN_TARGET_OS_IS_IOS)

   char machine[64] = { 0 };
   size_t size = sizeof(machine) - 1;
   ::sysctlbyname("hw.machine", machine, &size, nullptr, 0);

   detected_features = flags_by_ios_machine_type(machine);

#elif defined(BOTAN_USE_GCC_INLINE_ASM) && defined(BOTAN_TARGET_ARCH_IS_ARM64)

   /*
   No getauxval API available, fall back on probe functions. We only
   bother with Aarch64 here to simplify the code and because going to
   extreme contortions to support detect NEON on devices that probably
   don't support it doesn't seem worthwhile.

   NEON registers v0-v7 are caller saved in Aarch64
   */

   auto neon_probe  = []() noexcept -> int { asm("and v0.16b, v0.16b, v0.16b"); return 1; };
   auto aes_probe   = []() noexcept -> int { asm(".word 0x4e284800"); return 1; };
   auto pmull_probe = []() noexcept -> int { asm(".word 0x0ee0e000"); return 1; };
   auto sha1_probe  = []() noexcept -> int { asm(".word 0x5e280800"); return 1; };
   auto sha2_probe  = []() noexcept -> int { asm(".word 0x5e282800"); return 1; };

   // Only bother running the crypto detection if we found NEON

   if(OS::run_cpu_instruction_probe(neon_probe) == 1)
      {
      detected_features |= CPUID::CPUID_ARM_NEON_BIT;

      if(OS::run_cpu_instruction_probe(aes_probe) == 1)
         detected_features |= CPUID::CPUID_ARM_AES_BIT;
      if(OS::run_cpu_instruction_probe(pmull_probe) == 1)
         detected_features |= CPUID::CPUID_ARM_PMULL_BIT;
      if(OS::run_cpu_instruction_probe(sha1_probe) == 1)
         detected_features |= CPUID::CPUID_ARM_SHA1_BIT;
      if(OS::run_cpu_instruction_probe(sha2_probe) == 1)
         detected_features |= CPUID::CPUID_ARM_SHA2_BIT;
      }

#endif

   return detected_features;
   }

#endif

}
<commit_msg>Fix an unused var warning when compiling for iOS<commit_after>/*
* Runtime CPU detection for ARM
* (C) 2009,2010,2013,2017 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/cpuid.h>

#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)

#if defined(BOTAN_TARGET_OS_IS_IOS)
  #include <sys/types.h>
  #include <sys/sysctl.h>

#else
  #include <botan/internal/os_utils.h>

#endif

#endif

namespace Botan {

#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)

#if defined(BOTAN_TARGET_OS_IS_IOS)

namespace {

uint64_t flags_by_ios_machine_type(const std::string& machine)
   {
   /*
   * This relies on a map of known machine names to features. This
   * will quickly grow out of date as new products are introduced, but
   * is apparently the best we can do for iOS.
   */

   struct version_info {
      std::string name;
      size_t min_version_neon;
      size_t min_version_armv8;
      };

   static const version_info min_versions[] = {
      { "iPhone", 2, 6 },
      { "iPad", 1, 4 },
      { "iPod", 4, 7 },
      { "AppleTV", 2, 5 },
   };

   if(machine.size() < 3)
      return 0;

   auto comma = machine.find(',');

   // Simulator, or something we don't know about
   if(comma == std::string::npos)
      return 0;

   std::string product = machine.substr(0, comma);

   size_t version = 0;
   size_t place = 1;
   while(product.size() > 1 && ::isdigit(product.back()))
      {
      const size_t digit = product.back() - '0';
      version += digit * place;
      place *= 10;
      product.pop_back();
      }

   if(version == 0)
      return 0;

   for(const version_info& info : min_versions)
      {
      if(info.name != product)
         continue;

      if(version >= info.min_version_armv8)
         {
         return CPUID::CPUID_ARM_AES_BIT |
                CPUID::CPUID_ARM_PMULL_BIT |
                CPUID::CPUID_ARM_SHA1_BIT |
                CPUID::CPUID_ARM_SHA2_BIT |
                CPUID::CPUID_ARM_NEON_BIT;
         }

      if(version >= info.min_version_neon)
         return CPUID::CPUID_ARM_NEON_BIT;
      }

   // Some other product we don't know about
   return 0;
   }

}

#endif

uint64_t CPUID::CPUID_Data::detect_cpu_features(size_t* cache_line_size)
   {
   uint64_t detected_features = 0;

#if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) || defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO)
   /*
   * On systems with getauxval these bits should normally be defined
   * in bits/auxv.h but some buggy? glibc installs seem to miss them.
   * These following values are all fixed, for the Linux ELF format,
   * so we just hardcode them in ARM_hwcap_bit enum.
   */

   enum ARM_hwcap_bit {
#if defined(BOTAN_TARGET_ARCH_IS_ARM32)
      NEON_bit  = (1 << 12),
      AES_bit   = (1 << 0),
      PMULL_bit = (1 << 1),
      SHA1_bit  = (1 << 2),
      SHA2_bit  = (1 << 3),

      ARCH_hwcap_neon   = 16, // AT_HWCAP
      ARCH_hwcap_crypto = 26, // AT_HWCAP2
#elif defined(BOTAN_TARGET_ARCH_IS_ARM64)
      NEON_bit  = (1 << 1),
      AES_bit   = (1 << 3),
      PMULL_bit = (1 << 4),
      SHA1_bit  = (1 << 5),
      SHA2_bit  = (1 << 6),
      SHA3_bit  = (1 << 17),
      SM3_bit  = (1 << 18),
      SM4_bit  = (1 << 19),
      SHA2_512_bit  = (1 << 21),
      SVE_bit = (1 << 22),

      ARCH_hwcap_neon   = 16, // AT_HWCAP
      ARCH_hwcap_crypto = 16, // AT_HWCAP
#endif
   };

#if defined(AT_DCACHEBSIZE)
   // Exists only on Linux
   const unsigned long dcache_line = ::getauxval(AT_DCACHEBSIZE);

   // plausibility check
   if(dcache_line == 32 || dcache_line == 64 || dcache_line == 128)
      *cache_line_size = static_cast<size_t>(dcache_line);
#else
   BOTAN_UNUSED(cache_line_size);
#endif

   const unsigned long hwcap_neon = OS::get_auxval(ARM_hwcap_bit::ARCH_hwcap_neon);
   if(hwcap_neon & ARM_hwcap_bit::NEON_bit)
      detected_features |= CPUID::CPUID_ARM_NEON_BIT;

   /*
   On aarch64 this ends up calling getauxval twice with AT_HWCAP
   It doesn't seem worth optimizing this out, since getauxval is
   just reading a field in the ELF header.
   */
   const unsigned long hwcap_crypto = OS::get_auxval(ARM_hwcap_bit::ARCH_hwcap_crypto);
   if(hwcap_crypto & ARM_hwcap_bit::AES_bit)
      detected_features |= CPUID::CPUID_ARM_AES_BIT;
   if(hwcap_crypto & ARM_hwcap_bit::PMULL_bit)
      detected_features |= CPUID::CPUID_ARM_PMULL_BIT;
   if(hwcap_crypto & ARM_hwcap_bit::SHA1_bit)
      detected_features |= CPUID::CPUID_ARM_SHA1_BIT;
   if(hwcap_crypto & ARM_hwcap_bit::SHA2_bit)
      detected_features |= CPUID::CPUID_ARM_SHA2_BIT;

#if defined(BOTAN_TARGET_ARCH_IS_ARM64)
   if(hwcap_crypto & ARM_hwcap_bit::SHA3_bit)
      detected_features |= CPUID::CPUID_ARM_SHA3_BIT;
   if(hwcap_crypto & ARM_hwcap_bit::SM3_bit)
      detected_features |= CPUID::CPUID_ARM_SM3_BIT;
   if(hwcap_crypto & ARM_hwcap_bit::SM4_bit)
      detected_features |= CPUID::CPUID_ARM_SM4_BIT;
   if(hwcap_crypto & ARM_hwcap_bit::SHA2_512_bit)
      detected_features |= CPUID::CPUID_ARM_SHA2_512_BIT;
   if(hwcap_crypto & ARM_hwcap_bit::SVE_bit)
      detected_features |= CPUID::CPUID_ARM_SVE_BIT;
#endif

#elif defined(BOTAN_TARGET_OS_IS_IOS)

   char machine[64] = { 0 };
   size_t size = sizeof(machine) - 1;
   ::sysctlbyname("hw.machine", machine, &size, nullptr, 0);

   detected_features = flags_by_ios_machine_type(machine);
   // No way to detect this on iOS?
   BOTAN_UNUSED(cache_line_size);

#elif defined(BOTAN_USE_GCC_INLINE_ASM) && defined(BOTAN_TARGET_ARCH_IS_ARM64)

   /*
   No getauxval API available, fall back on probe functions. We only
   bother with Aarch64 here to simplify the code and because going to
   extreme contortions to support detect NEON on devices that probably
   don't support it doesn't seem worthwhile.

   NEON registers v0-v7 are caller saved in Aarch64
   */

   auto neon_probe  = []() noexcept -> int { asm("and v0.16b, v0.16b, v0.16b"); return 1; };
   auto aes_probe   = []() noexcept -> int { asm(".word 0x4e284800"); return 1; };
   auto pmull_probe = []() noexcept -> int { asm(".word 0x0ee0e000"); return 1; };
   auto sha1_probe  = []() noexcept -> int { asm(".word 0x5e280800"); return 1; };
   auto sha2_probe  = []() noexcept -> int { asm(".word 0x5e282800"); return 1; };

   // Only bother running the crypto detection if we found NEON

   if(OS::run_cpu_instruction_probe(neon_probe) == 1)
      {
      detected_features |= CPUID::CPUID_ARM_NEON_BIT;

      if(OS::run_cpu_instruction_probe(aes_probe) == 1)
         detected_features |= CPUID::CPUID_ARM_AES_BIT;
      if(OS::run_cpu_instruction_probe(pmull_probe) == 1)
         detected_features |= CPUID::CPUID_ARM_PMULL_BIT;
      if(OS::run_cpu_instruction_probe(sha1_probe) == 1)
         detected_features |= CPUID::CPUID_ARM_SHA1_BIT;
      if(OS::run_cpu_instruction_probe(sha2_probe) == 1)
         detected_features |= CPUID::CPUID_ARM_SHA2_BIT;
      }

   BOTAN_UNUSED(cache_line_size);

#endif

   return detected_features;
   }

#endif

}
<|endoftext|>


<commit_before>/*
* Runtime CPU detection for POWER/PowerPC
* (C) 2009,2010,2013,2017 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/cpuid.h>
#include <botan/internal/os_utils.h>

#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)

/*
* On Darwin and OpenBSD ppc, use sysctl to detect AltiVec
*/
#if defined(BOTAN_TARGET_OS_IS_DARWIN)
  #include <sys/sysctl.h>
#elif defined(BOTAN_TARGET_OS_IS_OPENBSD)
  #include <sys/param.h>
  #include <sys/sysctl.h>
  #include <machine/cpu.h>
#elif defined(BOTAN_TARGET_OS_HAS_GETAUXVAL)
  #include <sys/auxv.h>
#endif

#endif

namespace Botan {

#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)

/*
* PowerPC specific block: check for AltiVec using either
* sysctl or by reading processor version number register.
*/
uint64_t CPUID::detect_cpu_features(size_t* cache_line_size)
   {
#if defined(BOTAN_TARGET_OS_IS_DARWIN) || defined(BOTAN_TARGET_OS_IS_OPENBSD)
   // On Darwin/OS X and OpenBSD, use sysctl

   int sels[2] = {
#if defined(BOTAN_TARGET_OS_IS_OPENBSD)
      CTL_MACHDEP, CPU_ALTIVEC
#else
      CTL_HW, HW_VECTORUNIT
#endif
   };

   int vector_type = 0;
   size_t length = sizeof(vector_type);
   int error = ::sysctl(sels, 2, &vector_type, &length, NULL, 0);

   if(error == 0 && vector_type > 0)
      return CPUID::CPUID_ALTIVEC_BIT;

#elif defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) && defined(BOTAN_TARGET_ARCH_IS_PPC64)

   enum PPC_hwcap_bit {
      ALTIVEC_bit  = (1 << 28),
      CRYPTO_bit   = (1 << 25),

      ARCH_hwcap_altivec = 16, // AT_HWCAP
      ARCH_hwcap_crypto  = 26, // AT_HWCAP2
   };

   uint64_t detected_features = 0;

   const unsigned long hwcap_altivec = ::getauxval(PPC_hwcap_bit::ARCH_hwcap_altivec);
   if(hwcap_altivec & PPC_hwcap_bit::ALTIVEC_bit)
      detected_features |= CPUID::CPUID_ALTIVEC_BIT;

   const unsigned long hwcap_crypto = ::getauxval(PPC_hwcap_bit::ARCH_hwcap_crypto);
   if(hwcap_crypto & PPC_hwcap_bit::CRYPTO_bit)
     detected_features |= CPUID::CPUID_PPC_CRYPTO_BIT;

   return detected_features;

#else

   /*
   On PowerPC, MSR 287 is PVR, the Processor Version Number
   Normally it is only accessible to ring 0, but Linux and NetBSD
   (others, too, maybe?) will trap and emulate it for us.
   */

   int pvr = OS::run_cpu_instruction_probe([]() -> int {
      uint32_t pvr = 0;
      asm volatile("mfspr %0, 287" : "=r" (pvr));
      // Top 16 bits suffice to identify the model
      return static_cast<int>(pvr >> 16);
      });

   if(pvr > 0)
      {
      const uint16_t ALTIVEC_PVR[] = {
         0x003E, // IBM POWER6
         0x003F, // IBM POWER7
         0x004A, // IBM POWER7p
         0x004D, // IBM POWER8
         0x004B, // IBM POWER8E
         0x000C, // G4-7400
         0x0039, // G5 970
         0x003C, // G5 970FX
         0x0044, // G5 970MP
         0x0070, // Cell PPU
         0, // end
      };

      for(size_t i = 0; ALTIVEC_PVR[i]; ++i)
         {
         if(pvr == ALTIVEC_PVR[i])
            return CPUID::CPUID_ALTIVEC_BIT;
         }

      return 0;
      }

   // TODO try direct instruction probing

#endif

   return 0;
   }

#endif

}
<commit_msg>Avoid unused arg warning in PowerPC CPUID code<commit_after>/*
* Runtime CPU detection for POWER/PowerPC
* (C) 2009,2010,2013,2017 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/cpuid.h>
#include <botan/internal/os_utils.h>

#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)

/*
* On Darwin and OpenBSD ppc, use sysctl to detect AltiVec
*/
#if defined(BOTAN_TARGET_OS_IS_DARWIN)
  #include <sys/sysctl.h>
#elif defined(BOTAN_TARGET_OS_IS_OPENBSD)
  #include <sys/param.h>
  #include <sys/sysctl.h>
  #include <machine/cpu.h>
#elif defined(BOTAN_TARGET_OS_HAS_GETAUXVAL)
  #include <sys/auxv.h>
#endif

#endif

namespace Botan {

#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)

/*
* PowerPC specific block: check for AltiVec using either
* sysctl or by reading processor version number register.
*/
uint64_t CPUID::detect_cpu_features(size_t* cache_line_size)
   {
   BOTAN_UNUSED(cache_line_size);

#if defined(BOTAN_TARGET_OS_IS_DARWIN) || defined(BOTAN_TARGET_OS_IS_OPENBSD)
   // On Darwin/OS X and OpenBSD, use sysctl

   int sels[2] = {
#if defined(BOTAN_TARGET_OS_IS_OPENBSD)
      CTL_MACHDEP, CPU_ALTIVEC
#else
      CTL_HW, HW_VECTORUNIT
#endif
   };

   int vector_type = 0;
   size_t length = sizeof(vector_type);
   int error = ::sysctl(sels, 2, &vector_type, &length, NULL, 0);

   if(error == 0 && vector_type > 0)
      return CPUID::CPUID_ALTIVEC_BIT;

#elif defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) && defined(BOTAN_TARGET_ARCH_IS_PPC64)

   enum PPC_hwcap_bit {
      ALTIVEC_bit  = (1 << 28),
      CRYPTO_bit   = (1 << 25),

      ARCH_hwcap_altivec = 16, // AT_HWCAP
      ARCH_hwcap_crypto  = 26, // AT_HWCAP2
   };

   uint64_t detected_features = 0;

   const unsigned long hwcap_altivec = ::getauxval(PPC_hwcap_bit::ARCH_hwcap_altivec);
   if(hwcap_altivec & PPC_hwcap_bit::ALTIVEC_bit)
      detected_features |= CPUID::CPUID_ALTIVEC_BIT;

   const unsigned long hwcap_crypto = ::getauxval(PPC_hwcap_bit::ARCH_hwcap_crypto);
   if(hwcap_crypto & PPC_hwcap_bit::CRYPTO_bit)
     detected_features |= CPUID::CPUID_PPC_CRYPTO_BIT;

   return detected_features;

#else

   /*
   On PowerPC, MSR 287 is PVR, the Processor Version Number
   Normally it is only accessible to ring 0, but Linux and NetBSD
   (others, too, maybe?) will trap and emulate it for us.
   */

   int pvr = OS::run_cpu_instruction_probe([]() -> int {
      uint32_t pvr = 0;
      asm volatile("mfspr %0, 287" : "=r" (pvr));
      // Top 16 bits suffice to identify the model
      return static_cast<int>(pvr >> 16);
      });

   if(pvr > 0)
      {
      const uint16_t ALTIVEC_PVR[] = {
         0x003E, // IBM POWER6
         0x003F, // IBM POWER7
         0x004A, // IBM POWER7p
         0x004D, // IBM POWER8
         0x004B, // IBM POWER8E
         0x000C, // G4-7400
         0x0039, // G5 970
         0x003C, // G5 970FX
         0x0044, // G5 970MP
         0x0070, // Cell PPU
         0, // end
      };

      for(size_t i = 0; ALTIVEC_PVR[i]; ++i)
         {
         if(pvr == ALTIVEC_PVR[i])
            return CPUID::CPUID_ALTIVEC_BIT;
         }

      return 0;
      }

   // TODO try direct instruction probing

#endif

   return 0;
   }

#endif

}
<|endoftext|>


<commit_before>#include "atcommander.h"

constexpr char ATCommander::OK[];
constexpr char ATCommander::AT[];
constexpr char ATCommander::ERROR[];
constexpr char ATCommander::WHITESPACE_NEWLINE[];

#define FEATURE_OK_ERROR_CHECK

bool ATCommander::check_for_ok()
{
    const char* OK_OR_ERROR[] = { ERROR, OK, nullptr };

    ignore_whitespace_and_newlines();

#ifdef FEATURE_OK_ERROR_CHECK
    const char* result = input_match(OK_OR_ERROR);

    skip_newline();

    if(result == OK)
    {
        return true;
    }
    else
    {
        error.set_at_result();
        return false;
    }
#else
    // Old check for OK only code
    bool got_ok = input_match(OK);
    if(!got_ok) return false;
    skip_newline();
#endif
}

#ifdef FEATURE_ATC_PEEK
#define OLD_WHITESPACE_IGNORE
#endif

void ATCommander::ignore_whitespace_and_newlines()
{
#ifdef OLD_WHITESPACE_IGNORE
    char ch;

    while(is_match(ch = get(), WHITESPACE_NEWLINE));

    unget(ch);
#else
    int ch;

    while((ch = peek_timeout_experimental()) != EOF)
    {
        if (is_match((char)ch, WHITESPACE_NEWLINE))
            get();
        else
            return;
    }
#endif
}

// TODO: upgrade istream to do this using std::ws manipulator ala
// https://stackoverflow.com/questions/13501862/how-to-properly-use-cin-peek
void ATCommander::ignore_whitespace()
{
#ifdef OLD_WHITESPACE_IGNORE
    char ch;

    while((ch = get()) == ' ');

    unget(ch);
#else
    int ch;

    while(!ch_valid_data(ch = peek_timeout_experimental()))
    {
        if(ch == ' ')
            get();
        else
            return;
    }
#endif
}

// TODO: rename this to input_newline
bool ATCommander::skip_newline()
{
    // look for CRLF, LFCR, or LF alone.  CR alone not supported at this time
    ignore_whitespace();
#ifdef OLD_WHITESPACE_IGNORE
    char ch = get();
    if(ch == 13)
    {
        ch = get();
        if(ch == 10)
        {
            return true;
        }

        unget(ch);
    }
    else if(ch == 10)
    {
        // WARNING: may not be 100% POSIX compliant!
        ch = cin.peek();

        if (ch == 13)
            ch = get();

        return true;
    }

#else
    int ch = peek_timeout_experimental();

    if(ch == 13)
    {
        get();
        if(peek_timeout_experimental() == 10)
        {
            get();
            return true;
        }
    }
    else if(ch == 10)
    {
        get();
        if(getsome() == 13)
        //if(peek_timeout_experimental() == 13)
            get();

        // FIX: It's possible that peek() doesn't have CR *yet* and
        // a subsequent call to this function will result in a false
        // since CR alone isn't considered a newline for this particular
        // function
        // HOWEVER
        // if we do a timeout here, it frequently burns a lot of time since we are ending on
        // a newline
        return true;
    }
#endif

    return false;
}

// retrieves a text string in input up to max size
// leaves any discovered delimiter cached
size_t ATCommander::input(char* input, size_t max)
{
    int ch;
    size_t len = 0;

#ifdef FEATURE_ATC_PEEK
    while(!is_delimiter(ch = get()) && len < max && ch != -1)
    {
        *input++ = ch;
        len++;
    }

    // FIX: check if input can be assigned to still
    // (ensure we haven't exceeded max)
    *input = 0;

    if(ch != -1)
        // FIX: be sure to check len also
        unget(ch);
#else
    while((ch = peek_timeout_experimental()) != EOF)
    {
        if(len >= max || is_delimiter(ch)) break;

        get();

        *input++ = ch;
        len++;
    }

    // FIX: check if input can be assigned to still
    // (ensure we haven't exceeded max)
    *input = 0;
#endif

    return len;
}

void ATCommander::do_assign(const char *cmd)
{
    do_command(cmd);
    cout.put('=');
}

/*
template <>
ATCommander& ATCommander::operator>>(const char* matchValue)
{
    if(!input_match(matchValue))
    {
        set_error("match", matchValue);
    }
    return *this;
}
*/

/*
template <>
ATCommander& ATCommander::operator>>(char* inputValue)
{
    input(inputValue, 100);
    return *this;
}
*/
/*
template <>
bool ATCommander::input(const char*& input)
{
    // be sure to FAIL here
    //static_assert("Cannot input into a static pointer");
    return false;
} */

void ATCommander::do_request_prefix(const char *cmd)
{
    send_request(cmd);
    recv_request_echo_prefix(cmd);
}

namespace layer3 {

const char* MultiMatcher::do_match(const char* input, const char** keywords)
{
    const char* keyword;

    while((keyword = *keywords++))
    {
        if(strcmp(keyword, input) == 0) return keyword;
    }

    return nullptr;
}

bool MultiMatcher::parse(char c)
{
    const char** _keyword = &keywords[vpos];
    const char* keyword;

    // If we still have keywords to inspect
    while((keyword = *_keyword) != nullptr)
    {
        char ch = *(keyword + hpos);
        // see if this particular keyword at this particular horizontal
        // position IN the keyword matches incoming c
        if(ch == c)
        {
            // If so, bump hpos up as we have a "so far" match and prep
            // for the next one
            hpos++;
            return true;
        }
        else if(c == 13)
        {
            // FIX: eating CR for now, but we can do better (parse it out before we get here)
            return true;
        }
        else if(ch == 0) // reaching ch == 0 here means we DID get a match, technically
        {
            match = true;
            // but we might want to keep looking to make a more "greedy" match (longer keyword, if available)

            // TODO: make incoming terminator more configurable
            if(c == 10)
            {
                // if we get here it means both incoming character and our own keyword
                // are at their delimiters, meaning an exact match
                // and we're done
                return false;
            }

            // TODO: greedy match mode not yet implemented, will involve fiddling with vpos
            // i.e. only bumping it forward if we really want to abandon this match
            return false;
        }

        // if no match, then move forward (alphabetically)
        // down the line
        vpos++;
        _keyword++;

        // NOTE: this is what makes alphabetical ordering important
        // if we don't get a match, we compare the current const match to the
        // next potential const match to see if the prefix
        // at least matches so that we can then compare a suffix.  If prefix does
        // NOT match, that means we are done - again, things must be alphabetical
        // for that to work
        if (memcmp(keyword, *_keyword, hpos) != 0) return false;
    }

    // if we get to the end, then definitely no match
    return false;
}

}
<commit_msg>Repaired my glitchy whitespace ignore function<commit_after>#include "atcommander.h"

constexpr char ATCommander::OK[];
constexpr char ATCommander::AT[];
constexpr char ATCommander::ERROR[];
constexpr char ATCommander::WHITESPACE_NEWLINE[];

#define FEATURE_OK_ERROR_CHECK

bool ATCommander::check_for_ok()
{
    const char* OK_OR_ERROR[] = { ERROR, OK, nullptr };

    ignore_whitespace_and_newlines();

#ifdef FEATURE_OK_ERROR_CHECK
    const char* result = input_match(OK_OR_ERROR);

    skip_newline();

    if(result == OK)
    {
        return true;
    }
    else
    {
        error.set_at_result();
        return false;
    }
#else
    // Old check for OK only code
    bool got_ok = input_match(OK);
    if(!got_ok) return false;
    skip_newline();
#endif
}

#ifdef FEATURE_ATC_PEEK
#define OLD_WHITESPACE_IGNORE
#endif

void ATCommander::ignore_whitespace_and_newlines()
{
#ifdef OLD_WHITESPACE_IGNORE
    char ch;

    while(is_match(ch = get(), WHITESPACE_NEWLINE));

    unget(ch);
#else
    int ch;

    while((ch = peek_timeout_experimental()) != EOF)
    {
        if (is_match((char)ch, WHITESPACE_NEWLINE))
            get();
        else
            return;
    }
#endif
}

// TODO: upgrade istream to do this using std::ws manipulator ala
// https://stackoverflow.com/questions/13501862/how-to-properly-use-cin-peek
void ATCommander::ignore_whitespace()
{
#ifdef OLD_WHITESPACE_IGNORE
    char ch;

    while((ch = get()) == ' ');

    unget(ch);
#else
    int ch;

    while((ch = peek_timeout_experimental()) && ch == ' ')
        cin.ignore();
#endif
}

// TODO: rename this to input_newline
bool ATCommander::skip_newline()
{
    // look for CRLF, LFCR, or LF alone.  CR alone not supported at this time
    ignore_whitespace();
#ifdef OLD_WHITESPACE_IGNORE
    char ch = get();
    if(ch == 13)
    {
        ch = get();
        if(ch == 10)
        {
            return true;
        }

        unget(ch);
    }
    else if(ch == 10)
    {
        // WARNING: may not be 100% POSIX compliant!
        ch = cin.peek();

        if (ch == 13)
            ch = get();

        return true;
    }

#else
    int ch = peek_timeout_experimental();

    if(ch == 13)
    {
        get();
        if(peek_timeout_experimental() == 10)
        {
            get();
            return true;
        }
    }
    else if(ch == 10)
    {
        get();
        if(getsome() == 13)
        //if(peek_timeout_experimental() == 13)
            get();

        // FIX: It's possible that peek() doesn't have CR *yet* and
        // a subsequent call to this function will result in a false
        // since CR alone isn't considered a newline for this particular
        // function
        // HOWEVER
        // if we do a timeout here, it frequently burns a lot of time since we are ending on
        // a newline
        return true;
    }
#endif

    return false;
}

// retrieves a text string in input up to max size
// leaves any discovered delimiter cached
size_t ATCommander::input(char* input, size_t max)
{
    int ch;
    size_t len = 0;

#ifdef FEATURE_ATC_PEEK
    while(!is_delimiter(ch = get()) && len < max && ch != -1)
    {
        *input++ = ch;
        len++;
    }

    // FIX: check if input can be assigned to still
    // (ensure we haven't exceeded max)
    *input = 0;

    if(ch != -1)
        // FIX: be sure to check len also
        unget(ch);
#else
    while((ch = peek_timeout_experimental()) != EOF)
    {
        if(len >= max || is_delimiter(ch)) break;

        get();

        *input++ = ch;
        len++;
    }

    // FIX: check if input can be assigned to still
    // (ensure we haven't exceeded max)
    *input = 0;
#endif

    return len;
}

void ATCommander::do_assign(const char *cmd)
{
    do_command(cmd);
    cout.put('=');
}

/*
template <>
ATCommander& ATCommander::operator>>(const char* matchValue)
{
    if(!input_match(matchValue))
    {
        set_error("match", matchValue);
    }
    return *this;
}
*/

/*
template <>
ATCommander& ATCommander::operator>>(char* inputValue)
{
    input(inputValue, 100);
    return *this;
}
*/
/*
template <>
bool ATCommander::input(const char*& input)
{
    // be sure to FAIL here
    //static_assert("Cannot input into a static pointer");
    return false;
} */

void ATCommander::do_request_prefix(const char *cmd)
{
    send_request(cmd);
    recv_request_echo_prefix(cmd);
}

namespace layer3 {

const char* MultiMatcher::do_match(const char* input, const char** keywords)
{
    const char* keyword;

    while((keyword = *keywords++))
    {
        if(strcmp(keyword, input) == 0) return keyword;
    }

    return nullptr;
}

bool MultiMatcher::parse(char c)
{
    const char** _keyword = &keywords[vpos];
    const char* keyword;

    // If we still have keywords to inspect
    while((keyword = *_keyword) != nullptr)
    {
        char ch = *(keyword + hpos);
        // see if this particular keyword at this particular horizontal
        // position IN the keyword matches incoming c
        if(ch == c)
        {
            // If so, bump hpos up as we have a "so far" match and prep
            // for the next one
            hpos++;
            return true;
        }
        else if(c == 13)
        {
            // FIX: eating CR for now, but we can do better (parse it out before we get here)
            return true;
        }
        else if(ch == 0) // reaching ch == 0 here means we DID get a match, technically
        {
            match = true;
            // but we might want to keep looking to make a more "greedy" match (longer keyword, if available)

            // TODO: make incoming terminator more configurable
            if(c == 10)
            {
                // if we get here it means both incoming character and our own keyword
                // are at their delimiters, meaning an exact match
                // and we're done
                return false;
            }

            // TODO: greedy match mode not yet implemented, will involve fiddling with vpos
            // i.e. only bumping it forward if we really want to abandon this match
            return false;
        }

        // if no match, then move forward (alphabetically)
        // down the line
        vpos++;
        _keyword++;

        // NOTE: this is what makes alphabetical ordering important
        // if we don't get a match, we compare the current const match to the
        // next potential const match to see if the prefix
        // at least matches so that we can then compare a suffix.  If prefix does
        // NOT match, that means we are done - again, things must be alphabetical
        // for that to work
        if (memcmp(keyword, *_keyword, hpos) != 0) return false;
    }

    // if we get to the end, then definitely no match
    return false;
}

}
<|endoftext|>


<commit_before>//**************************************************************************************************
//
//     OSSIM Open Source Geospatial Data Processing Library
//     See top level LICENSE.txt file for license information
//
//**************************************************************************************************

#include "AtpConfig.h"
#include "AtpOpenCV.h"
#include <ossim/base/ossimCommon.h>
#include <ossim/base/ossimException.h>
#include <ossim/base/ossimPreferences.h>
#include <opencv2/features2d/features2d.hpp>
#include <memory>

using namespace std;

namespace ATP
{
AtpParam AtpConfig::s_nullParam;

AtpParam::AtpParam(const ossimString& argname,
                   const ossimString& arglabel,
                   const ossimString& argdescr,
                   ParamType   argparamType,
                   void* value)
:  _name (argname),
   _label (arglabel),
   _descr (argdescr),
   _type (argparamType),
   _value(0)
{
   setValue(value);
}

AtpParam::AtpParam(const AtpParam& copy)
:  _label (copy._label),
   _name (copy._name),
   _descr (copy._descr),
   _type (copy._type),
   _value (0)
{
   setValue(copy._value);
}

void AtpParam::setValue(void* value)
{
   if (!value)
      return;

   switch (_type)
   {
   case AtpParam::BOOL:
      _value = new bool;
      memcpy(_value, value, sizeof(bool));
      break;
   case AtpParam::INT:
      _value = new int;
      memcpy(_value, value, sizeof(int));
      break;
   case AtpParam::UINT:
      _value = new unsigned int;
      memcpy(_value, value, sizeof(unsigned int));
      break;
   case AtpParam::FLOAT:
      _value = new double;
      memcpy(_value, value, sizeof(double));
      break;
   case AtpParam::STRING:
      _value = new string(*(string*)(value));
      break;
   case AtpParam::VECTOR:
      _value = new vector<double>(*(vector<double>*)(value));
      break;
   default:
      _value = 0;
   }
}

void AtpParam::resetValue()
{
   if (!_value)
      return;

   switch (_type)
   {
   case AtpParam::BOOL:
      delete (bool*)_value;
      break;
   case AtpParam::INT:
   case AtpParam::UINT:
      delete (int*)_value;
      break;
   case AtpParam::FLOAT:
      delete (double*)_value;
      break;
   case AtpParam::STRING:
      delete (string*)_value;
      break;
   case AtpParam::VECTOR:
      ((vector<double>*)_value)->clear();
      delete (vector<double>*)_value;
      break;
   default:
      break;
   }
   _value = 0;
}

bool AtpParam::loadJSON(const Json::Value& paramNode)
{
   try
   {
      _name = paramNode["name"].asString();
      _label = paramNode["label"].asString();
      _descr = paramNode["descr"].asString();
      Json::Value value = paramNode["value"];

      ossimString ptype = paramNode["type"].asString();
      if (ptype.empty() || _name.empty())
         return false;

      ptype.upcase();

      if (ptype == "VECTOR")
      {
         _type = AtpParam::VECTOR;
         vector<double> v;
         if (value.isArray())
         {
            int n = value.size();
            for (unsigned int j=0; j<n; ++j)
               v.push_back(value[j].asDouble());
         }
         setValue(&v);
      }
      else
      {
         // Screen for param value list as found in the default config JSONs. Pick the first element
         // as the default:
         if (value.isArray())
            value = value[0];

         if (ptype == "BOOL")
         {
            _type = AtpParam::BOOL;
            bool v = value.asBool();
            setValue(&v);
         }
         else if (ptype == "UINT")
         {
            _type = AtpParam::UINT;
            unsigned int v = value.asUInt();
            setValue(&v);
         }
         else if (ptype == "INT")
         {
            _type = AtpParam::INT;
            int v = value.asInt();
            setValue(&v);
         }
         else if (ptype == "FLOAT")
         {
            _type = AtpParam::FLOAT;
            double v = value.asDouble();
            setValue(&v);
         }
         else if (ptype == "STRING")
         {
            _type = AtpParam::STRING;
            string v = value.asString();
            setValue(&v);
         }
      }
   }
   catch (exception& e)
   {
      ossimNotify(ossimNotifyLevel_WARN)<<"AtpParam::loadJSON() parse error encountered. Ignoring "
            "but should check the AtpConfig JSON for parameter <"<<_name<<">."<<endl;
      return false;
   }
   return true;
}

void AtpParam::saveJSON(Json::Value& paramNode) const
{
   vector<double>& v = *(vector<double>*)_value; // maybe not used since maybe not valid cast
   unsigned int n = 0;
   int i;
   double f;
   string s;
   bool b;

   paramNode["name"] = _name.string();
   paramNode["label"] = _label.string();
   paramNode["descr"] = _descr.string();

   switch (_type)
   {
   case AtpParam::BOOL:
      paramNode["type"] = "bool";
      b = *(bool*)_value;
      paramNode["value"] = b;
      break;

   case AtpParam::INT:
      paramNode["type"] = "int";
      i = *(int*)_value;
      paramNode["value"] = i;
      break;

   case AtpParam::UINT:
      paramNode["type"] = "uint";
      n = *(unsigned int*)_value;
      paramNode["value"] = n;
      break;

   case AtpParam::FLOAT:
      paramNode["type"] = "float";
      f = *(double*)_value;
      paramNode["value"] = f;
      break;

   case AtpParam::STRING:
      paramNode["type"] = "string";
      s = *(string*)_value;
      paramNode["value"] = s;
      break;

   case AtpParam::VECTOR:
      paramNode["type"] = "vector";
      n = v.size();
      for (unsigned int j=0; j<n; ++j)
         paramNode["value"][j] = v[j];
      break;

   default:
      break;
   }
}

bool AtpParam::asBool() const
{
   if (_type == BOOL)
      return *(bool*)_value;
   return false;
}

unsigned int AtpParam::asUint() const
{
   if (_type == UINT)
      return *(unsigned int*)_value;
   return 0;
}

int  AtpParam::asInt() const
{
   if ((_type == INT) || (_type == UINT))
      return *(int*)_value;
   return 0;
}

double AtpParam::asFloat() const
{
   if (_type == FLOAT)
      return *(double*)_value;
   return ossim::nan();
}

std::string AtpParam::asString() const
{
   if (_type == STRING)
      return *(string*)_value;
   return "";
}

void AtpParam::asVector(std::vector<double>& v) const
{
   v.clear();
   if (_type == VECTOR)
      v = *(vector<double>*)_value;
}

ostream& operator<<(std::ostream& out, const AtpParam& obj)
{
   Json::Value jsonNode;
   obj.saveJSON(jsonNode);
   Json::StyledStreamWriter ssw;
   ssw.write(out, jsonNode);
   return out;
}

//-------------------------------------------------------------

AtpConfig& AtpConfig::instance()
{
   static AtpConfig singleton;
   return singleton;
}

AtpConfig::AtpConfig()
{

   // Register the ISA-common parameters in the params map:
   readConfig();
}

AtpConfig::~AtpConfig()
{
   m_paramsMap.clear();
}

bool AtpConfig::readConfig(const string& cn)
{
   // This method could eventually curl a spring config server for the param JSON. For now it
   // is reading the installed share/ossim-isa system directory for config JSON files.

   // The previous parameters list is cleared first for a fresh start:
   m_paramsMap.clear();

   ossimFilename configFilename;
   Json::Reader reader;
   Json::Value jsonRoot;
   try
   {
      // First establish the directory location of the default config files:
      ossimFilename shareDir = ossimPreferences::instance()->
         preferencesKWL().findKey( std::string( "ossim_share_directory" ) );
      shareDir.append("/atp");
      if (!shareDir.isDir())
         throw ossimException("Nonexistent share drive provided for config files.");

      // Read the default common parameters first:
      configFilename = "atpConfig.json";
      configFilename.setPath(shareDir);
      ifstream file1 (configFilename.string());
      if (file1.fail())
         throw ossimException("Bad file open.");
      if (!reader.parse(file1, jsonRoot))
         throw ossimException("Bad file JSON parse");
      jsonRoot = jsonRoot["parameters"];
      loadJSON(jsonRoot);
      file1.close();

      // Read the algorithm-specific default parameters if generic algo name specified as config:
      ossimString configName (cn);
      configFilename.clear();
      if (configName == "crosscorr")
         configFilename = "crossCorrConfig.json";
      else if (configName == "descriptor")
         configFilename = "descriptorConfig.json";
      else if (configName == "nasa")
         configFilename = "nasaConfig.json";
      else if (!configName.empty())
      {
         // Custom configuration. TODO: the path here is still the install's share directory.
         // Eventually want to provide a database access to the config JSON.
         configFilename = configName + ".json";
      }

      // Load the specified configuration. This will override the common defaults:
      if (!configFilename.empty())
      {
         configFilename.setPath(shareDir);
         ifstream file2 (configFilename.string());
         if (file2.fail() || !reader.parse(file2, jsonRoot))
            throw ossimException("Bad file open or JSON parse");
         jsonRoot = jsonRoot["parameters"];
         loadJSON(jsonRoot);
         file2.close();
      }
   }
   catch (ossimException& e)
   {
      ossimNotify(ossimNotifyLevel_WARN)<<"AtpConfig::readConfig():  Could not open/parse "
            "config file at <"<< configFilename << ">. Error: "<<e.what()<<endl;
      return false;
   }
   return true;
}

AtpParam& AtpConfig::getParameter(const char* paramName)
{
   map<string, AtpParam>::iterator i = m_paramsMap.find(string(paramName));
   if (i != m_paramsMap.end())
      return i->second;
   return s_nullParam;
}

void AtpConfig::setParameter(const AtpParam& p)
{
   // Tricky stuff to make sure it is a deep copy of the parameter:
   string key = p.name().string();
   std::map<std::string, AtpParam>::iterator iter = m_paramsMap.find(key);
   if (iter != m_paramsMap.end())
      m_paramsMap.erase(key);
   m_paramsMap.emplace(key, p);
}

bool AtpConfig::paramExists(const char* paramName) const
{
   map<string, AtpParam>::const_iterator i = m_paramsMap.find(string(paramName));
   if (i != m_paramsMap.end())
      return true;
   return false;
}

void AtpConfig::loadJSON(const Json::Value& json_node)
{
   Json::Value paramNode;

   // Support two forms: long (with full param descriptions and types), or short (just name: value)
   if (json_node.isArray())
   {
      // Long form:
      for (unsigned int i=0; i<json_node.size(); ++i)
      {
         paramNode = json_node[i];
         AtpParam p;
         if (p.loadJSON(paramNode))
            setParameter(p);
      }
   }
   else
   {
      // Short form expects a prior entry in the params map whose value will be overriden here:
      Json::Value::Members members = json_node.getMemberNames();
      for (size_t i=0; i<members.size(); ++i)
      {
         AtpParam& p = getParameter(members[i].c_str());
         if (p.name().empty())
         {
            ossimNotify(ossimNotifyLevel_WARN)<<"AtpConfig::loadJSON():  Attempted to override "
                  "nonexistent parameter <"<< members[i] << ">. Ignoring request."<<endl;
            continue;
         }

         // Create a full JSON representation of the named parameter from the default list, replace
         // its value, and recreate the parameter from the updated full JSON:
         p.saveJSON(paramNode);
         paramNode["value"] = json_node[p.name().string()];
         p.loadJSON(paramNode);
     }
   }
}

void AtpConfig::saveJSON(Json::Value& json_node) const
{
   Json::Value paramNode;

   map<string, AtpParam>::const_iterator param = m_paramsMap.begin();
   int entry = 0;
   while (param != m_paramsMap.end())
   {
      param->second.saveJSON(paramNode);
      json_node[entry++] = paramNode;
      ++param;
   }
}

bool AtpConfig::diagnosticLevel(unsigned int level) const
{
   map<string, AtpParam>::const_iterator i = m_paramsMap.find(string("diagnosticLevel"));
   if (i != m_paramsMap.end())
   {
      unsigned int levelSetting = i->second.asUint();
      return (level <= levelSetting);
   }
   return false;
}

std::ostream& operator<<(std::ostream& out, const AtpConfig& obj)
{
   Json::Value configJsonNode;
   obj.saveJSON(configJsonNode);
   Json::StyledStreamWriter ssw;
   ssw.write(out, configJsonNode);

   return out;
}

}
<commit_msg>Fixed append of share path<commit_after>//**************************************************************************************************
//
//     OSSIM Open Source Geospatial Data Processing Library
//     See top level LICENSE.txt file for license information
//
//**************************************************************************************************

#include "AtpConfig.h"
#include "AtpOpenCV.h"
#include <ossim/base/ossimCommon.h>
#include <ossim/base/ossimException.h>
#include <ossim/base/ossimPreferences.h>
#include <opencv2/features2d/features2d.hpp>
#include <memory>

using namespace std;

namespace ATP
{
AtpParam AtpConfig::s_nullParam;

AtpParam::AtpParam(const ossimString& argname,
                   const ossimString& arglabel,
                   const ossimString& argdescr,
                   ParamType   argparamType,
                   void* value)
:  _name (argname),
   _label (arglabel),
   _descr (argdescr),
   _type (argparamType),
   _value(0)
{
   setValue(value);
}

AtpParam::AtpParam(const AtpParam& copy)
:  _label (copy._label),
   _name (copy._name),
   _descr (copy._descr),
   _type (copy._type),
   _value (0)
{
   setValue(copy._value);
}

void AtpParam::setValue(void* value)
{
   if (!value)
      return;

   switch (_type)
   {
   case AtpParam::BOOL:
      _value = new bool;
      memcpy(_value, value, sizeof(bool));
      break;
   case AtpParam::INT:
      _value = new int;
      memcpy(_value, value, sizeof(int));
      break;
   case AtpParam::UINT:
      _value = new unsigned int;
      memcpy(_value, value, sizeof(unsigned int));
      break;
   case AtpParam::FLOAT:
      _value = new double;
      memcpy(_value, value, sizeof(double));
      break;
   case AtpParam::STRING:
      _value = new string(*(string*)(value));
      break;
   case AtpParam::VECTOR:
      _value = new vector<double>(*(vector<double>*)(value));
      break;
   default:
      _value = 0;
   }
}

void AtpParam::resetValue()
{
   if (!_value)
      return;

   switch (_type)
   {
   case AtpParam::BOOL:
      delete (bool*)_value;
      break;
   case AtpParam::INT:
   case AtpParam::UINT:
      delete (int*)_value;
      break;
   case AtpParam::FLOAT:
      delete (double*)_value;
      break;
   case AtpParam::STRING:
      delete (string*)_value;
      break;
   case AtpParam::VECTOR:
      ((vector<double>*)_value)->clear();
      delete (vector<double>*)_value;
      break;
   default:
      break;
   }
   _value = 0;
}

bool AtpParam::loadJSON(const Json::Value& paramNode)
{
   try
   {
      _name = paramNode["name"].asString();
      _label = paramNode["label"].asString();
      _descr = paramNode["descr"].asString();
      Json::Value value = paramNode["value"];

      ossimString ptype = paramNode["type"].asString();
      if (ptype.empty() || _name.empty())
         return false;

      ptype.upcase();

      if (ptype == "VECTOR")
      {
         _type = AtpParam::VECTOR;
         vector<double> v;
         if (value.isArray())
         {
            int n = value.size();
            for (unsigned int j=0; j<n; ++j)
               v.push_back(value[j].asDouble());
         }
         setValue(&v);
      }
      else
      {
         // Screen for param value list as found in the default config JSONs. Pick the first element
         // as the default:
         if (value.isArray())
            value = value[0];

         if (ptype == "BOOL")
         {
            _type = AtpParam::BOOL;
            bool v = value.asBool();
            setValue(&v);
         }
         else if (ptype == "UINT")
         {
            _type = AtpParam::UINT;
            unsigned int v = value.asUInt();
            setValue(&v);
         }
         else if (ptype == "INT")
         {
            _type = AtpParam::INT;
            int v = value.asInt();
            setValue(&v);
         }
         else if (ptype == "FLOAT")
         {
            _type = AtpParam::FLOAT;
            double v = value.asDouble();
            setValue(&v);
         }
         else if (ptype == "STRING")
         {
            _type = AtpParam::STRING;
            string v = value.asString();
            setValue(&v);
         }
      }
   }
   catch (exception& e)
   {
      ossimNotify(ossimNotifyLevel_WARN)<<"AtpParam::loadJSON() parse error encountered. Ignoring "
            "but should check the AtpConfig JSON for parameter <"<<_name<<">."<<endl;
      return false;
   }
   return true;
}

void AtpParam::saveJSON(Json::Value& paramNode) const
{
   vector<double>& v = *(vector<double>*)_value; // maybe not used since maybe not valid cast
   unsigned int n = 0;
   int i;
   double f;
   string s;
   bool b;

   paramNode["name"] = _name.string();
   paramNode["label"] = _label.string();
   paramNode["descr"] = _descr.string();

   switch (_type)
   {
   case AtpParam::BOOL:
      paramNode["type"] = "bool";
      b = *(bool*)_value;
      paramNode["value"] = b;
      break;

   case AtpParam::INT:
      paramNode["type"] = "int";
      i = *(int*)_value;
      paramNode["value"] = i;
      break;

   case AtpParam::UINT:
      paramNode["type"] = "uint";
      n = *(unsigned int*)_value;
      paramNode["value"] = n;
      break;

   case AtpParam::FLOAT:
      paramNode["type"] = "float";
      f = *(double*)_value;
      paramNode["value"] = f;
      break;

   case AtpParam::STRING:
      paramNode["type"] = "string";
      s = *(string*)_value;
      paramNode["value"] = s;
      break;

   case AtpParam::VECTOR:
      paramNode["type"] = "vector";
      n = v.size();
      for (unsigned int j=0; j<n; ++j)
         paramNode["value"][j] = v[j];
      break;

   default:
      break;
   }
}

bool AtpParam::asBool() const
{
   if (_type == BOOL)
      return *(bool*)_value;
   return false;
}

unsigned int AtpParam::asUint() const
{
   if (_type == UINT)
      return *(unsigned int*)_value;
   return 0;
}

int  AtpParam::asInt() const
{
   if ((_type == INT) || (_type == UINT))
      return *(int*)_value;
   return 0;
}

double AtpParam::asFloat() const
{
   if (_type == FLOAT)
      return *(double*)_value;
   return ossim::nan();
}

std::string AtpParam::asString() const
{
   if (_type == STRING)
      return *(string*)_value;
   return "";
}

void AtpParam::asVector(std::vector<double>& v) const
{
   v.clear();
   if (_type == VECTOR)
      v = *(vector<double>*)_value;
}

ostream& operator<<(std::ostream& out, const AtpParam& obj)
{
   Json::Value jsonNode;
   obj.saveJSON(jsonNode);
   Json::StyledStreamWriter ssw;
   ssw.write(out, jsonNode);
   return out;
}

//-------------------------------------------------------------

AtpConfig& AtpConfig::instance()
{
   static AtpConfig singleton;
   return singleton;
}

AtpConfig::AtpConfig()
{

   // Register the ISA-common parameters in the params map:
   readConfig();
}

AtpConfig::~AtpConfig()
{
   m_paramsMap.clear();
}

bool AtpConfig::readConfig(const string& cn)
{
   // This method could eventually curl a spring config server for the param JSON. For now it
   // is reading the installed share/ossim-isa system directory for config JSON files.

   // The previous parameters list is cleared first for a fresh start:
   m_paramsMap.clear();

   ossimFilename configFilename;
   Json::Reader reader;
   Json::Value jsonRoot;
   try
   {
      // First establish the directory location of the default config files:
      ossimFilename shareDir = ossimPreferences::instance()->
         preferencesKWL().findKey( std::string( "ossim_share_directory" ) );
      shareDir += "/atp";
      if (!shareDir.isDir())
         throw ossimException("Nonexistent share drive provided for config files.");

      // Read the default common parameters first:
      configFilename = "atpConfig.json";
      configFilename.setPath(shareDir);
      ifstream file1 (configFilename.string());
      if (file1.fail())
         throw ossimException("Bad file open.");
      if (!reader.parse(file1, jsonRoot))
         throw ossimException("Bad file JSON parse");
      jsonRoot = jsonRoot["parameters"];
      loadJSON(jsonRoot);
      file1.close();

      // Read the algorithm-specific default parameters if generic algo name specified as config:
      ossimString configName (cn);
      configFilename.clear();
      if (configName == "crosscorr")
         configFilename = "crossCorrConfig.json";
      else if (configName == "descriptor")
         configFilename = "descriptorConfig.json";
      else if (configName == "nasa")
         configFilename = "nasaConfig.json";
      else if (!configName.empty())
      {
         // Custom configuration. TODO: the path here is still the install's share directory.
         // Eventually want to provide a database access to the config JSON.
         configFilename = configName + ".json";
      }

      // Load the specified configuration. This will override the common defaults:
      if (!configFilename.empty())
      {
         configFilename.setPath(shareDir);
         ifstream file2 (configFilename.string());
         if (file2.fail() || !reader.parse(file2, jsonRoot))
            throw ossimException("Bad file open or JSON parse");
         jsonRoot = jsonRoot["parameters"];
         loadJSON(jsonRoot);
         file2.close();
      }
   }
   catch (ossimException& e)
   {
      ossimNotify(ossimNotifyLevel_WARN)<<"AtpConfig::readConfig():  Could not open/parse "
            "config file at <"<< configFilename << ">. Error: "<<e.what()<<endl;
      return false;
   }
   return true;
}

AtpParam& AtpConfig::getParameter(const char* paramName)
{
   map<string, AtpParam>::iterator i = m_paramsMap.find(string(paramName));
   if (i != m_paramsMap.end())
      return i->second;
   return s_nullParam;
}

void AtpConfig::setParameter(const AtpParam& p)
{
   // Tricky stuff to make sure it is a deep copy of the parameter:
   string key = p.name().string();
   std::map<std::string, AtpParam>::iterator iter = m_paramsMap.find(key);
   if (iter != m_paramsMap.end())
      m_paramsMap.erase(key);
   m_paramsMap.emplace(key, p);
}

bool AtpConfig::paramExists(const char* paramName) const
{
   map<string, AtpParam>::const_iterator i = m_paramsMap.find(string(paramName));
   if (i != m_paramsMap.end())
      return true;
   return false;
}

void AtpConfig::loadJSON(const Json::Value& json_node)
{
   Json::Value paramNode;

   // Support two forms: long (with full param descriptions and types), or short (just name: value)
   if (json_node.isArray())
   {
      // Long form:
      for (unsigned int i=0; i<json_node.size(); ++i)
      {
         paramNode = json_node[i];
         AtpParam p;
         if (p.loadJSON(paramNode))
            setParameter(p);
      }
   }
   else
   {
      // Short form expects a prior entry in the params map whose value will be overriden here:
      Json::Value::Members members = json_node.getMemberNames();
      for (size_t i=0; i<members.size(); ++i)
      {
         AtpParam& p = getParameter(members[i].c_str());
         if (p.name().empty())
         {
            ossimNotify(ossimNotifyLevel_WARN)<<"AtpConfig::loadJSON():  Attempted to override "
                  "nonexistent parameter <"<< members[i] << ">. Ignoring request."<<endl;
            continue;
         }

         // Create a full JSON representation of the named parameter from the default list, replace
         // its value, and recreate the parameter from the updated full JSON:
         p.saveJSON(paramNode);
         paramNode["value"] = json_node[p.name().string()];
         p.loadJSON(paramNode);
     }
   }
}

void AtpConfig::saveJSON(Json::Value& json_node) const
{
   Json::Value paramNode;

   map<string, AtpParam>::const_iterator param = m_paramsMap.begin();
   int entry = 0;
   while (param != m_paramsMap.end())
   {
      param->second.saveJSON(paramNode);
      json_node[entry++] = paramNode;
      ++param;
   }
}

bool AtpConfig::diagnosticLevel(unsigned int level) const
{
   map<string, AtpParam>::const_iterator i = m_paramsMap.find(string("diagnosticLevel"));
   if (i != m_paramsMap.end())
   {
      unsigned int levelSetting = i->second.asUint();
      return (level <= levelSetting);
   }
   return false;
}

std::ostream& operator<<(std::ostream& out, const AtpConfig& obj)
{
   Json::Value configJsonNode;
   obj.saveJSON(configJsonNode);
   Json::StyledStreamWriter ssw;
   ssw.write(out, configJsonNode);

   return out;
}

}
<|endoftext|>