<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011-2016.
// Distributed under the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <iostream>

#include "cpp_utils/assert.hpp"

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

#include "ast/Printer.hpp"
#include "ast/SourceFile.hpp"
#include "ast/Operator.hpp"

using namespace eddic;

namespace {

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--;
    }

    void print_template_list(const std::vector<ast::Type>& template_types) const {
        if(!template_types.empty()){
            std::cout << "<";

            std::cout << to_string(template_types[0]);

            for(std::size_t i = 1; i < template_types.size(); ++i){
                std::cout << ", " << to_string(template_types[i]);
            }

            std::cout << ">";
        }
    }

    void print_template_list(const std::vector<std::string>& template_types) const {
        if(!template_types.empty()){
            std::cout << "<";

            std::cout << template_types[0];

            for(std::size_t i = 1; i < template_types.size(); ++i){
                std::cout << ", " << template_types[i];
            }

            std::cout << ">";
        }
    }

    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.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::struct_definition& declaration) const {
        std::cout << indent() << "Struct Definition";
        if(declaration.is_template_declaration()){
            print_template_list(declaration.decl_template_types);
        }
        std::cout << " " << declaration.name << std::endl;
        level++;
        print_each_sub(declaration.blocks, "Blocks");
        level--;
        std::cout << std::endl;
    }

    void operator()(ast::TemplateFunctionDeclaration& declaration) const {
        if(declaration.is_template()){
            std::cout << indent() << "Template Function";
            print_template_list(declaration.template_types);
            std::cout << declaration.functionName << std::endl;
            std::cout << std::endl;
        } else {
            std::cout << indent() << "Function " << declaration.functionName << std::endl;

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

            print_each_sub(declaration.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.parameters){
            std::cout << indent() << param.parameterName << std::endl;
        }
        level--;

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

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

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

    void operator()(ast::MemberDeclaration& declaration) const {
        std::cout << indent() << ast::to_string(declaration.type)  << " " << declaration.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 " << ast::to_string(new_.type) << std::endl;
        print_each_sub(new_.values, "Value");
    }

    void operator()(ast::NewArray& new_array) const {
        std::cout << indent() << "New array of " << ast::to_string(new_array.type) << std::endl;
        print_sub(new_array.size, "Size");
    }

    void operator()(ast::Delete& delete_) const {
        std::cout << indent() << "Delete" << std::endl;
        print_sub(delete_.value, "Value");
    }

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

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

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

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

        ++level;

        print_sub(switch_.value, "Value");

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

        if(switch_.default_case){
            visit_non_variant(*this, *switch_.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_.condition, "Condition:");
        print_each_sub(while_.instructions, "Instructions:");
    }

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

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

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

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

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

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

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

    void operator()(ast::FunctionCall& call) const {
        std::cout << indent() << "FunctionCall " << call.function_name;
        print_template_list(call.template_types);
        std::cout << std::endl;
        print_each_sub(call.values);
    }

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

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

        print_each_sub(declaration.values, "Values");
    }

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

        if(declaration.value){
            print_sub(*declaration.value);
        }
    }

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

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

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

    void operator()(ast::Assignment& assign) const {
        std::cout << indent() << "Assignment [" << ast::toString(assign.op) << "] " << std::endl;

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

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

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

    void operator()(ast::Return& return_) const {
        print_sub(return_.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::Boolean& boolean) const {
        std::cout << indent() << boolean.value << std::endl;
    }

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

    void operator()(ast::VariableValue& value) const {
        std::cout << indent() << "Variable " << value.variableName << std::endl;
    }

    void operator()(ast::Expression& value) const {
        std::cout << indent() << "Expression [" << value.operations.size() << "]" << std::endl;
        ++level;

        visit(*this, value.first);

        for(auto& operation : value.operations){
            std::cout << indent() << ast::toString(operation.get<0>()) << std::endl;

            if(ast::has_operation_value(operation)){
                visit(*this, operation.get<1>());
            }
        }

        --level;
    }

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

    template<typename T>
    void operator()(x3::forward_ast<T>& value) const {
        (*this)(value.get());
    }
};

} //end of anonymous namespace

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

void ast::Printer::print(Expression& program){
    DebugVisitor visitor;
    visit_non_variant(visitor, program);
}

void ast::Printer::print(Value& value){
    DebugVisitor visitor;
    visit(visitor, value);
}

void ast::Printer::print(Instruction& value){
    DebugVisitor visitor;
    visit(visitor, value);
}
<commit_msg>Improve priting<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011-2016.
// Distributed under the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <iostream>

#include "cpp_utils/assert.hpp"

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

#include "ast/Printer.hpp"
#include "ast/SourceFile.hpp"
#include "ast/Operator.hpp"

using namespace eddic;

namespace {

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--;
    }

    void print_template_list(const std::vector<ast::Type>& template_types) const {
        if(!template_types.empty()){
            std::cout << "<";

            std::cout << to_string(template_types[0]);

            for(std::size_t i = 1; i < template_types.size(); ++i){
                std::cout << ", " << to_string(template_types[i]);
            }

            std::cout << ">";
        }
    }

    void print_template_list(const std::vector<std::string>& template_types) const {
        if(!template_types.empty()){
            std::cout << "<";

            std::cout << template_types[0];

            for(std::size_t i = 1; i < template_types.size(); ++i){
                std::cout << ", " << template_types[i];
            }

            std::cout << ">";
        }
    }

    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.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::struct_definition& declaration) const {
        std::cout << indent() << "Struct Definition";
        if(declaration.is_template_declaration()){
            print_template_list(declaration.decl_template_types);
        }
        std::cout << " " << declaration.name << std::endl;
        level++;
        print_each_sub(declaration.blocks, "Blocks");
        level--;
        std::cout << std::endl;
    }

    void operator()(ast::TemplateFunctionDeclaration& declaration) const {
        if(declaration.is_template()){
            std::cout << indent() << "Template Function";
            print_template_list(declaration.template_types);
            std::cout << declaration.functionName << std::endl;
            std::cout << std::endl;
        } else {
            std::cout << indent() << "Function " << declaration.functionName << std::endl;

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

            print_each_sub(declaration.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.parameters){
            std::cout << indent() << param.parameterName << std::endl;
        }
        level--;

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

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

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

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

    void operator()(ast::GlobalVariableDeclaration& declaration) const {
        std::cout << indent() << "Global Variable declaration [" << declaration.variableName << "]" << std::endl;

        if(declaration.value){
            print_sub(*declaration.value);
        }
    }

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

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

    void operator()(ast::NewArray& new_array) const {
        std::cout << indent() << "New array of " << ast::to_string(new_array.type) << std::endl;
        print_sub(new_array.size, "Size");
    }

    void operator()(ast::Delete& delete_) const {
        std::cout << indent() << "Delete" << std::endl;
        print_sub(delete_.value, "Value");
    }

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

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

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

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

        ++level;

        print_sub(switch_.value, "Value");

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

        if(switch_.default_case){
            visit_non_variant(*this, *switch_.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_.condition, "Condition:");
        print_each_sub(while_.instructions, "Instructions:");
    }

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

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

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

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

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

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

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

    void operator()(ast::FunctionCall& call) const {
        std::cout << indent() << "FunctionCall " << call.function_name;
        print_template_list(call.template_types);
        std::cout << std::endl;
        print_each_sub(call.values);
    }

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

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

        print_each_sub(declaration.values, "Values");
    }

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

        if(declaration.value){
            print_sub(*declaration.value);
        }
    }

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

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

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

    void operator()(ast::Assignment& assign) const {
        std::cout << indent() << "Assignment [" << ast::toString(assign.op) << "] " << std::endl;

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

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

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

    void operator()(ast::Return& return_) const {
        print_sub(return_.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::Boolean& boolean) const {
        std::cout << indent() << boolean.value << std::endl;
    }

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

    void operator()(ast::VariableValue& value) const {
        std::cout << indent() << "Variable " << value.variableName << std::endl;
    }

    void operator()(ast::Expression& value) const {
        std::cout << indent() << "Expression [" << value.operations.size() << "]" << std::endl;
        ++level;

        visit(*this, value.first);

        for(auto& operation : value.operations){
            std::cout << indent() << ast::toString(operation.get<0>()) << std::endl;

            if(ast::has_operation_value(operation)){
                visit(*this, operation.get<1>());
            }
        }

        --level;
    }

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

    template<typename T>
    void operator()(x3::forward_ast<T>& value) const {
        (*this)(value.get());
    }
};

} //end of anonymous namespace

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

void ast::Printer::print(Expression& program){
    DebugVisitor visitor;
    visit_non_variant(visitor, program);
}

void ast::Printer::print(Value& value){
    DebugVisitor visitor;
    visit(visitor, value);
}

void ast::Printer::print(Instruction& value){
    DebugVisitor visitor;
    visit(visitor, value);
}
<|endoftext|>


<commit_before>/************************************************************************
*
* CppSharp
* Licensed under the simplified BSD license. All rights reserved.
*
************************************************************************/

#include "Parser.h"
#include "Interop.h"

#include <clang/AST/ASTContext.h>

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

static CppSharp::AST::RawCommentKind
ConvertCommentKind(clang::RawComment::CommentKind Kind)
{
	using clang::RawComment;
	using namespace CppSharp::AST;

	switch(Kind)
	{
	case RawComment::RCK_Invalid: return RawCommentKind::Invalid;
	case RawComment::RCK_OrdinaryBCPL: return RawCommentKind::OrdinaryBCPL;
	case RawComment::RCK_OrdinaryC: return RawCommentKind::OrdinaryC;
	case RawComment::RCK_BCPLSlash: return RawCommentKind::BCPLSlash;
	case RawComment::RCK_BCPLExcl: return RawCommentKind::BCPLExcl;
	case RawComment::RCK_JavaDoc: return RawCommentKind::JavaDoc;
	case RawComment::RCK_Qt: return RawCommentKind::Qt;
	case RawComment::RCK_Merged: return RawCommentKind::Merged;
	}

	llvm_unreachable("Unknown comment kind");
}

CppSharp::AST::RawComment^ Parser::WalkRawComment(const clang::RawComment* RC)
{
	using namespace clang;
    using namespace clix;

	auto &SM = C->getSourceManager();
	auto Comment = gcnew CppSharp::AST::RawComment();
	Comment->Kind = ConvertCommentKind(RC->getKind());
	Comment->Text = marshalString<E_UTF8>(RC->getRawText(SM));
	Comment->BriefText = marshalString<E_UTF8>(RC->getBriefText(*AST));

	return Comment;
}

static CppSharp::AST::InlineCommandComment::RenderKind
ConvertRenderKind(clang::comments::InlineCommandComment::RenderKind Kind)
{
	using namespace clang::comments;
	switch(Kind)
	{
	case InlineCommandComment::RenderNormal:
		return CppSharp::AST::InlineCommandComment::RenderKind::RenderNormal;
	case InlineCommandComment::RenderBold:
		return CppSharp::AST::InlineCommandComment::RenderKind::RenderBold;
	case InlineCommandComment::RenderMonospaced:
		return CppSharp::AST::InlineCommandComment::RenderKind::RenderMonospaced;
	case InlineCommandComment::RenderEmphasized:
		return CppSharp::AST::InlineCommandComment::RenderKind::RenderEmphasized;
	}
	llvm_unreachable("Unknown render kind");
}

static CppSharp::AST::ParamCommandComment::PassDirection
ConvertParamPassDirection(clang::comments::ParamCommandComment::PassDirection Dir)
{
	using namespace clang::comments;
	switch(Dir)
	{
	case ParamCommandComment::In:
		return CppSharp::AST::ParamCommandComment::PassDirection::In;
	case ParamCommandComment::Out:
		return CppSharp::AST::ParamCommandComment::PassDirection::Out;
	case ParamCommandComment::InOut:
		return CppSharp::AST::ParamCommandComment::PassDirection::InOut;
	}
	llvm_unreachable("Unknown parameter pass direction");
}

static void HandleBlockCommand(const clang::comments::BlockCommandComment *CK,
							   CppSharp::AST::BlockCommandComment^ BC)
{
	using namespace clix;

	BC->CommandId = CK->getCommandID();
	for (unsigned I = 0, E = CK->getNumArgs(); I != E; ++I)
	{
		auto Arg = CppSharp::AST::BlockCommandComment::Argument();
		Arg.Text = marshalString<E_UTF8>(CK->getArgText(I));
		BC->Arguments->Add(Arg);
	}
}

static CppSharp::AST::Comment^ ConvertCommentBlock(clang::comments::Comment* C)
{
    using namespace clang;
	using clang::comments::Comment;

    using namespace clix;
	using namespace CppSharp::AST;

	// This needs to have an underscore else we get an ICE under VS2012.
	CppSharp::AST::Comment^ _Comment;

	switch(C->getCommentKind())
	{
	case Comment::BlockCommandCommentKind:
	{
		auto CK = cast<const clang::comments::BlockCommandComment>(C);
		auto BC = gcnew BlockCommandComment();
		_Comment = BC;
		HandleBlockCommand(CK, BC);
		break;
	}
	case Comment::ParamCommandCommentKind:
	{
		auto CK = cast<clang::comments::ParamCommandComment>(C);
		auto PC = gcnew ParamCommandComment();
		_Comment = PC;
		HandleBlockCommand(CK, PC);
		PC->Direction = ConvertParamPassDirection(CK->getDirection());
		PC->ParamIndex = CK->getParamIndex();
		break;
	}
	case Comment::TParamCommandCommentKind:
	{
		auto CK = cast<clang::comments::TParamCommandComment>(C);
		_Comment = gcnew TParamCommandComment();
		auto TC = gcnew TParamCommandComment();
		_Comment = TC;
		HandleBlockCommand(CK, TC);
		if (CK->isPositionValid())
			for (unsigned I = 0, E = CK->getDepth(); I != E; ++I)
				TC->Position->Add(CK->getIndex(I));
		break;
	}
	case Comment::VerbatimBlockCommentKind:
	{
		auto CK = cast<clang::comments::VerbatimBlockComment>(C);
		auto VB = gcnew VerbatimBlockComment();
		_Comment = VB;
		for (auto I = CK->child_begin(), E = CK->child_end(); I != E; ++I)
		{
			auto Line = ConvertCommentBlock(*I);
			VB->Lines->Add(dynamic_cast<VerbatimBlockLineComment^>(Line));
		}
		break;
	}
	case Comment::VerbatimLineCommentKind:
	{
		auto CK = cast<clang::comments::VerbatimLineComment>(C);
		auto VL = gcnew VerbatimLineComment();
		_Comment = VL;
		VL->Text = marshalString<E_UTF8>(CK->getText());
		break;
	}
	case Comment::ParagraphCommentKind:
	{
		auto CK = cast<clang::comments::ParagraphComment>(C);
		auto PC = gcnew ParagraphComment();
		_Comment = PC;
		for (auto I = CK->child_begin(), E = CK->child_end(); I != E; ++I)
		{
			auto Content = ConvertCommentBlock(*I);
			PC->Content->Add(dynamic_cast<InlineContentComment^>(Content));
		}
		PC->IsWhitespace = CK->isWhitespace();
		break;
	}
	case Comment::FullCommentKind:
	{
		auto CK = cast<clang::comments::FullComment>(C);
		auto FC = gcnew FullComment();
		_Comment = FC;
		for (auto I = CK->child_begin(), E = CK->child_end(); I != E; ++I)
		{
			auto Content = ConvertCommentBlock(*I);
			FC->Blocks->Add(dynamic_cast<BlockContentComment^>(Content));
		}
		break;
	}
	case Comment::HTMLStartTagCommentKind:
	{
		auto CK = cast<clang::comments::HTMLStartTagComment>(C);
		auto TC = gcnew HTMLStartTagComment();
		_Comment = TC;
		TC->TagName = marshalString<E_UTF8>(CK->getTagName());
		for (unsigned I = 0, E = CK->getNumAttrs(); I != E; ++I)
		{
			auto A = CK->getAttr(I);
			auto Attr = CppSharp::AST::HTMLStartTagComment::Attribute();
			Attr.Name = marshalString<E_UTF8>(A.Name);
			Attr.Value = marshalString<E_UTF8>(A.Value);
			TC->Attributes->Add(Attr);
		}
		break;
	}
	case Comment::HTMLEndTagCommentKind:
	{
		auto CK = cast<clang::comments::HTMLEndTagComment>(C);
		auto TC = gcnew HTMLEndTagComment();
		_Comment = TC;
		TC->TagName = marshalString<E_UTF8>(CK->getTagName());
		break;
	}
	case Comment::TextCommentKind:
	{
		auto CK = cast<clang::comments::TextComment>(C);
		auto TC = gcnew TextComment();
		_Comment = TC;
		TC->Text = marshalString<E_UTF8>(CK->getText());
		break;
	}
	case Comment::InlineCommandCommentKind:
	{
		auto CK = cast<clang::comments::InlineCommandComment>(C);
		auto IC = gcnew InlineCommandComment();
		_Comment = IC;
		IC->Kind = ConvertRenderKind(CK->getRenderKind());
		for (unsigned I = 0, E = CK->getNumArgs(); I != E; ++I)
		{
			auto Arg = CppSharp::AST::InlineCommandComment::Argument();
			Arg.Text = marshalString<E_UTF8>(CK->getArgText(I));
			IC->Arguments->Add(Arg);
		}
		break;
	}
	case Comment::VerbatimBlockLineCommentKind:
	{
		auto CK = cast<clang::comments::VerbatimBlockLineComment>(C);
		auto VL = gcnew VerbatimBlockLineComment();
		_Comment = VL;
		VL->Text = marshalString<E_UTF8>(CK->getText());
		break;
	}
	case Comment::NoCommentKind: return nullptr;
	default:
		llvm_unreachable("Unknown comment kind");
	}

	assert(_Comment && "Invalid comment instance");
	return _Comment;
}

void Parser::HandleComments(clang::Decl* D, CppSharp::AST::Declaration^ Decl)
{
    using namespace clang;
	using namespace clang::comments;
    using namespace clix;

    const RawComment* RC = 0;
    if (!(RC = AST->getRawCommentForAnyRedecl(D)))
		return;

	auto RawComment = WalkRawComment(RC);
	Decl->Comment = RawComment;

	if (FullComment* FC = RC->parse(*AST, &C->getPreprocessor(), D))
	{
		auto CB = safe_cast<CppSharp::AST::FullComment^>(ConvertCommentBlock(FC));
		RawComment->FullComment = CB;
	}

	// Debug Text
    SourceManager& SM = C->getSourceManager();
    const LangOptions& LangOpts = C->getLangOpts();

    auto Range = CharSourceRange::getTokenRange(D->getSourceRange());

    bool Invalid;
    StringRef DeclText = Lexer::getSourceText(Range, SM, LangOpts, &Invalid);
    //assert(!Invalid && "Should have a valid location");

    if (!Invalid)
        Decl->DebugText = marshalString<E_UTF8>(DeclText);
}
<commit_msg>Fixed whitespace.<commit_after>/************************************************************************
*
* CppSharp
* Licensed under the simplified BSD license. All rights reserved.
*
************************************************************************/

#include "Parser.h"
#include "Interop.h"

#include <clang/AST/ASTContext.h>

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

static CppSharp::AST::RawCommentKind
ConvertCommentKind(clang::RawComment::CommentKind Kind)
{
    using clang::RawComment;
    using namespace CppSharp::AST;

    switch(Kind)
    {
    case RawComment::RCK_Invalid: return RawCommentKind::Invalid;
    case RawComment::RCK_OrdinaryBCPL: return RawCommentKind::OrdinaryBCPL;
    case RawComment::RCK_OrdinaryC: return RawCommentKind::OrdinaryC;
    case RawComment::RCK_BCPLSlash: return RawCommentKind::BCPLSlash;
    case RawComment::RCK_BCPLExcl: return RawCommentKind::BCPLExcl;
    case RawComment::RCK_JavaDoc: return RawCommentKind::JavaDoc;
    case RawComment::RCK_Qt: return RawCommentKind::Qt;
    case RawComment::RCK_Merged: return RawCommentKind::Merged;
    }

    llvm_unreachable("Unknown comment kind");
}

CppSharp::AST::RawComment^ Parser::WalkRawComment(const clang::RawComment* RC)
{
    using namespace clang;
    using namespace clix;

    auto &SM = C->getSourceManager();
    auto Comment = gcnew CppSharp::AST::RawComment();
    Comment->Kind = ConvertCommentKind(RC->getKind());
    Comment->Text = marshalString<E_UTF8>(RC->getRawText(SM));
    Comment->BriefText = marshalString<E_UTF8>(RC->getBriefText(*AST));

    return Comment;
}

static CppSharp::AST::InlineCommandComment::RenderKind
ConvertRenderKind(clang::comments::InlineCommandComment::RenderKind Kind)
{
    using namespace clang::comments;
    switch(Kind)
    {
    case InlineCommandComment::RenderNormal:
        return CppSharp::AST::InlineCommandComment::RenderKind::RenderNormal;
    case InlineCommandComment::RenderBold:
        return CppSharp::AST::InlineCommandComment::RenderKind::RenderBold;
    case InlineCommandComment::RenderMonospaced:
        return CppSharp::AST::InlineCommandComment::RenderKind::RenderMonospaced;
    case InlineCommandComment::RenderEmphasized:
        return CppSharp::AST::InlineCommandComment::RenderKind::RenderEmphasized;
    }
    llvm_unreachable("Unknown render kind");
}

static CppSharp::AST::ParamCommandComment::PassDirection
ConvertParamPassDirection(clang::comments::ParamCommandComment::PassDirection Dir)
{
    using namespace clang::comments;
    switch(Dir)
    {
    case ParamCommandComment::In:
        return CppSharp::AST::ParamCommandComment::PassDirection::In;
    case ParamCommandComment::Out:
        return CppSharp::AST::ParamCommandComment::PassDirection::Out;
    case ParamCommandComment::InOut:
        return CppSharp::AST::ParamCommandComment::PassDirection::InOut;
    }
    llvm_unreachable("Unknown parameter pass direction");
}

static void HandleBlockCommand(const clang::comments::BlockCommandComment *CK,
                               CppSharp::AST::BlockCommandComment^ BC)
{
    using namespace clix;

    BC->CommandId = CK->getCommandID();
    for (unsigned I = 0, E = CK->getNumArgs(); I != E; ++I)
    {
        auto Arg = CppSharp::AST::BlockCommandComment::Argument();
        Arg.Text = marshalString<E_UTF8>(CK->getArgText(I));
        BC->Arguments->Add(Arg);
    }
}

static CppSharp::AST::Comment^ ConvertCommentBlock(clang::comments::Comment* C)
{
    using namespace clang;
    using clang::comments::Comment;

    using namespace clix;
    using namespace CppSharp::AST;

    // This needs to have an underscore else we get an ICE under VS2012.
    CppSharp::AST::Comment^ _Comment;

    switch(C->getCommentKind())
    {
    case Comment::BlockCommandCommentKind:
    {
        auto CK = cast<const clang::comments::BlockCommandComment>(C);
        auto BC = gcnew BlockCommandComment();
        _Comment = BC;
        HandleBlockCommand(CK, BC);
        break;
    }
    case Comment::ParamCommandCommentKind:
    {
        auto CK = cast<clang::comments::ParamCommandComment>(C);
        auto PC = gcnew ParamCommandComment();
        _Comment = PC;
        HandleBlockCommand(CK, PC);
        PC->Direction = ConvertParamPassDirection(CK->getDirection());
        PC->ParamIndex = CK->getParamIndex();
        break;
    }
    case Comment::TParamCommandCommentKind:
    {
        auto CK = cast<clang::comments::TParamCommandComment>(C);
        _Comment = gcnew TParamCommandComment();
        auto TC = gcnew TParamCommandComment();
        _Comment = TC;
        HandleBlockCommand(CK, TC);
        if (CK->isPositionValid())
            for (unsigned I = 0, E = CK->getDepth(); I != E; ++I)
                TC->Position->Add(CK->getIndex(I));
        break;
    }
    case Comment::VerbatimBlockCommentKind:
    {
        auto CK = cast<clang::comments::VerbatimBlockComment>(C);
        auto VB = gcnew VerbatimBlockComment();
        _Comment = VB;
        for (auto I = CK->child_begin(), E = CK->child_end(); I != E; ++I)
        {
            auto Line = ConvertCommentBlock(*I);
            VB->Lines->Add(dynamic_cast<VerbatimBlockLineComment^>(Line));
        }
        break;
    }
    case Comment::VerbatimLineCommentKind:
    {
        auto CK = cast<clang::comments::VerbatimLineComment>(C);
        auto VL = gcnew VerbatimLineComment();
        _Comment = VL;
        VL->Text = marshalString<E_UTF8>(CK->getText());
        break;
    }
    case Comment::ParagraphCommentKind:
    {
        auto CK = cast<clang::comments::ParagraphComment>(C);
        auto PC = gcnew ParagraphComment();
        _Comment = PC;
        for (auto I = CK->child_begin(), E = CK->child_end(); I != E; ++I)
        {
            auto Content = ConvertCommentBlock(*I);
            PC->Content->Add(dynamic_cast<InlineContentComment^>(Content));
        }
        PC->IsWhitespace = CK->isWhitespace();
        break;
    }
    case Comment::FullCommentKind:
    {
        auto CK = cast<clang::comments::FullComment>(C);
        auto FC = gcnew FullComment();
        _Comment = FC;
        for (auto I = CK->child_begin(), E = CK->child_end(); I != E; ++I)
        {
            auto Content = ConvertCommentBlock(*I);
            FC->Blocks->Add(dynamic_cast<BlockContentComment^>(Content));
        }
        break;
    }
    case Comment::HTMLStartTagCommentKind:
    {
        auto CK = cast<clang::comments::HTMLStartTagComment>(C);
        auto TC = gcnew HTMLStartTagComment();
        _Comment = TC;
        TC->TagName = marshalString<E_UTF8>(CK->getTagName());
        for (unsigned I = 0, E = CK->getNumAttrs(); I != E; ++I)
        {
            auto A = CK->getAttr(I);
            auto Attr = CppSharp::AST::HTMLStartTagComment::Attribute();
            Attr.Name = marshalString<E_UTF8>(A.Name);
            Attr.Value = marshalString<E_UTF8>(A.Value);
            TC->Attributes->Add(Attr);
        }
        break;
    }
    case Comment::HTMLEndTagCommentKind:
    {
        auto CK = cast<clang::comments::HTMLEndTagComment>(C);
        auto TC = gcnew HTMLEndTagComment();
        _Comment = TC;
        TC->TagName = marshalString<E_UTF8>(CK->getTagName());
        break;
    }
    case Comment::TextCommentKind:
    {
        auto CK = cast<clang::comments::TextComment>(C);
        auto TC = gcnew TextComment();
        _Comment = TC;
        TC->Text = marshalString<E_UTF8>(CK->getText());
        break;
    }
    case Comment::InlineCommandCommentKind:
    {
        auto CK = cast<clang::comments::InlineCommandComment>(C);
        auto IC = gcnew InlineCommandComment();
        _Comment = IC;
        IC->Kind = ConvertRenderKind(CK->getRenderKind());
        for (unsigned I = 0, E = CK->getNumArgs(); I != E; ++I)
        {
            auto Arg = CppSharp::AST::InlineCommandComment::Argument();
            Arg.Text = marshalString<E_UTF8>(CK->getArgText(I));
            IC->Arguments->Add(Arg);
        }
        break;
    }
    case Comment::VerbatimBlockLineCommentKind:
    {
        auto CK = cast<clang::comments::VerbatimBlockLineComment>(C);
        auto VL = gcnew VerbatimBlockLineComment();
        _Comment = VL;
        VL->Text = marshalString<E_UTF8>(CK->getText());
        break;
    }
    case Comment::NoCommentKind: return nullptr;
    default:
        llvm_unreachable("Unknown comment kind");
    }

    assert(_Comment && "Invalid comment instance");
    return _Comment;
}

void Parser::HandleComments(clang::Decl* D, CppSharp::AST::Declaration^ Decl)
{
    using namespace clang;
    using namespace clang::comments;
    using namespace clix;

    const RawComment* RC = 0;
    if (!(RC = AST->getRawCommentForAnyRedecl(D)))
        return;

    auto RawComment = WalkRawComment(RC);
    Decl->Comment = RawComment;

    if (FullComment* FC = RC->parse(*AST, &C->getPreprocessor(), D))
    {
        auto CB = safe_cast<CppSharp::AST::FullComment^>(ConvertCommentBlock(FC));
        RawComment->FullComment = CB;
    }

    // Debug Text
    SourceManager& SM = C->getSourceManager();
    const LangOptions& LangOpts = C->getLangOpts();

    auto Range = CharSourceRange::getTokenRange(D->getSourceRange());

    bool Invalid;
    StringRef DeclText = Lexer::getSourceText(Range, SM, LangOpts, &Invalid);
    //assert(!Invalid && "Should have a valid location");

    if (!Invalid)
        Decl->DebugText = marshalString<E_UTF8>(DeclText);
}
<|endoftext|>


<commit_before>/**
 * @file   Asset.hpp
 * @brief  Asset class prototype.
 * @author zer0
 * @date   2016-04-03
 */

#ifndef __INCLUDE_LIBTBAG__LIBTBAG_ASSET_HPP__
#define __INCLUDE_LIBTBAG__LIBTBAG_ASSET_HPP__

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#include <libtbag/config.h>
#include <libtbag/filesystem/Path.hpp>

#include <vector>
#include <map>
#include <string>

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

/**
 * Asset class prototype.
 *
 * @author zer0
 * @date   2016-04-03
 *
 * @remarks
 *  Resource manager class.
 *
 * @warning
 *  Not supported wchar_t string.
 */
class Asset
{
public:
    using ValueType = char;
    using String    = std::basic_string<ValueType>;
    using Path      = ::libtbag::filesystem::Path;
    using PathMap   = std::map<String, Path>;

    static_assert(std::is_same<ValueType, char>::value
            , "ValueType must be the same type as char");
    static_assert(std::is_same<ValueType, typename String::value_type>::value
            , "ValueType must be the same type as String::value_type");

public:
    /** Default setting for the constructor. */
    struct default_setting { __EMPTY_BLOCK__ };

public:
    static constexpr char const * const HOME_DIRECTORY_ASSET_NAME = "__HOME__";
    static constexpr char const * const  EXE_DIRECTORY_ASSET_NAME = "__EXE__";

private:
    PathMap _dirs;

public:
    Asset() noexcept(std::is_nothrow_default_constructible<PathMap>::value) {
        __EMPTY_BLOCK__
    }

    /** Construct of Default settings. */
    explicit Asset(default_setting const & UNUSED_PARAM(empty_value)) {
        this->insertDir(getHomeDirKeyName(), getHomeDirPath());
        this->insertDir(getExeDirKeyName(), getExeDirPath());
    }

    Asset(PathMap const & dirs) {
        this->_dirs = dirs;
    }

    Asset(Asset const & obj) {
        this->copy(obj);
    }

    Asset(Asset && obj) {
        this->swap(obj);
    }

    virtual ~Asset() {
        __EMPTY_BLOCK__
    }

public:
    Asset & operator =(Asset const & obj) {
        return this->copy(obj);
    }

    Asset & operator =(Asset && obj) {
        this->swap(obj);
        return *this;
    }

public:
    Asset & copy(Asset const & obj) {
        if (this != &obj) {
            this->_dirs = obj._dirs;
        }
        return *this;
    }

    void swap(Asset & obj) {
        if (this != &obj) {
            this->_dirs.swap(obj._dirs);
        }
    }

public:
    /**
     * Obtain directory name.
     *
     * @param key [in] Directory key name.
     *
     * @return
     *  - Empty string: If it can't find.
     *  - Otherwise: Successful find.
     */
    Path getDirPath(String const & key) const {
        try {
            return this->_dirs.at(key);
        } catch (std::out_of_range & e) {
            return Path();
        }
    }

    String getDirString(String const & key) const {
        return getDirPath(key).getString();
    }

    /**
     * Insert directory name.
     *
     * @param key   [in] Directory key name.
     * @param value [in] Directory path.
     */
    void insertDir(String const & key, Path const & value) {
        this->_dirs.insert(std::make_pair(key, value));
    }

    /**
     * Insert directory name.
     *
     * @param key   [in] Directory key name.
     * @param value [in] Directory path string.
     */
    void insertDir(String const & key, String const & value) {
        this->insertDir(key, Path(value));
    }

    std::size_t size() const noexcept(true) {
        return this->_dirs.size();
    }

public:
    std::vector<Path> scanDirWithKey(std::string const & key) const {
        return scanDir(getDirPath(key));
    }

    static std::vector<Path> scanDir(Path const & path) {
        std::vector<Path> result;
        for (auto cursor : filesystem::Common::scanDir(path.getNativeString())) {
            result.push_back(Path(Path::append(path, cursor)));
        }
        return result;
    }

public:
    bool isDirectoryWithKey(std::string const & key) {
        return isDirectory(getDirPath(key));
    }

    static bool isDirectory(Path const & path) {
        return filesystem::Common::isDirectory(path.getNativeString());
    }

// Static methods.
public:
    /** Obtain HOME directory key name. */
    static String getHomeDirKeyName() {
        return String(HOME_DIRECTORY_ASSET_NAME);
    }

    /** Obtain executable file directory key name. */
    static String getExeDirKeyName() {
        return String(EXE_DIRECTORY_ASSET_NAME);
    }

    /** Obtain HOME directory path. */
    static Path getHomeDirPath() {
        using filesystem::Common;
        return Path(Common::getHomeDir());
    }

    /** Obtain executable file directory path. */
    static Path getExeDirPath() {
        using filesystem::Common;
        return Path(Common::getExeDir());
    }

#ifndef CREATE_ASSET_PATH
/** Create a main directory accessor & mutator macro. */
#define CREATE_ASSET_PATH(name, path)                       \
public:                                                     \
    static constexpr ValueType const * const                \
            ASSET_NAME_KEY_##name = #name;                  \
    void insert_##name() {                                  \
        insertDir(ASSET_NAME_KEY_##name, path);             \
    }                                                       \
    Path get_##name() const {                               \
        return getDirPath(ASSET_NAME_KEY_##name);           \
    }                                                       \
    bool create_##name() const {                            \
        return filesystem::Common::createDir(get_##name()); \
    }                                                       \
    bool remove_##name() const {                            \
        return filesystem::Common::removeDir(get_##name()); \
    }                                                       \
    bool exists_##name() const {                            \
        return isDirectory(get_##name());                   \
    }                                                       \
    std::vector<Path> scan_##name() const {                 \
        return scanDir(get_##name());                       \
    }                                                       \
private:
#endif

#ifndef CREATE_ASSET_PATH_SUB
/** Create a subdirectory accessor & mutator macro. */
#define CREATE_ASSET_PATH_SUB(name, sub, path)                      \
public:                                                             \
    Path get_##name##_##sub() const {                               \
        return getDirPath(ASSET_NAME_KEY_##name) / path;            \
    }                                                               \
    bool create_##name##_##sub() const {                            \
        return filesystem::Common::createDir(get_##name##_##sub()); \
    }                                                               \
    bool remove_##name##_##sub() const {                            \
        return filesystem::Common::removeDir(get_##name##_##sub()); \
    }                                                               \
    bool exists_##name##_##sub() const {                            \
        return isDirectory(get_##name##_##sub());                   \
    }                                                               \
    std::vector<Path> scan_##name##_##sub() const {                 \
        return scanDir(get_##name##_##sub());                       \
    }                                                               \
private:
#endif
};

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

#endif // __INCLUDE_LIBTBAG__LIBTBAG_ASSET_HPP__

<commit_msg>Refactoring Asset class.<commit_after>/**
 * @file   Asset.hpp
 * @brief  Asset class prototype.
 * @author zer0
 * @date   2016-04-03
 */

#ifndef __INCLUDE_LIBTBAG__LIBTBAG_ASSET_HPP__
#define __INCLUDE_LIBTBAG__LIBTBAG_ASSET_HPP__

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#include <libtbag/config.h>
#include <libtbag/filesystem/Path.hpp>

#include <vector>
#include <map>
#include <string>

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

/**
 * Asset class prototype.
 *
 * @author zer0
 * @date   2016-04-03
 *
 * @remarks
 *  Resource manager class.
 *
 * @warning
 *  Not supported wchar_t string.
 */
class Asset
{
public:
    using ValueType = char;
    using String    = std::basic_string<ValueType>;
    using Path      = ::libtbag::filesystem::Path;
    using PathMap   = std::map<String, Path>;

    static_assert(std::is_same<ValueType, char>::value
            , "ValueType must be the same type as char");
    static_assert(std::is_same<ValueType, typename String::value_type>::value
            , "ValueType must be the same type as String::value_type");

public:
    /** Default setting for the constructor. */
    struct default_setting { __EMPTY_BLOCK__ };

public:
    static constexpr char const * const HOME_DIRECTORY_ASSET_NAME = "__HOME__";
    static constexpr char const * const  EXE_DIRECTORY_ASSET_NAME = "__EXE__";

private:
    PathMap _dirs;

public:
    Asset() noexcept(std::is_nothrow_default_constructible<PathMap>::value) {
        __EMPTY_BLOCK__
    }

    /** Construct of Default settings. */
    explicit Asset(default_setting const & UNUSED_PARAM(empty_value)) {
        this->insertDir(getHomeDirKeyName(), getHomeDirPath());
        this->insertDir(getExeDirKeyName(), getExeDirPath());
    }

    Asset(PathMap const & dirs) {
        this->_dirs = dirs;
    }

    Asset(Asset const & obj) {
        this->copy(obj);
    }

    Asset(Asset && obj) {
        this->swap(obj);
    }

    virtual ~Asset() {
        __EMPTY_BLOCK__
    }

public:
    Asset & operator =(Asset const & obj) {
        return this->copy(obj);
    }

    Asset & operator =(Asset && obj) {
        this->swap(obj);
        return *this;
    }

public:
    Asset & copy(Asset const & obj) {
        if (this != &obj) {
            this->_dirs = obj._dirs;
        }
        return *this;
    }

    void swap(Asset & obj) {
        if (this != &obj) {
            this->_dirs.swap(obj._dirs);
        }
    }

public:
    /**
     * Obtain directory name.
     *
     * @param key [in] Directory key name.
     *
     * @return
     *  - Empty string: If it can't find.
     *  - Otherwise: Successful find.
     */
    Path getDirPath(String const & key) const {
        try {
            return this->_dirs.at(key);
        } catch (std::out_of_range & e) {
            return Path();
        }
    }

    String getDirString(String const & key) const {
        return getDirPath(key).getString();
    }

    /**
     * Insert directory name.
     *
     * @param key   [in] Directory key name.
     * @param value [in] Directory path.
     */
    void insertDir(String const & key, Path const & value) {
        this->_dirs.insert(std::make_pair(key, value));
    }

    /**
     * Insert directory name.
     *
     * @param key   [in] Directory key name.
     * @param value [in] Directory path string.
     */
    void insertDir(String const & key, String const & value) {
        this->insertDir(key, Path(value));
    }

    std::size_t size() const noexcept(true) {
        return this->_dirs.size();
    }

public:
    std::vector<Path> scanDirWithKey(std::string const & key) const {
        return scanDir(getDirPath(key));
    }

    static std::vector<Path> scanDir(Path const & path) {
        std::vector<Path> result;
        for (auto cursor : filesystem::Common::scanDir(path.getNativeString())) {
            result.push_back(Path(Path::append(path, cursor)));
        }
        return result;
    }

public:
    bool isDirectoryWithKey(std::string const & key) {
        return isDirectory(getDirPath(key));
    }

    static bool isDirectory(Path const & path) {
        return filesystem::Common::isDirectory(path.getNativeString());
    }

// Static methods.
public:
    /** Obtain HOME directory key name. */
    static String getHomeDirKeyName() {
        return String(HOME_DIRECTORY_ASSET_NAME);
    }

    /** Obtain executable file directory key name. */
    static String getExeDirKeyName() {
        return String(EXE_DIRECTORY_ASSET_NAME);
    }

    /** Obtain HOME directory path. */
    static Path getHomeDirPath() {
        using filesystem::Common;
        return Path(Common::getHomeDir());
    }

    /** Obtain executable file directory path. */
    static Path getExeDirPath() {
        using filesystem::Common;
        return Path(Common::getExeDir());
    }

#ifndef CREATE_ASSET_PATH
/** Create a main directory accessor & mutator macro. */
#define CREATE_ASSET_PATH(name, path)                   \
public:                                                 \
    static constexpr ValueType const * const            \
            ASSET_NAME_KEY_##name = #name;              \
    void insert_##name() {                              \
        insertDir(ASSET_NAME_KEY_##name, path);         \
    }                                                   \
    Path get_##name() const {                           \
        return getDirPath(ASSET_NAME_KEY_##name);       \
    }                                                   \
    bool create_##name() const {                        \
        using Common = ::libtbag::filesystem::Common;   \
        return Common::createDir(get_##name());         \
    }                                                   \
    bool remove_##name() const {                        \
        using Common = ::libtbag::filesystem::Common;   \
        return Common::removeDir(get_##name());         \
    }                                                   \
    bool exists_##name() const {                        \
        return isDirectory(get_##name());               \
    }                                                   \
    std::vector<Path> scan_##name() const {             \
        return scanDir(get_##name());                   \
    }                                                   \
private:
#endif

#ifndef CREATE_ASSET_PATH_SUB
/** Create a subdirectory accessor & mutator macro. */
#define CREATE_ASSET_PATH_SUB(name, sub, path)           \
public:                                                  \
    Path get_##name##_##sub() const {                    \
        return getDirPath(ASSET_NAME_KEY_##name) / path; \
    }                                                    \
    bool create_##name##_##sub() const {                 \
        using Common = ::libtbag::filesystem::Common;    \
        return Common::createDir(get_##name##_##sub());  \
    }                                                    \
    bool remove_##name##_##sub() const {                 \
        using Common = ::libtbag::filesystem::Common;    \
        return Common::removeDir(get_##name##_##sub());  \
    }                                                    \
    bool exists_##name##_##sub() const {                 \
        return isDirectory(get_##name##_##sub());        \
    }                                                    \
    std::vector<Path> scan_##name##_##sub() const {      \
        return scanDir(get_##name##_##sub());            \
    }                                                    \
private:
#endif
};

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

#endif // __INCLUDE_LIBTBAG__LIBTBAG_ASSET_HPP__

<|endoftext|>


<commit_before>/*
* Copyright 2018 NXP.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* Neither the name of the NXP Semiconductor nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/

#include <vector>
#include "config.h"
#include "cmd.h"
#include "libuuu.h"

static Config g_config;

#define FSL_VID 0x15A2
#define NXP_VID 0x1FC9

Config::Config()
{
	push_back(ConfigItem("SDPS:", "MX8QXP", NULL,   NXP_VID, 0x012F, 0x0002));
	push_back(ConfigItem("SDPS:", "MX8QM",  "MX8QXP",   NXP_VID, 0x0129, 0x0002));
	push_back(ConfigItem("SDPS:", "MX28",   NULL,   FSL_VID, 0x004f));
	push_back(ConfigItem("SDPS:", "MX815",  NULL,   NXP_VID, 0x013E));
	push_back(ConfigItem("SDP:", "MX7D",    NULL,   FSL_VID, 0x0076));
	push_back(ConfigItem("SDP:", "MX6Q",    NULL,   FSL_VID, 0x0054));
	push_back(ConfigItem("SDP:", "MX6D",    "MX6Q", FSL_VID, 0x0061));
	push_back(ConfigItem("SDP:", "MX6SL",   "MX6Q", FSL_VID, 0x0063));
	push_back(ConfigItem("SDP:", "MX6SX",   "MX6Q", FSL_VID, 0x0071));
	push_back(ConfigItem("SDP:", "MX6UL",   "MX7D", FSL_VID, 0x007D));
	push_back(ConfigItem("SDP:", "MX6ULL",  "MX7D", FSL_VID, 0x0080));
	push_back(ConfigItem("SDP:", "MX6SLL",  "MX7D", NXP_VID, 0x0128));
	push_back(ConfigItem("SDP:", "MX7ULP",   NULL,  NXP_VID, 0x0126));
	push_back(ConfigItem("SDP:", "MXRT106X",  NULL,  NXP_VID, 0x0135));
	push_back(ConfigItem("SDP:", "MX8MM",   "MX8MQ", NXP_VID, 0x0134));
	push_back(ConfigItem("SDP:", "MX8MQ",   "MX8MQ", NXP_VID, 0x012B));
	push_back(ConfigItem("SDPU:", "SPL",    "SPL",  0x0525, 0xB4A4, 0,      0x04FF));
	push_back(ConfigItem("SDPV:", "SPL1",   "SPL",  0x0525, 0xB4A4, 0x0500, 0x9998));
	push_back(ConfigItem("SDPU:", "SPL",    "SPL",  0x0525, 0xB4A4, 0x9999, 0x9999)); /*old i.MX8 MQEVk use bcd 9999*/
	push_back(ConfigItem("FBK:", NULL, NULL, 0x066F, 0x9AFE));
	push_back(ConfigItem("FBK:", NULL, NULL, 0x066F, 0x9BFF));
	push_back(ConfigItem("FB:", NULL, NULL,  0x0525, 0xA4A5));
	push_back(ConfigItem("FB:", NULL, NULL,  0x18D1, 0x0D02));
}

int uuu_for_each_cfg(uuu_show_cfg fn, void *p)
{
	for (size_t i = 0; i < g_config.size(); i++)
	{
		if (fn(g_config[i].m_protocol.c_str(),
			   g_config[i].m_chip.c_str(),
			   g_config[i].m_compatible.c_str(),
			   g_config[i].m_vid,
			   g_config[i].m_pid,
			   g_config[i].m_bcdVerMin,
			   g_config[i].m_bcdVerMax,
			   p))
			return -1;
	}
	return 0;
}

Config * get_config()
{
	return &g_config;
}

ConfigItem * Config::find(uint16_t vid, uint16_t pid, uint16_t ver)
{
	iterator it;
	for (it = begin(); it != end(); it++)
	{
		if (vid == it->m_vid && pid == it->m_pid)
		{
			if (ver >= it->m_bcdVerMin && ver <= it->m_bcdVerMax)
				return &(*it);
		}
	}
	return NULL;
}

Config Config::find(string pro)
{
	Config items;
	iterator it;
	for (it = begin(); it != end(); it++)
	{
		if (it->m_protocol == pro)
			items.push_back(*it);
	}
	return items;
}

int CfgCmd::run(CmdCtx *)
{
	size_t pos = 0;
	string param;

	ConfigItem item;
	param = get_next_param(m_cmd, pos);

	if (str_to_upper(param) == "CFG:")
		param = get_next_param(m_cmd, pos);

	if (param.empty())
	{
		set_last_err_string("Wrong param");
		return -1;
	}

	item.m_protocol = str_to_upper(param);

	while (pos < m_cmd.size())
	{
		param = get_next_param(m_cmd, pos);
		if (param == "-pid")
		{
			param = get_next_param(m_cmd, pos);
			item.m_pid = str_to_uint(param);
			continue;
		}
		if (param == "-vid")
		{
			param = get_next_param(m_cmd, pos);
			item.m_vid = str_to_uint(param);
			continue;
		}
		if (param == "-bcdversion")
		{
			param = get_next_param(m_cmd, pos);
			item.m_bcdVerMin = item.m_bcdVerMax = str_to_uint(param);
			continue;
		}
		if (param == "-bcdmin")
		{
			param = get_next_param(m_cmd, pos);
			item.m_bcdVerMin =  str_to_uint(param);
			continue;
		}
		if (param == "-bcdmax")
		{
			param = get_next_param(m_cmd, pos);
			item.m_bcdVerMax = str_to_uint(param);
			continue;
		}
		if (param == "-chip")
		{
			param = get_next_param(m_cmd, pos);
			item.m_chip = param;
			continue;
		}
		if (param == "-compatible")
		{
			param = get_next_param(m_cmd, pos);
			item.m_compatible = param;
			continue;
		}
	}

	ConfigItem *pItem= g_config.find(item.m_vid, item.m_pid, item.m_bcdVerMax);
	if (pItem)
		*pItem = item;
	else
		g_config.push_back(item);

	return 0;
}
<commit_msg>Add i.MX865 PID information<commit_after>/*
* Copyright 2018 NXP.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* Neither the name of the NXP Semiconductor nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/

#include <vector>
#include "config.h"
#include "cmd.h"
#include "libuuu.h"

static Config g_config;

#define FSL_VID 0x15A2
#define NXP_VID 0x1FC9

Config::Config()
{
	push_back(ConfigItem("SDPS:", "MX8QXP", NULL,   NXP_VID, 0x012F, 0x0002));
	push_back(ConfigItem("SDPS:", "MX8QM",  "MX8QXP",   NXP_VID, 0x0129, 0x0002));
	push_back(ConfigItem("SDPS:", "MX28",   NULL,   FSL_VID, 0x004f));
	push_back(ConfigItem("SDPS:", "MX815",  NULL,   NXP_VID, 0x013E));
	push_back(ConfigItem("SDPS:", "MX865",  "MX815",   NXP_VID, 0x0146));
	push_back(ConfigItem("SDP:", "MX7D",    NULL,   FSL_VID, 0x0076));
	push_back(ConfigItem("SDP:", "MX6Q",    NULL,   FSL_VID, 0x0054));
	push_back(ConfigItem("SDP:", "MX6D",    "MX6Q", FSL_VID, 0x0061));
	push_back(ConfigItem("SDP:", "MX6SL",   "MX6Q", FSL_VID, 0x0063));
	push_back(ConfigItem("SDP:", "MX6SX",   "MX6Q", FSL_VID, 0x0071));
	push_back(ConfigItem("SDP:", "MX6UL",   "MX7D", FSL_VID, 0x007D));
	push_back(ConfigItem("SDP:", "MX6ULL",  "MX7D", FSL_VID, 0x0080));
	push_back(ConfigItem("SDP:", "MX6SLL",  "MX7D", NXP_VID, 0x0128));
	push_back(ConfigItem("SDP:", "MX7ULP",   NULL,  NXP_VID, 0x0126));
	push_back(ConfigItem("SDP:", "MXRT106X",  NULL,  NXP_VID, 0x0135));
	push_back(ConfigItem("SDP:", "MX8MM",   "MX8MQ", NXP_VID, 0x0134));
	push_back(ConfigItem("SDP:", "MX8MQ",   "MX8MQ", NXP_VID, 0x012B));
	push_back(ConfigItem("SDPU:", "SPL",    "SPL",  0x0525, 0xB4A4, 0,      0x04FF));
	push_back(ConfigItem("SDPV:", "SPL1",   "SPL",  0x0525, 0xB4A4, 0x0500, 0x9998));
	push_back(ConfigItem("SDPU:", "SPL",    "SPL",  0x0525, 0xB4A4, 0x9999, 0x9999)); /*old i.MX8 MQEVk use bcd 9999*/
	push_back(ConfigItem("FBK:", NULL, NULL, 0x066F, 0x9AFE));
	push_back(ConfigItem("FBK:", NULL, NULL, 0x066F, 0x9BFF));
	push_back(ConfigItem("FB:", NULL, NULL,  0x0525, 0xA4A5));
	push_back(ConfigItem("FB:", NULL, NULL,  0x18D1, 0x0D02));
}

int uuu_for_each_cfg(uuu_show_cfg fn, void *p)
{
	for (size_t i = 0; i < g_config.size(); i++)
	{
		if (fn(g_config[i].m_protocol.c_str(),
			   g_config[i].m_chip.c_str(),
			   g_config[i].m_compatible.c_str(),
			   g_config[i].m_vid,
			   g_config[i].m_pid,
			   g_config[i].m_bcdVerMin,
			   g_config[i].m_bcdVerMax,
			   p))
			return -1;
	}
	return 0;
}

Config * get_config()
{
	return &g_config;
}

ConfigItem * Config::find(uint16_t vid, uint16_t pid, uint16_t ver)
{
	iterator it;
	for (it = begin(); it != end(); it++)
	{
		if (vid == it->m_vid && pid == it->m_pid)
		{
			if (ver >= it->m_bcdVerMin && ver <= it->m_bcdVerMax)
				return &(*it);
		}
	}
	return NULL;
}

Config Config::find(string pro)
{
	Config items;
	iterator it;
	for (it = begin(); it != end(); it++)
	{
		if (it->m_protocol == pro)
			items.push_back(*it);
	}
	return items;
}

int CfgCmd::run(CmdCtx *)
{
	size_t pos = 0;
	string param;

	ConfigItem item;
	param = get_next_param(m_cmd, pos);

	if (str_to_upper(param) == "CFG:")
		param = get_next_param(m_cmd, pos);

	if (param.empty())
	{
		set_last_err_string("Wrong param");
		return -1;
	}

	item.m_protocol = str_to_upper(param);

	while (pos < m_cmd.size())
	{
		param = get_next_param(m_cmd, pos);
		if (param == "-pid")
		{
			param = get_next_param(m_cmd, pos);
			item.m_pid = str_to_uint(param);
			continue;
		}
		if (param == "-vid")
		{
			param = get_next_param(m_cmd, pos);
			item.m_vid = str_to_uint(param);
			continue;
		}
		if (param == "-bcdversion")
		{
			param = get_next_param(m_cmd, pos);
			item.m_bcdVerMin = item.m_bcdVerMax = str_to_uint(param);
			continue;
		}
		if (param == "-bcdmin")
		{
			param = get_next_param(m_cmd, pos);
			item.m_bcdVerMin =  str_to_uint(param);
			continue;
		}
		if (param == "-bcdmax")
		{
			param = get_next_param(m_cmd, pos);
			item.m_bcdVerMax = str_to_uint(param);
			continue;
		}
		if (param == "-chip")
		{
			param = get_next_param(m_cmd, pos);
			item.m_chip = param;
			continue;
		}
		if (param == "-compatible")
		{
			param = get_next_param(m_cmd, pos);
			item.m_compatible = param;
			continue;
		}
	}

	ConfigItem *pItem= g_config.find(item.m_vid, item.m_pid, item.m_bcdVerMax);
	if (pItem)
		*pItem = item;
	else
		g_config.push_back(item);

	return 0;
}
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2017, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the <organization> nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#include "PosixSerialPort.h"

#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <errno.h>

#include <string>

#ifndef B460800
#define B460800 460800
#endif
#ifndef B921600
#define B921600 921600
#endif

PosixSerialPort::PosixSerialPort(const std::string& name, bool isUsb) :
    SerialPort(name), _devfd(-1), _isUsb(isUsb), _timeout(0),
    _autoFlush(false)
{
}

PosixSerialPort::~PosixSerialPort()
{
    if (_devfd >= 0)
        ::close(_devfd);
}

bool
PosixSerialPort::open(int baud,
                      int data,
                      SerialPort::Parity parity,
                      SerialPort::StopBit stop)
{
    struct termios options;
    speed_t speed;
    // Try opening port assuming _name is full path. If it fails
    // try "/dev/" + _name
    _devfd = ::open(_name.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
    if (_devfd == -1)
    {
        std::string dev("/dev/");
        dev += _name;
        _devfd = ::open(dev.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
        if (_devfd == -1)
            return false;
    }

    if (tcgetattr(_devfd, &options) == -1)
    {
        close();
        return false;
    }

    switch (baud)
    {
    case 1200:
        speed = B1200;
        break;
    case 9600:
        speed = B9600;
        break;
    case 19200:
        speed = B19200;
        break;
    case 38400:
        speed = B38400;
        break;
    case 57600:
        speed = B57600;
        break;
    case 115200:
        speed = B115200;
        break;
    case 230400:
        speed = B230400;
        break;
    case 460800:
        speed = B460800;
        break;
    case 921600:
        speed = B921600;
        break;
    default:
        close();
        return false;
    }

    if (cfsetispeed(&options, speed) || cfsetospeed(&options, speed))
    {
        close();
        return false;
    }

    options.c_cflag |= (CLOCAL | CREAD);

    switch (data)
    {
        case 8:
            options.c_cflag &= ~CSIZE;
            options.c_cflag |= CS8;
            break;
        case 7:
            options.c_cflag &= ~CSIZE;
            options.c_cflag |= CS7;
            break;
        default:
            close();
            return false;
    }

    switch (parity)
    {
        case SerialPort::ParityNone:
            options.c_cflag &= ~PARENB;
            options.c_cflag &= ~PARODD;
            options.c_iflag &= ~(INPCK | ISTRIP);
            break;
        case SerialPort::ParityOdd:
            options.c_cflag |= PARENB;
            options.c_cflag |= PARODD;
            options.c_iflag |= (INPCK | ISTRIP);
            break;
        case SerialPort::ParityEven:
            options.c_cflag |= PARENB;
            options.c_cflag &= ~PARODD;
            options.c_iflag |= (INPCK | ISTRIP);
            break;
        default:
            close();
            return false;
    }

    switch (stop)
    {
    case StopBitOne:
        options.c_cflag &= ~CSTOPB;
        break;
    case StopBitTwo:
        options.c_cflag |= CSTOPB;
        break;
    default:
        close();
        return false;
    }

    // No hardware flow control
    options.c_cflag &= ~CRTSCTS;

    // No software flow control
    options.c_iflag &= ~(IXON | IXOFF | IXANY);

    // Raw input
    options.c_iflag &= ~(BRKINT | ICRNL);
    options.c_lflag &= ~(ICANON | IEXTEN | ECHO | ECHOE | ISIG);

    // Raw output
    options.c_oflag &= ~OPOST;

    // No wait time
    options.c_cc[VMIN]  = 0;
    options.c_cc[VTIME] = 0;

    if (tcsetattr(_devfd, TCSANOW, &options))
    {
        close();
        return false;
    }

    return true;
}

void
PosixSerialPort::close()
{
    if (_devfd >= 0)
        ::close(_devfd);
    _devfd = -1;
}

int
PosixSerialPort::read(uint8_t* buffer, int len)
{
    fd_set fds;
    struct timeval tv;
    int numread = 0;
    int retval;

    if (_devfd == -1)
        return -1;

    while (numread < len)
    {
        FD_ZERO(&fds);
        FD_SET(_devfd, &fds);

        tv.tv_sec  = _timeout / 1000;
        tv.tv_usec = (_timeout % 1000) * 1000;

        retval = select(_devfd + 1, &fds, NULL, NULL, &tv);

        if (retval < 0)
        {
            return -1;
        }
        else if (retval == 0)
        {
            return numread;
        }
        else if (FD_ISSET(_devfd, &fds))
        {
            retval = ::read(_devfd, (uint8_t*) buffer + numread, len - numread);
            if (retval < 0)
                return -1;
            numread += retval;
        }
    }

    return numread;
}

int
PosixSerialPort::write(const uint8_t* buffer, int len)
{
    if (_devfd == -1)
        return -1;

    int res = ::write(_devfd, buffer, len);
    // Used on macos to avoid upload errors
    if (_autoFlush)
        flush();
    return res;
}

int
PosixSerialPort::get()
{
    uint8_t byte;

    if (_devfd == -1)
        return -1;

    if (read(&byte, 1) != 1)
        return -1;

    return byte;
}

int
PosixSerialPort::put(int c)
{
    uint8_t byte;

    byte = c;
    return write(&byte, 1);
}

void
PosixSerialPort::flush()
{
    // There isn't a reliable way to flush on a file descriptor
    // so we just wait it out.  One millisecond is the USB poll
    // interval so that should cover it.
    usleep(1000);
}

bool
PosixSerialPort::timeout(int millisecs)
{
    _timeout = millisecs;
    return true;
}

void
PosixSerialPort::setDTR(bool dtr)
{
    if (_devfd == -1)
        return;

    int iFlags = TIOCM_DTR;

    ioctl(_devfd, (dtr ? TIOCMBIS : TIOCMBIC), &iFlags);
}

void
PosixSerialPort::setRTS(bool rts)
{
    if (_devfd == -1)
        return;

    int iFlags = TIOCM_RTS;

    ioctl(_devfd, (rts ? TIOCMBIS : TIOCMBIC), &iFlags);
}

void
PosixSerialPort::setAutoFlush(bool autoflush)
{
    _autoFlush = autoflush;
}
<commit_msg>Added proper include for ioctl() used by the 1200bps hack<commit_after>///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2017, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the <organization> nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#include "PosixSerialPort.h"

#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>

#include <string>

#ifndef B460800
#define B460800 460800
#endif
#ifndef B921600
#define B921600 921600
#endif

PosixSerialPort::PosixSerialPort(const std::string& name, bool isUsb) :
    SerialPort(name), _devfd(-1), _isUsb(isUsb), _timeout(0),
    _autoFlush(false)
{
}

PosixSerialPort::~PosixSerialPort()
{
    if (_devfd >= 0)
        ::close(_devfd);
}

bool
PosixSerialPort::open(int baud,
                      int data,
                      SerialPort::Parity parity,
                      SerialPort::StopBit stop)
{
    struct termios options;
    speed_t speed;
    // Try opening port assuming _name is full path. If it fails
    // try "/dev/" + _name
    _devfd = ::open(_name.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
    if (_devfd == -1)
    {
        std::string dev("/dev/");
        dev += _name;
        _devfd = ::open(dev.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
        if (_devfd == -1)
            return false;
    }

    if (tcgetattr(_devfd, &options) == -1)
    {
        close();
        return false;
    }

    switch (baud)
    {
    case 1200:
        speed = B1200;
        break;
    case 9600:
        speed = B9600;
        break;
    case 19200:
        speed = B19200;
        break;
    case 38400:
        speed = B38400;
        break;
    case 57600:
        speed = B57600;
        break;
    case 115200:
        speed = B115200;
        break;
    case 230400:
        speed = B230400;
        break;
    case 460800:
        speed = B460800;
        break;
    case 921600:
        speed = B921600;
        break;
    default:
        close();
        return false;
    }

    if (cfsetispeed(&options, speed) || cfsetospeed(&options, speed))
    {
        close();
        return false;
    }

    options.c_cflag |= (CLOCAL | CREAD);

    switch (data)
    {
        case 8:
            options.c_cflag &= ~CSIZE;
            options.c_cflag |= CS8;
            break;
        case 7:
            options.c_cflag &= ~CSIZE;
            options.c_cflag |= CS7;
            break;
        default:
            close();
            return false;
    }

    switch (parity)
    {
        case SerialPort::ParityNone:
            options.c_cflag &= ~PARENB;
            options.c_cflag &= ~PARODD;
            options.c_iflag &= ~(INPCK | ISTRIP);
            break;
        case SerialPort::ParityOdd:
            options.c_cflag |= PARENB;
            options.c_cflag |= PARODD;
            options.c_iflag |= (INPCK | ISTRIP);
            break;
        case SerialPort::ParityEven:
            options.c_cflag |= PARENB;
            options.c_cflag &= ~PARODD;
            options.c_iflag |= (INPCK | ISTRIP);
            break;
        default:
            close();
            return false;
    }

    switch (stop)
    {
    case StopBitOne:
        options.c_cflag &= ~CSTOPB;
        break;
    case StopBitTwo:
        options.c_cflag |= CSTOPB;
        break;
    default:
        close();
        return false;
    }

    // No hardware flow control
    options.c_cflag &= ~CRTSCTS;

    // No software flow control
    options.c_iflag &= ~(IXON | IXOFF | IXANY);

    // Raw input
    options.c_iflag &= ~(BRKINT | ICRNL);
    options.c_lflag &= ~(ICANON | IEXTEN | ECHO | ECHOE | ISIG);

    // Raw output
    options.c_oflag &= ~OPOST;

    // No wait time
    options.c_cc[VMIN]  = 0;
    options.c_cc[VTIME] = 0;

    if (tcsetattr(_devfd, TCSANOW, &options))
    {
        close();
        return false;
    }

    return true;
}

void
PosixSerialPort::close()
{
    if (_devfd >= 0)
        ::close(_devfd);
    _devfd = -1;
}

int
PosixSerialPort::read(uint8_t* buffer, int len)
{
    fd_set fds;
    struct timeval tv;
    int numread = 0;
    int retval;

    if (_devfd == -1)
        return -1;

    while (numread < len)
    {
        FD_ZERO(&fds);
        FD_SET(_devfd, &fds);

        tv.tv_sec  = _timeout / 1000;
        tv.tv_usec = (_timeout % 1000) * 1000;

        retval = select(_devfd + 1, &fds, NULL, NULL, &tv);

        if (retval < 0)
        {
            return -1;
        }
        else if (retval == 0)
        {
            return numread;
        }
        else if (FD_ISSET(_devfd, &fds))
        {
            retval = ::read(_devfd, (uint8_t*) buffer + numread, len - numread);
            if (retval < 0)
                return -1;
            numread += retval;
        }
    }

    return numread;
}

int
PosixSerialPort::write(const uint8_t* buffer, int len)
{
    if (_devfd == -1)
        return -1;

    int res = ::write(_devfd, buffer, len);
    // Used on macos to avoid upload errors
    if (_autoFlush)
        flush();
    return res;
}

int
PosixSerialPort::get()
{
    uint8_t byte;

    if (_devfd == -1)
        return -1;

    if (read(&byte, 1) != 1)
        return -1;

    return byte;
}

int
PosixSerialPort::put(int c)
{
    uint8_t byte;

    byte = c;
    return write(&byte, 1);
}

void
PosixSerialPort::flush()
{
    // There isn't a reliable way to flush on a file descriptor
    // so we just wait it out.  One millisecond is the USB poll
    // interval so that should cover it.
    usleep(1000);
}

bool
PosixSerialPort::timeout(int millisecs)
{
    _timeout = millisecs;
    return true;
}

void
PosixSerialPort::setDTR(bool dtr)
{
    if (_devfd == -1)
        return;

    int iFlags = TIOCM_DTR;

    ioctl(_devfd, (dtr ? TIOCMBIS : TIOCMBIC), &iFlags);
}

void
PosixSerialPort::setRTS(bool rts)
{
    if (_devfd == -1)
        return;

    int iFlags = TIOCM_RTS;

    ioctl(_devfd, (rts ? TIOCMBIS : TIOCMBIC), &iFlags);
}

void
PosixSerialPort::setAutoFlush(bool autoflush)
{
    _autoFlush = autoflush;
}
<|endoftext|>


<commit_before>// @(#)root/meta:$
// Author: Axel Naumann 2014-05-02

/*************************************************************************
 * Copyright (C) 1995-2014, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// Persistent version of a TClass.                                      //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TProtoClass.h"

#include "TBaseClass.h"
#include "TClass.h"
#include "TDataMember.h"
#include "TList.h"
#include "TListOfDataMembers.h"
#include "TRealData.h"

//______________________________________________________________________________
TProtoClass::TProtoClass(TClass* cl):
   TNamed(*cl), fBase(cl->GetListOfBases()), fData(cl->GetListOfDataMembers()),
   fSizeof(cl->fSizeof), fCanSplit(cl->fCanSplit), fProperty(cl->fProperty)
{
   // Initialize a TProtoClass from a TClass.
   fPRealData = new TList();

   // Build the list of RealData before we access it:
   cl->BuildRealData(0, true /*isTransient*/);
   // The data members are ordered as follows:
   // - this class's data members,
   // - foreach base: base class's data members.
   // fPRealData encodes all TProtoRealData objects with a
   // TObjString to signal a new class.
   TClass* clCurrent = cl;
   for (auto realDataObj: *cl->GetListOfRealData()) {
      TRealData *rd = (TRealData*)realDataObj;
      TClass* clRD = rd->GetDataMember()->GetClass();
      if (clRD != clCurrent) {
         clCurrent = clRD;
         fPRealData->AddLast(new TObjString(clRD->GetName()));
      }
      fPRealData->AddLast(new TProtoRealData(rd));
   }
}

//______________________________________________________________________________
TProtoClass::~TProtoClass()
{
   // Destructor.
   Delete();
}

//______________________________________________________________________________
void TProtoClass::Delete(Option_t* opt /*= ""*/) {
   // Delete the containers that are usually owned by their TClass.
   if (fPRealData) fPRealData->Delete(opt);
   delete fPRealData; fPRealData = 0;
   if (fBase) fBase->Delete(opt);
   delete fBase; fBase = 0;
   if (fData) fData->Delete(opt);
   delete fData; fData = 0;
}

//______________________________________________________________________________
void TProtoClass::FillTClass(TClass* cl) {
   // Move data from this TProtoClass into cl.
   if (cl->fRealData || cl->fBase || cl->fData || cl->fSizeof || cl->fCanSplit
       || cl->fProperty) {
      Error("AdoptProto", "TClass %s already initialized!", cl->GetName());
      return;
   }
   *((TNamed*)cl) = *this;
   cl->fBase = fBase;
   cl->fData = (TListOfDataMembers*)fData;
   cl->fRealData = new TList(); // FIXME: this should really become a THashList!
   TClass* currentRDClass = cl;
   for (TObject* element: *fPRealData) {
      if (element->IsA() == TObjString::Class()) {
         currentRDClass = TClass::GetClass(element->GetName());
         if (!currentRDClass) {
            Error("TProtoClass::FillTClass()", "Cannot find TClass for %s; skipping its members.",
                  element->GetName());
         }
      } else {
         if (!currentRDClass) continue;
         TProtoRealData* prd = (TProtoRealData*)element;
         if (TRealData* rd = prd->CreateRealData(currentRDClass)) {
            cl->fRealData->AddLast(rd);
         }
      }
   }
   cl->fSizeof = fSizeof;
   cl->fCanSplit = fCanSplit;
   cl->fProperty = fProperty;

   // Update pointers to TClass
   for (auto base: *cl->fBase) {
      ((TBaseClass*)base)->SetClass(cl);
   }
   for (auto dm: *cl->fData) {
      ((TDataMember*)dm)->SetClass(cl);
   }
   ((TListOfDataMembers*)cl->fData)->SetClass(cl);

   fBase = 0;
   fData = 0;
   fPRealData->Delete();
   delete fPRealData;
   fPRealData = 0;
}

//______________________________________________________________________________
TProtoClass::TProtoRealData::TProtoRealData(const TRealData* rd):
   TNamed(rd->GetDataMember()->GetName(), rd->GetName()),
   fOffset(rd->GetThisOffset())
{
   // Initialize this from a TRealData object.
   SetBit(kIsObject, rd->IsObject());
}

//______________________________________________________________________________
TProtoClass::TProtoRealData::~TProtoRealData()
{
   // Destructor to pin vtable.
}

//______________________________________________________________________________
TRealData* TProtoClass::TProtoRealData::CreateRealData(TClass* dmClass) const
{
   // Create a TRealData from this, with its data member coming from dmClass.
   TDataMember* dm = (TDataMember*)dmClass->GetListOfDataMembers()->FindObject(GetName());
   if (!dm) {
      Error("TProtoClass::TProtoRealData::CreateRealData()",
            "Cannot find data member %s::%s!", dmClass->GetName(), GetName());
      return 0;
   }
   TRealData* rd = new TRealData(GetTitle(), fOffset, dm);
   rd->SetIsObject(TestBit(kIsObject));
   return rd;
}
<commit_msg>Must call Size(); not the same as fSizeof.<commit_after>// @(#)root/meta:$
// Author: Axel Naumann 2014-05-02

/*************************************************************************
 * Copyright (C) 1995-2014, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// Persistent version of a TClass.                                      //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TProtoClass.h"

#include "TBaseClass.h"
#include "TClass.h"
#include "TDataMember.h"
#include "TList.h"
#include "TListOfDataMembers.h"
#include "TRealData.h"

//______________________________________________________________________________
TProtoClass::TProtoClass(TClass* cl):
   TNamed(*cl), fBase(cl->GetListOfBases()), fData(cl->GetListOfDataMembers()),
   fSizeof(cl->Size()), fCanSplit(cl->fCanSplit), fProperty(cl->fProperty)
{
   // Initialize a TProtoClass from a TClass.
   fPRealData = new TList();

   // Build the list of RealData before we access it:
   cl->BuildRealData(0, true /*isTransient*/);
   // The data members are ordered as follows:
   // - this class's data members,
   // - foreach base: base class's data members.
   // fPRealData encodes all TProtoRealData objects with a
   // TObjString to signal a new class.
   TClass* clCurrent = cl;
   for (auto realDataObj: *cl->GetListOfRealData()) {
      TRealData *rd = (TRealData*)realDataObj;
      TClass* clRD = rd->GetDataMember()->GetClass();
      if (clRD != clCurrent) {
         clCurrent = clRD;
         fPRealData->AddLast(new TObjString(clRD->GetName()));
      }
      fPRealData->AddLast(new TProtoRealData(rd));
   }
}

//______________________________________________________________________________
TProtoClass::~TProtoClass()
{
   // Destructor.
   Delete();
}

//______________________________________________________________________________
void TProtoClass::Delete(Option_t* opt /*= ""*/) {
   // Delete the containers that are usually owned by their TClass.
   if (fPRealData) fPRealData->Delete(opt);
   delete fPRealData; fPRealData = 0;
   if (fBase) fBase->Delete(opt);
   delete fBase; fBase = 0;
   if (fData) fData->Delete(opt);
   delete fData; fData = 0;
}

//______________________________________________________________________________
void TProtoClass::FillTClass(TClass* cl) {
   // Move data from this TProtoClass into cl.
   if (cl->fRealData || cl->fBase || cl->fData || cl->fSizeof != -1 || cl->fCanSplit
       || cl->fProperty) {
      Error("AdoptProto", "TClass %s already initialized!", cl->GetName());
      return;
   }
   *((TNamed*)cl) = *this;
   cl->fBase = fBase;
   cl->fData = (TListOfDataMembers*)fData;
   cl->fRealData = new TList(); // FIXME: this should really become a THashList!
   TClass* currentRDClass = cl;
   for (TObject* element: *fPRealData) {
      if (element->IsA() == TObjString::Class()) {
         currentRDClass = TClass::GetClass(element->GetName());
         if (!currentRDClass) {
            Error("TProtoClass::FillTClass()", "Cannot find TClass for %s; skipping its members.",
                  element->GetName());
         }
      } else {
         if (!currentRDClass) continue;
         TProtoRealData* prd = (TProtoRealData*)element;
         if (TRealData* rd = prd->CreateRealData(currentRDClass)) {
            cl->fRealData->AddLast(rd);
         }
      }
   }
   cl->fSizeof = fSizeof;
   cl->fCanSplit = fCanSplit;
   cl->fProperty = fProperty;

   // Update pointers to TClass
   for (auto base: *cl->fBase) {
      ((TBaseClass*)base)->SetClass(cl);
   }
   for (auto dm: *cl->fData) {
      ((TDataMember*)dm)->SetClass(cl);
   }
   ((TListOfDataMembers*)cl->fData)->SetClass(cl);

   fBase = 0;
   fData = 0;
   fPRealData->Delete();
   delete fPRealData;
   fPRealData = 0;
}

//______________________________________________________________________________
TProtoClass::TProtoRealData::TProtoRealData(const TRealData* rd):
   TNamed(rd->GetDataMember()->GetName(), rd->GetName()),
   fOffset(rd->GetThisOffset())
{
   // Initialize this from a TRealData object.
   SetBit(kIsObject, rd->IsObject());
}

//______________________________________________________________________________
TProtoClass::TProtoRealData::~TProtoRealData()
{
   // Destructor to pin vtable.
}

//______________________________________________________________________________
TRealData* TProtoClass::TProtoRealData::CreateRealData(TClass* dmClass) const
{
   // Create a TRealData from this, with its data member coming from dmClass.
   TDataMember* dm = (TDataMember*)dmClass->GetListOfDataMembers()->FindObject(GetName());
   if (!dm) {
      Error("TProtoClass::TProtoRealData::CreateRealData()",
            "Cannot find data member %s::%s!", dmClass->GetName(), GetName());
      return 0;
   }
   TRealData* rd = new TRealData(GetTitle(), fOffset, dm);
   rd->SetIsObject(TestBit(kIsObject));
   return rd;
}
<|endoftext|>