mirror of https://github.com/mono/CppSharp.git
27 changed files with 8 additions and 4386 deletions
@ -1,48 +0,0 @@ |
|||||||
//===----- CXXABI.h - Interface to C++ ABIs ---------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file is distributed under the University of Illinois Open Source
|
|
||||||
// License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This provides an abstract class for C++ AST support. Concrete
|
|
||||||
// subclasses of this implement AST support for specific C++ ABIs.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef LLVM_CLANG_AST_CXXABI_H |
|
||||||
#define LLVM_CLANG_AST_CXXABI_H |
|
||||||
|
|
||||||
#include "clang/AST/Type.h" |
|
||||||
|
|
||||||
namespace clang { |
|
||||||
|
|
||||||
class ASTContext; |
|
||||||
class MemberPointerType; |
|
||||||
|
|
||||||
/// Implements C++ ABI-specific semantic analysis functions.
|
|
||||||
class CXXABI { |
|
||||||
public: |
|
||||||
virtual ~CXXABI(); |
|
||||||
|
|
||||||
/// Returns the size of a member pointer in multiples of the target
|
|
||||||
/// pointer size.
|
|
||||||
virtual unsigned getMemberPointerSize(const MemberPointerType *MPT) const = 0; |
|
||||||
|
|
||||||
/// Returns the default calling convention for C++ methods.
|
|
||||||
virtual CallingConv getDefaultMethodCallConv() const = 0; |
|
||||||
|
|
||||||
// Returns whether the given class is nearly empty, with just virtual pointers
|
|
||||||
// and no data except possibly virtual bases.
|
|
||||||
virtual bool isNearlyEmpty(const CXXRecordDecl *RD) const = 0; |
|
||||||
}; |
|
||||||
|
|
||||||
/// Creates an instance of a C++ ABI class.
|
|
||||||
CXXABI *CreateARMCXXABI(ASTContext &Ctx); |
|
||||||
CXXABI *CreateItaniumCXXABI(ASTContext &Ctx); |
|
||||||
CXXABI *CreateMicrosoftCXXABI(ASTContext &Ctx); |
|
||||||
} |
|
||||||
|
|
||||||
#endif |
|
@ -1,268 +0,0 @@ |
|||||||
/************************************************************************
|
|
||||||
* |
|
||||||
* 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()); |
|
||||||
if (CK->isParamIndexValid() && !CK->isVarArgParam()) |
|
||||||
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; |
|
||||||
} |
|
||||||
} |
|
@ -1,203 +0,0 @@ |
|||||||
// ------------------------------------------------------------------------------------------- //
|
|
||||||
// clix.hpp (from http://blog.nuclex-games.com/mono-dotnet/cxx-cli-string-marshaling)
|
|
||||||
//
|
|
||||||
// Marshals strings between .NET and C++ using C++/CLI (Visual C++ 2005 and later only).
|
|
||||||
// Faster and cleaner than the System::Interop method because it uses garbage collected memory.
|
|
||||||
// Use at your own leisure. No warranties whatsoever provided.
|
|
||||||
//
|
|
||||||
// Original code by Markus Ewald
|
|
||||||
// Updated version including several improvements suggested by Neil Hunt
|
|
||||||
//
|
|
||||||
// Licensed under the IBM CPL (free of charge, closed source commercial use is okay)
|
|
||||||
// ------------------------------------------------------------------------------------------- //
|
|
||||||
#pragma once |
|
||||||
|
|
||||||
#include <string> |
|
||||||
#include <vcclr.h> |
|
||||||
|
|
||||||
// CLI extensions namespace
|
|
||||||
namespace clix { |
|
||||||
|
|
||||||
/// <summary>Encoding types for strings</summary>
|
|
||||||
enum Encoding { |
|
||||||
|
|
||||||
/// <summary>ANSI encoding</summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This is the default encoding you've most likely been using all around in C++. ANSI
|
|
||||||
/// means 8 Bit encoding with character codes depending on the system's selected code page.
|
|
||||||
/// <remarks>
|
|
||||||
E_ANSI, |
|
||||||
|
|
||||||
/// <summary>UTF-8 encoding</summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This is the encoding commonly used for multilingual C++ strings. All ASCII characters
|
|
||||||
/// (0-127) will be represented as single bytes. Be aware that UTF-8 uses more than one
|
|
||||||
/// byte for extended characters, so std::string::length() might not reflect the actual
|
|
||||||
/// length of the string in characters if it contains any non-ASCII characters.
|
|
||||||
/// <remarks>
|
|
||||||
E_UTF8, |
|
||||||
|
|
||||||
/// <summary>UTF-16 encoding</summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This is the suggested to be used for marshaling and the native encoding of .NET
|
|
||||||
/// strings. It is similar to UTF-8 but uses a minimum of two bytes per character, making
|
|
||||||
/// the number of bytes required for a given string better predictable. Be aware, however,
|
|
||||||
/// that UTF-16 can still use more than two bytes for a character, so std::wstring::length()
|
|
||||||
/// might not reflect the actual length of the string.
|
|
||||||
/// </remarks>
|
|
||||||
E_UTF16, E_UNICODE = E_UTF16 |
|
||||||
|
|
||||||
}; |
|
||||||
|
|
||||||
// Ignore this if you're just scanning the headers for informations!
|
|
||||||
/* All this template stuff might seem like overkill, but it is well thought out and enables
|
|
||||||
you to use a readable and convenient call while still keeping the highest possible code |
|
||||||
efficiency due to compile-time evaluation of the required conversion path. |
|
||||||
*/ |
|
||||||
namespace detail { |
|
||||||
|
|
||||||
// Get C++ string type for specified encoding
|
|
||||||
template<Encoding encoding> struct StringTypeSelector; |
|
||||||
template<> struct StringTypeSelector<E_ANSI> { typedef std::string Type; }; |
|
||||||
template<> struct StringTypeSelector<E_UTF8> { typedef std::string Type; }; |
|
||||||
template<> struct StringTypeSelector<E_UTF16> { typedef std::wstring Type; }; |
|
||||||
|
|
||||||
// Compile-time selection depending on whether a string is managed
|
|
||||||
template<typename StringType> struct IfManaged { |
|
||||||
struct Select { |
|
||||||
template<typename TrueType, typename FalseType> |
|
||||||
struct Either { typedef FalseType Type; }; |
|
||||||
}; |
|
||||||
enum { Result = false }; |
|
||||||
}; |
|
||||||
template<> struct IfManaged<System::String ^> { |
|
||||||
struct Select { |
|
||||||
template<typename TrueType, typename FalseType> |
|
||||||
struct Either { typedef TrueType Type; }; |
|
||||||
}; |
|
||||||
enum { Result = true }; |
|
||||||
}; |
|
||||||
|
|
||||||
// Direction of the marshaling process
|
|
||||||
enum MarshalingDirection { |
|
||||||
CxxFromNet, |
|
||||||
NetFromCxx |
|
||||||
}; |
|
||||||
|
|
||||||
// The actual marshaling code
|
|
||||||
template<MarshalingDirection direction> struct StringMarshaler; |
|
||||||
|
|
||||||
// Marshals to .NET from C++ strings
|
|
||||||
template<> struct StringMarshaler<NetFromCxx> { |
|
||||||
|
|
||||||
template<Encoding encoding, typename SourceType> |
|
||||||
static System::String ^marshal(const SourceType &string) { |
|
||||||
// Constructs a std::[w]string in case someone gave us a char * to choke on
|
|
||||||
return marshalCxxString<encoding, SourceType>(string); |
|
||||||
} |
|
||||||
|
|
||||||
template<Encoding encoding, typename SourceType> |
|
||||||
static System::String ^marshalCxxString( |
|
||||||
const typename StringTypeSelector<encoding>::Type &cxxString |
|
||||||
) { |
|
||||||
typedef typename StringTypeSelector<encoding>::Type SourceStringType; |
|
||||||
size_t byteCount = cxxString.length() * sizeof(SourceStringType::value_type); |
|
||||||
|
|
||||||
if(byteCount == 0) return System::String::Empty; |
|
||||||
|
|
||||||
// Copy the C++ string contents into a managed array of bytes
|
|
||||||
array<unsigned char> ^bytes = gcnew array<unsigned char>(byteCount); |
|
||||||
{ pin_ptr<unsigned char> pinnedBytes = &bytes[0]; |
|
||||||
memcpy(pinnedBytes, cxxString.c_str(), byteCount); |
|
||||||
} |
|
||||||
|
|
||||||
// Now let one of .NET's encoding classes do the rest
|
|
||||||
return decode<encoding>(bytes); |
|
||||||
} |
|
||||||
|
|
||||||
private: |
|
||||||
// Converts a byte array based on the selected encoding
|
|
||||||
template<Encoding encoding> static System::String ^decode(array<unsigned char> ^bytes); |
|
||||||
template<> static System::String ^decode<E_ANSI>(array<unsigned char> ^bytes) { |
|
||||||
return System::Text::Encoding::Default->GetString(bytes); |
|
||||||
} |
|
||||||
template<> static System::String ^decode<E_UTF8>(array<unsigned char> ^bytes) { |
|
||||||
return System::Text::Encoding::UTF8->GetString(bytes); |
|
||||||
} |
|
||||||
template<> static System::String ^decode<E_UTF16>(array<unsigned char> ^bytes) { |
|
||||||
return System::Text::Encoding::Unicode->GetString(bytes); |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
// Marshals to C++ strings from .NET
|
|
||||||
template<> struct StringMarshaler<CxxFromNet> { |
|
||||||
|
|
||||||
template<Encoding encoding, typename SourceType> |
|
||||||
static typename detail::StringTypeSelector<encoding>::Type marshal( |
|
||||||
System::String ^string |
|
||||||
) { |
|
||||||
typedef typename StringTypeSelector<encoding>::Type StringType; |
|
||||||
|
|
||||||
// First, we use .NET's encoding classes to convert the string into a byte array
|
|
||||||
array<unsigned char> ^bytes = encode<encoding>(string); |
|
||||||
|
|
||||||
if(bytes->Length == 0) return StringType(); |
|
||||||
|
|
||||||
// Then we construct our native string from that byte array
|
|
||||||
pin_ptr<unsigned char> pinnedBytes(&bytes[0]); |
|
||||||
return StringType( |
|
||||||
reinterpret_cast<StringType::value_type *>(static_cast<unsigned char *>(pinnedBytes)), |
|
||||||
bytes->Length / sizeof(StringType::value_type) |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
template<> static std::wstring marshal<E_UTF16, System::String ^>( |
|
||||||
System::String ^string |
|
||||||
) { |
|
||||||
// We can directly accesss the characters in the managed string
|
|
||||||
pin_ptr<const wchar_t> pinnedChars(::PtrToStringChars(string)); |
|
||||||
return std::wstring(pinnedChars, string->Length); |
|
||||||
} |
|
||||||
|
|
||||||
private: |
|
||||||
// Converts a string based on the selected encoding
|
|
||||||
template<Encoding encoding> static array<unsigned char> ^encode(System::String ^string); |
|
||||||
template<> static array<unsigned char> ^encode<E_ANSI>(System::String ^string) { |
|
||||||
return System::Text::Encoding::Default->GetBytes(string); |
|
||||||
} |
|
||||||
template<> static array<unsigned char> ^encode<E_UTF8>(System::String ^string) { |
|
||||||
return System::Text::Encoding::UTF8->GetBytes(string); |
|
||||||
} |
|
||||||
template<> static array<unsigned char> ^encode<E_UTF16>(System::String ^string) { |
|
||||||
return System::Text::Encoding::Unicode->GetBytes(string); |
|
||||||
} |
|
||||||
|
|
||||||
}; |
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------- //
|
|
||||||
// clix::marshalString()
|
|
||||||
// ----------------------------------------------------------------------------------------- //
|
|
||||||
/// <summary>Marshals strings between .NET managed and C++ native</summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This all-in-one function marshals native C++ strings to .NET strings and vice versa.
|
|
||||||
/// You have to specify an encoding to use for the conversion, which always applies to the
|
|
||||||
/// native C++ string as .NET always uses UTF-16 for its own strings.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="string">String to be marshalled to the other side</param>
|
|
||||||
/// <returns>The marshaled representation of the string</returns>
|
|
||||||
template<Encoding encoding, typename SourceType> |
|
||||||
typename detail::IfManaged<SourceType>::Select::Either< |
|
||||||
typename detail::StringTypeSelector<encoding>::Type, |
|
||||||
System::String ^ |
|
||||||
>::Type marshalString(SourceType string) { |
|
||||||
|
|
||||||
// Pass on the call to our nifty template routines
|
|
||||||
return detail::StringMarshaler< |
|
||||||
detail::IfManaged<SourceType>::Result ? detail::CxxFromNet : detail::NetFromCxx |
|
||||||
>::marshal<encoding, SourceType>(string); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
} // namespace clix
|
|
@ -1,46 +0,0 @@ |
|||||||
/************************************************************************
|
|
||||||
* |
|
||||||
* CppSharp |
|
||||||
* Licensed under the simplified BSD license. All rights reserved. |
|
||||||
* |
|
||||||
************************************************************************/ |
|
||||||
|
|
||||||
#include "Parser.h" |
|
||||||
#include "Interop.h" |
|
||||||
|
|
||||||
namespace CppSharp { namespace Parser { |
|
||||||
|
|
||||||
public ref class ClangParser |
|
||||||
{ |
|
||||||
public: |
|
||||||
|
|
||||||
static ParserTargetInfo^ GetTargetInfo(ParserOptions^ Opts) |
|
||||||
{ |
|
||||||
::Parser parser(Opts); |
|
||||||
return parser.GetTargetInfo(); |
|
||||||
} |
|
||||||
|
|
||||||
static ParserResult^ ParseHeader(ParserOptions^ Opts) |
|
||||||
{ |
|
||||||
if (!Opts->FileName) return nullptr; |
|
||||||
|
|
||||||
using namespace clix; |
|
||||||
std::string File = marshalString<E_UTF8>(Opts->FileName); |
|
||||||
|
|
||||||
::Parser parser(Opts); |
|
||||||
return parser.ParseHeader(File); |
|
||||||
} |
|
||||||
|
|
||||||
static ParserResult^ ParseLibrary(ParserOptions^ Opts) |
|
||||||
{ |
|
||||||
if (!Opts->FileName) return nullptr; |
|
||||||
|
|
||||||
using namespace clix; |
|
||||||
std::string File = marshalString<E_UTF8>(Opts->FileName); |
|
||||||
|
|
||||||
::Parser parser(Opts); |
|
||||||
return parser.ParseLibrary(File); |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
} } |
|
@ -1,102 +0,0 @@ |
|||||||
/************************************************************************
|
|
||||||
* |
|
||||||
* CppSharp |
|
||||||
* Licensed under the simplified BSD license. All rights reserved. |
|
||||||
* |
|
||||||
************************************************************************/ |
|
||||||
|
|
||||||
#using <CppSharp.AST.dll> |
|
||||||
using namespace System::Collections::Generic; |
|
||||||
|
|
||||||
public enum struct CppAbi |
|
||||||
{ |
|
||||||
Itanium, |
|
||||||
Microsoft, |
|
||||||
ARM |
|
||||||
}; |
|
||||||
|
|
||||||
public ref struct ParserOptions |
|
||||||
{ |
|
||||||
ParserOptions() |
|
||||||
{ |
|
||||||
Arguments = gcnew List<System::String^>(); |
|
||||||
IncludeDirs = gcnew List<System::String^>(); |
|
||||||
SystemIncludeDirs = gcnew List<System::String^>(); |
|
||||||
Defines = gcnew List<System::String^>(); |
|
||||||
LibraryDirs = gcnew List<System::String^>(); |
|
||||||
MicrosoftMode = false; |
|
||||||
NoStandardIncludes = false; |
|
||||||
NoBuiltinIncludes = false; |
|
||||||
} |
|
||||||
|
|
||||||
List<System::String^>^ Arguments; |
|
||||||
|
|
||||||
// Include directories
|
|
||||||
List<System::String^>^ IncludeDirs; |
|
||||||
List<System::String^>^ SystemIncludeDirs; |
|
||||||
List<System::String^>^ Defines; |
|
||||||
List<System::String^>^ LibraryDirs; |
|
||||||
|
|
||||||
// C/C++ header file name.
|
|
||||||
System::String^ FileName; |
|
||||||
|
|
||||||
CppSharp::AST::ASTContext^ ASTContext; |
|
||||||
|
|
||||||
int ToolSetToUse; |
|
||||||
System::String^ TargetTriple; |
|
||||||
|
|
||||||
bool NoStandardIncludes; |
|
||||||
bool NoBuiltinIncludes; |
|
||||||
bool MicrosoftMode; |
|
||||||
CppAbi Abi; |
|
||||||
|
|
||||||
bool Verbose; |
|
||||||
}; |
|
||||||
|
|
||||||
public enum struct ParserDiagnosticLevel |
|
||||||
{ |
|
||||||
Ignored, |
|
||||||
Note, |
|
||||||
Warning, |
|
||||||
Error, |
|
||||||
Fatal |
|
||||||
}; |
|
||||||
|
|
||||||
public value struct ParserDiagnostic |
|
||||||
{ |
|
||||||
System::String^ FileName; |
|
||||||
System::String^ Message; |
|
||||||
ParserDiagnosticLevel Level; |
|
||||||
int LineNumber; |
|
||||||
int ColumnNumber; |
|
||||||
}; |
|
||||||
|
|
||||||
public enum struct ParserResultKind |
|
||||||
{ |
|
||||||
Success, |
|
||||||
Error, |
|
||||||
FileNotFound |
|
||||||
}; |
|
||||||
|
|
||||||
public ref struct ParserResult |
|
||||||
{ |
|
||||||
ParserResult() |
|
||||||
{ |
|
||||||
Diagnostics = gcnew List<ParserDiagnostic>(); |
|
||||||
} |
|
||||||
|
|
||||||
ParserResultKind Kind; |
|
||||||
List<ParserDiagnostic>^ Diagnostics; |
|
||||||
|
|
||||||
CppSharp::AST::ASTContext^ ASTContext; |
|
||||||
CppSharp::AST::NativeLibrary^ Library; |
|
||||||
}; |
|
||||||
|
|
||||||
enum class SourceLocationKind |
|
||||||
{ |
|
||||||
Invalid, |
|
||||||
Builtin, |
|
||||||
CommandLine, |
|
||||||
System, |
|
||||||
User |
|
||||||
}; |
|
@ -1,130 +0,0 @@ |
|||||||
/************************************************************************
|
|
||||||
* |
|
||||||
* CppSharp |
|
||||||
* Licensed under the simplified BSD license. All rights reserved. |
|
||||||
* |
|
||||||
************************************************************************/ |
|
||||||
|
|
||||||
#using <CppSharp.AST.dll> |
|
||||||
|
|
||||||
#include <llvm/Support/Host.h> |
|
||||||
#include <clang/Frontend/CompilerInstance.h> |
|
||||||
#include <clang/Frontend/CompilerInvocation.h> |
|
||||||
#include <clang/Frontend/ASTConsumers.h> |
|
||||||
#include <clang/Basic/FileManager.h> |
|
||||||
#include <clang/Basic/TargetOptions.h> |
|
||||||
#include <clang/Basic/TargetInfo.h> |
|
||||||
#include <clang/Basic/IdentifierTable.h> |
|
||||||
#include <clang/AST/ASTConsumer.h> |
|
||||||
#include <clang/AST/Mangle.h> |
|
||||||
#include <clang/AST/RawCommentList.h> |
|
||||||
#include <clang/AST/Comment.h> |
|
||||||
#include <clang/AST/RecordLayout.h> |
|
||||||
#include <clang/AST/VTableBuilder.h> |
|
||||||
#include <clang/Lex/Preprocessor.h> |
|
||||||
#include <clang/Lex/PreprocessingRecord.h> |
|
||||||
#include <clang/Parse/ParseAST.h> |
|
||||||
#include <clang/Sema/Sema.h> |
|
||||||
#include "CXXABI.h" |
|
||||||
#include "Options.h" |
|
||||||
#include "Target.h" |
|
||||||
|
|
||||||
#include <vcclr.h> |
|
||||||
#include <string> |
|
||||||
typedef std::string String; |
|
||||||
|
|
||||||
namespace clang { |
|
||||||
class TargetCodeGenInfo; |
|
||||||
namespace CodeGen { |
|
||||||
class CodeGenTypes; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
#define Debug printf |
|
||||||
|
|
||||||
struct Parser |
|
||||||
{ |
|
||||||
Parser(ParserOptions^ Opts); |
|
||||||
|
|
||||||
void SetupHeader(); |
|
||||||
ParserResult^ ParseHeader(const std::string& File); |
|
||||||
ParserResult^ ParseLibrary(const std::string& File); |
|
||||||
ParserResultKind ParseArchive(llvm::StringRef File, |
|
||||||
llvm::MemoryBuffer *Buffer, |
|
||||||
CppSharp::AST::NativeLibrary^ NativeLib); |
|
||||||
ParserResultKind ParseSharedLib(llvm::StringRef File, |
|
||||||
llvm::MemoryBuffer *Buffer, |
|
||||||
CppSharp::AST::NativeLibrary^ NativeLib); |
|
||||||
ParserTargetInfo^ GetTargetInfo(); |
|
||||||
|
|
||||||
protected: |
|
||||||
|
|
||||||
// AST traversers
|
|
||||||
void WalkAST(); |
|
||||||
CppSharp::AST::Declaration^ WalkDeclaration(clang::Decl* D, |
|
||||||
bool IgnoreSystemDecls = true, bool CanBeDefinition = false); |
|
||||||
CppSharp::AST::Declaration^ WalkDeclarationDef(clang::Decl* D); |
|
||||||
CppSharp::AST::Enumeration^ WalkEnum(clang::EnumDecl* ED); |
|
||||||
CppSharp::AST::Function^ WalkFunction(clang::FunctionDecl* FD, bool IsDependent = false, |
|
||||||
bool AddToNamespace = true); |
|
||||||
CppSharp::AST::Class^ WalkRecordCXX(clang::CXXRecordDecl* Record); |
|
||||||
void WalkRecordCXX(clang::CXXRecordDecl* Record, CppSharp::AST::Class^ RC); |
|
||||||
CppSharp::AST::ClassTemplateSpecialization^ |
|
||||||
WalkClassTemplateSpecialization(clang::ClassTemplateSpecializationDecl* CTS); |
|
||||||
CppSharp::AST::ClassTemplatePartialSpecialization^ |
|
||||||
WalkClassTemplatePartialSpecialization(clang::ClassTemplatePartialSpecializationDecl* CTS); |
|
||||||
CppSharp::AST::Method^ WalkMethodCXX(clang::CXXMethodDecl* MD, bool AddToClass = true); |
|
||||||
CppSharp::AST::Field^ WalkFieldCXX(clang::FieldDecl* FD, CppSharp::AST::Class^ Class); |
|
||||||
CppSharp::AST::ClassTemplate^ Parser::WalkClassTemplate(clang::ClassTemplateDecl* TD); |
|
||||||
CppSharp::AST::FunctionTemplate^ Parser::WalkFunctionTemplate( |
|
||||||
clang::FunctionTemplateDecl* TD); |
|
||||||
CppSharp::AST::FunctionTemplateSpecialization^ WalkFunctionTemplateSpec(clang::FunctionTemplateSpecializationInfo* FTS, CppSharp::AST::Function^ Function); |
|
||||||
CppSharp::AST::Variable^ WalkVariable(clang::VarDecl* VD); |
|
||||||
CppSharp::AST::RawComment^ WalkRawComment(const clang::RawComment* RC); |
|
||||||
CppSharp::AST::Type^ WalkType(clang::QualType QualType, clang::TypeLoc* TL = 0, |
|
||||||
bool DesugarType = false); |
|
||||||
CppSharp::AST::TemplateArgument WalkTemplateArgument(const clang::TemplateArgument& TA, clang::TemplateArgumentLoc* ArgLoc); |
|
||||||
List<CppSharp::AST::TemplateArgument>^ WalkTemplateArgumentList(const clang::TemplateArgumentList* TAL, clang::TemplateSpecializationTypeLoc* TSTL); |
|
||||||
List<CppSharp::AST::TemplateArgument>^ WalkTemplateArgumentList(const clang::TemplateArgumentList* TAL, const clang::ASTTemplateArgumentListInfo* TSTL); |
|
||||||
CppSharp::AST::QualifiedType^ WalkQualifiedType(clang::TypeSourceInfo* TSI); |
|
||||||
void WalkVTable(clang::CXXRecordDecl* RD, CppSharp::AST::Class^ C); |
|
||||||
CppSharp::AST::VTableLayout^ WalkVTableLayout(const clang::VTableLayout& VTLayout); |
|
||||||
CppSharp::AST::VTableComponent WalkVTableComponent(const clang::VTableComponent& Component); |
|
||||||
CppSharp::AST::PreprocessedEntity^ WalkPreprocessedEntity(CppSharp::AST::Declaration^ Decl, |
|
||||||
clang::PreprocessedEntity* PPEntity); |
|
||||||
|
|
||||||
// Clang helpers
|
|
||||||
SourceLocationKind GetLocationKind(const clang::SourceLocation& Loc); |
|
||||||
bool IsValidDeclaration(const clang::SourceLocation& Loc); |
|
||||||
std::string GetDeclMangledName(clang::Decl* D, clang::TargetCXXABI ABI, |
|
||||||
bool IsDependent = false); |
|
||||||
std::string GetTypeName(const clang::Type* Type); |
|
||||||
void WalkFunction(clang::FunctionDecl* FD, CppSharp::AST::Function^ F, |
|
||||||
bool IsDependent = false); |
|
||||||
void HandlePreprocessedEntities(CppSharp::AST::Declaration^ Decl); |
|
||||||
void HandlePreprocessedEntities(CppSharp::AST::Declaration^ Decl, clang::SourceRange sourceRange, |
|
||||||
CppSharp::AST::MacroLocation macroLocation = CppSharp::AST::MacroLocation::Unknown); |
|
||||||
bool GetDeclText(clang::SourceRange SR, std::string& Text); |
|
||||||
|
|
||||||
CppSharp::AST::TranslationUnit^ GetTranslationUnit(clang::SourceLocation Loc, |
|
||||||
SourceLocationKind *Kind = 0); |
|
||||||
CppSharp::AST::TranslationUnit^ GetTranslationUnit(const clang::Decl* D); |
|
||||||
|
|
||||||
CppSharp::AST::DeclarationContext^ GetNamespace(clang::Decl* D, clang::DeclContext* Ctx); |
|
||||||
CppSharp::AST::DeclarationContext^ GetNamespace(clang::Decl* D); |
|
||||||
|
|
||||||
void HandleDeclaration(clang::Decl* D, CppSharp::AST::Declaration^ Decl); |
|
||||||
void HandleOriginalText(clang::Decl* D, CppSharp::AST::Declaration^ Decl); |
|
||||||
void HandleComments(clang::Decl* D, CppSharp::AST::Declaration^ Decl); |
|
||||||
void HandleDiagnostics(ParserResult^ res); |
|
||||||
|
|
||||||
int Index; |
|
||||||
gcroot<CppSharp::AST::ASTContext^> Lib; |
|
||||||
gcroot<CppSharp::AST::SymbolContext^> Symbols; |
|
||||||
gcroot<ParserOptions^> Opts; |
|
||||||
llvm::OwningPtr<clang::CompilerInstance> C; |
|
||||||
clang::ASTContext* AST; |
|
||||||
clang::TargetCXXABI::Kind TargetABI; |
|
||||||
clang::TargetCodeGenInfo* CodeGenInfo; |
|
||||||
clang::CodeGen::CodeGenTypes* CodeGenTypes; |
|
||||||
}; |
|
@ -1,51 +0,0 @@ |
|||||||
clang_msvc_flags = |
|
||||||
{ |
|
||||||
"/wd4146", "/wd4244", "/wd4800", "/wd4345", |
|
||||||
"/wd4355", "/wd4996", "/wd4624", "/wd4291" |
|
||||||
} |
|
||||||
|
|
||||||
project "CppSharp.Parser" |
|
||||||
|
|
||||||
kind "SharedLib" |
|
||||||
language "C++" |
|
||||||
SetupNativeProject() |
|
||||||
|
|
||||||
dependson { "CppSharp.AST" } |
|
||||||
flags { common_flags, "Managed" } |
|
||||||
|
|
||||||
usingdirs { libdir } |
|
||||||
|
|
||||||
-- usingdirs is only supported in per-file configs in our |
|
||||||
-- premake build. remove this once this support is added |
|
||||||
-- at the project level. |
|
||||||
|
|
||||||
configuration { "Main.cpp" } |
|
||||||
flags { "Managed" } |
|
||||||
usingdirs { libdir } |
|
||||||
|
|
||||||
configuration { "Parser.cpp" } |
|
||||||
flags { "Managed" } |
|
||||||
usingdirs { libdir } |
|
||||||
|
|
||||||
configuration { "Comments.cpp" } |
|
||||||
flags { "Managed" } |
|
||||||
usingdirs { libdir } |
|
||||||
|
|
||||||
configuration "vs*" |
|
||||||
buildoptions { clang_msvc_flags } |
|
||||||
files { "VSLookup.cpp" } |
|
||||||
|
|
||||||
configuration "*" |
|
||||||
|
|
||||||
files |
|
||||||
{ |
|
||||||
"*.h", |
|
||||||
"*.cpp", |
|
||||||
"*.lua" |
|
||||||
} |
|
||||||
|
|
||||||
SetupLLVMIncludes() |
|
||||||
SetupLLVMLibs() |
|
||||||
|
|
||||||
configuration "*" |
|
||||||
|
|
@ -1,69 +0,0 @@ |
|||||||
/************************************************************************
|
|
||||||
* |
|
||||||
* CppSharp |
|
||||||
* Licensed under the simplified BSD license. All rights reserved. |
|
||||||
* |
|
||||||
************************************************************************/ |
|
||||||
|
|
||||||
#using <CppSharp.AST.dll> |
|
||||||
using namespace System::Collections::Generic; |
|
||||||
|
|
||||||
public enum ParserIntType |
|
||||||
{ |
|
||||||
NoInt = 0, |
|
||||||
SignedChar, |
|
||||||
UnsignedChar, |
|
||||||
SignedShort, |
|
||||||
UnsignedShort, |
|
||||||
SignedInt, |
|
||||||
UnsignedInt, |
|
||||||
SignedLong, |
|
||||||
UnsignedLong, |
|
||||||
SignedLongLong, |
|
||||||
UnsignedLongLong |
|
||||||
}; |
|
||||||
|
|
||||||
public ref struct ParserTargetInfo |
|
||||||
{ |
|
||||||
System::String^ ABI; |
|
||||||
|
|
||||||
ParserIntType Char16Type; |
|
||||||
ParserIntType Char32Type; |
|
||||||
ParserIntType Int64Type; |
|
||||||
ParserIntType IntMaxType; |
|
||||||
ParserIntType IntPtrType; |
|
||||||
ParserIntType SizeType; |
|
||||||
ParserIntType UIntMaxType; |
|
||||||
ParserIntType WCharType; |
|
||||||
ParserIntType WIntType; |
|
||||||
|
|
||||||
unsigned int BoolAlign; |
|
||||||
unsigned int BoolWidth; |
|
||||||
unsigned int CharAlign; |
|
||||||
unsigned int CharWidth; |
|
||||||
unsigned int Char16Align; |
|
||||||
unsigned int Char16Width; |
|
||||||
unsigned int Char32Align; |
|
||||||
unsigned int Char32Width; |
|
||||||
unsigned int HalfAlign; |
|
||||||
unsigned int HalfWidth; |
|
||||||
unsigned int FloatAlign; |
|
||||||
unsigned int FloatWidth; |
|
||||||
unsigned int DoubleAlign; |
|
||||||
unsigned int DoubleWidth; |
|
||||||
unsigned int ShortAlign; |
|
||||||
unsigned int ShortWidth; |
|
||||||
unsigned int IntAlign; |
|
||||||
unsigned int IntWidth; |
|
||||||
unsigned int IntMaxTWidth; |
|
||||||
unsigned int LongAlign; |
|
||||||
unsigned int LongWidth; |
|
||||||
unsigned int LongDoubleAlign; |
|
||||||
unsigned int LongDoubleWidth; |
|
||||||
unsigned int LongLongAlign; |
|
||||||
unsigned int LongLongWidth; |
|
||||||
unsigned int PointerAlign; |
|
||||||
unsigned int PointerWidth; |
|
||||||
unsigned int WCharAlign; |
|
||||||
unsigned int WCharWidth; |
|
||||||
}; |
|
@ -1,269 +0,0 @@ |
|||||||
/************************************************************************
|
|
||||||
* |
|
||||||
* CppSharp |
|
||||||
* Licensed under the simplified BSD license. All rights reserved. |
|
||||||
* |
|
||||||
************************************************************************/ |
|
||||||
|
|
||||||
#ifdef _MSC_VER |
|
||||||
|
|
||||||
#include <string> |
|
||||||
#include <vector> |
|
||||||
#include <cctype> |
|
||||||
|
|
||||||
// Include the necessary headers to interface with the Windows registry and
|
|
||||||
// environment.
|
|
||||||
#define WIN32_LEAN_AND_MEAN |
|
||||||
#define NOGDI |
|
||||||
#define NOMINMAX |
|
||||||
#include <Windows.h> |
|
||||||
|
|
||||||
/// \brief Read registry string.
|
|
||||||
/// This also supports a means to look for high-versioned keys by use
|
|
||||||
/// of a $VERSION placeholder in the key path.
|
|
||||||
/// $VERSION in the key path is a placeholder for the version number,
|
|
||||||
/// causing the highest value path to be searched for and used.
|
|
||||||
/// I.e. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
|
|
||||||
/// There can be additional characters in the component. Only the numeric
|
|
||||||
/// characters are compared.
|
|
||||||
static bool getSystemRegistryString(const char *keyPath, const char *valueName, |
|
||||||
char *value, size_t maxLength) { |
|
||||||
HKEY hRootKey = NULL; |
|
||||||
HKEY hKey = NULL; |
|
||||||
const char* subKey = NULL; |
|
||||||
DWORD valueType; |
|
||||||
DWORD valueSize = maxLength - 1; |
|
||||||
long lResult; |
|
||||||
bool returnValue = false; |
|
||||||
|
|
||||||
if (strncmp(keyPath, "HKEY_CLASSES_ROOT\\", 18) == 0) { |
|
||||||
hRootKey = HKEY_CLASSES_ROOT; |
|
||||||
subKey = keyPath + 18; |
|
||||||
} else if (strncmp(keyPath, "HKEY_USERS\\", 11) == 0) { |
|
||||||
hRootKey = HKEY_USERS; |
|
||||||
subKey = keyPath + 11; |
|
||||||
} else if (strncmp(keyPath, "HKEY_LOCAL_MACHINE\\", 19) == 0) { |
|
||||||
hRootKey = HKEY_LOCAL_MACHINE; |
|
||||||
subKey = keyPath + 19; |
|
||||||
} else if (strncmp(keyPath, "HKEY_CURRENT_USER\\", 18) == 0) { |
|
||||||
hRootKey = HKEY_CURRENT_USER; |
|
||||||
subKey = keyPath + 18; |
|
||||||
} else { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
const char *placeHolder = strstr(subKey, "$VERSION"); |
|
||||||
char bestName[256]; |
|
||||||
bestName[0] = '\0'; |
|
||||||
// If we have a $VERSION placeholder, do the highest-version search.
|
|
||||||
if (placeHolder) { |
|
||||||
const char *keyEnd = placeHolder - 1; |
|
||||||
const char *nextKey = placeHolder; |
|
||||||
// Find end of previous key.
|
|
||||||
while ((keyEnd > subKey) && (*keyEnd != '\\')) |
|
||||||
keyEnd--; |
|
||||||
// Find end of key containing $VERSION.
|
|
||||||
while (*nextKey && (*nextKey != '\\')) |
|
||||||
nextKey++; |
|
||||||
size_t partialKeyLength = keyEnd - subKey; |
|
||||||
char partialKey[256]; |
|
||||||
if (partialKeyLength > sizeof(partialKey)) |
|
||||||
partialKeyLength = sizeof(partialKey); |
|
||||||
strncpy(partialKey, subKey, partialKeyLength); |
|
||||||
partialKey[partialKeyLength] = '\0'; |
|
||||||
HKEY hTopKey = NULL; |
|
||||||
lResult = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ, &hTopKey); |
|
||||||
if (lResult == ERROR_SUCCESS) { |
|
||||||
char keyName[256]; |
|
||||||
int bestIndex = -1; |
|
||||||
double bestValue = 0.0; |
|
||||||
DWORD index, size = sizeof(keyName) - 1; |
|
||||||
for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL, |
|
||||||
NULL, NULL, NULL) == ERROR_SUCCESS; index++) { |
|
||||||
const char *sp = keyName; |
|
||||||
while (*sp && !isdigit(*sp)) |
|
||||||
sp++; |
|
||||||
if (!*sp) |
|
||||||
continue; |
|
||||||
const char *ep = sp + 1; |
|
||||||
while (*ep && (isdigit(*ep) || (*ep == '.'))) |
|
||||||
ep++; |
|
||||||
char numBuf[32]; |
|
||||||
strncpy(numBuf, sp, sizeof(numBuf) - 1); |
|
||||||
numBuf[sizeof(numBuf) - 1] = '\0'; |
|
||||||
double value = strtod(numBuf, NULL); |
|
||||||
|
|
||||||
// Check if InstallDir key value exists.
|
|
||||||
bool isViableVersion = false; |
|
||||||
|
|
||||||
lResult = RegOpenKeyExA(hTopKey, keyName, 0, KEY_READ, &hKey); |
|
||||||
if (lResult == ERROR_SUCCESS) { |
|
||||||
lResult = RegQueryValueExA(hKey, valueName, NULL, NULL, NULL, NULL); |
|
||||||
if (lResult == ERROR_SUCCESS) |
|
||||||
isViableVersion = true; |
|
||||||
RegCloseKey(hKey); |
|
||||||
} |
|
||||||
|
|
||||||
if (isViableVersion && (value > bestValue)) { |
|
||||||
bestIndex = (int)index; |
|
||||||
bestValue = value; |
|
||||||
strcpy(bestName, keyName); |
|
||||||
} |
|
||||||
size = sizeof(keyName) - 1; |
|
||||||
} |
|
||||||
// If we found the highest versioned key, open the key and get the value.
|
|
||||||
if (bestIndex != -1) { |
|
||||||
// Append rest of key.
|
|
||||||
strncat(bestName, nextKey, sizeof(bestName) - 1); |
|
||||||
bestName[sizeof(bestName) - 1] = '\0'; |
|
||||||
// Open the chosen key path remainder.
|
|
||||||
lResult = RegOpenKeyExA(hTopKey, bestName, 0, KEY_READ, &hKey); |
|
||||||
if (lResult == ERROR_SUCCESS) { |
|
||||||
lResult = RegQueryValueExA(hKey, valueName, NULL, &valueType, |
|
||||||
(LPBYTE)value, &valueSize); |
|
||||||
if (lResult == ERROR_SUCCESS) |
|
||||||
returnValue = true; |
|
||||||
RegCloseKey(hKey); |
|
||||||
} |
|
||||||
} |
|
||||||
RegCloseKey(hTopKey); |
|
||||||
} |
|
||||||
} else { |
|
||||||
lResult = RegOpenKeyExA(hRootKey, subKey, 0, KEY_READ, &hKey); |
|
||||||
if (lResult == ERROR_SUCCESS) { |
|
||||||
lResult = RegQueryValueExA(hKey, valueName, NULL, &valueType, |
|
||||||
(LPBYTE)value, &valueSize); |
|
||||||
if (lResult == ERROR_SUCCESS) |
|
||||||
returnValue = true; |
|
||||||
RegCloseKey(hKey); |
|
||||||
} |
|
||||||
} |
|
||||||
return returnValue; |
|
||||||
} |
|
||||||
|
|
||||||
/// \brief Get Windows SDK installation directory.
|
|
||||||
static bool getWindowsSDKDir(std::string &path) { |
|
||||||
char windowsSDKInstallDir[256]; |
|
||||||
// Try the Windows registry.
|
|
||||||
bool hasSDKDir = getSystemRegistryString( |
|
||||||
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION", |
|
||||||
"InstallationFolder", |
|
||||||
windowsSDKInstallDir, |
|
||||||
sizeof(windowsSDKInstallDir) - 1); |
|
||||||
// If we have both vc80 and vc90, pick version we were compiled with.
|
|
||||||
if (hasSDKDir && windowsSDKInstallDir[0]) { |
|
||||||
path = windowsSDKInstallDir; |
|
||||||
return true; |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
// Get Visual Studio installation directory.
|
|
||||||
static bool getVisualStudioDir(std::string &path) { |
|
||||||
// First check the environment variables that vsvars32.bat sets.
|
|
||||||
const char* vcinstalldir = getenv("VCINSTALLDIR"); |
|
||||||
if (vcinstalldir) { |
|
||||||
char *p = const_cast<char *>(strstr(vcinstalldir, "\\VC")); |
|
||||||
if (p) |
|
||||||
*p = '\0'; |
|
||||||
path = vcinstalldir; |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
char vsIDEInstallDir[256]; |
|
||||||
char vsExpressIDEInstallDir[256]; |
|
||||||
// Then try the windows registry.
|
|
||||||
bool hasVCDir = getSystemRegistryString( |
|
||||||
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION", |
|
||||||
"InstallDir", vsIDEInstallDir, sizeof(vsIDEInstallDir) - 1); |
|
||||||
bool hasVCExpressDir = getSystemRegistryString( |
|
||||||
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\$VERSION", |
|
||||||
"InstallDir", vsExpressIDEInstallDir, sizeof(vsExpressIDEInstallDir) - 1); |
|
||||||
// If we have both vc80 and vc90, pick version we were compiled with.
|
|
||||||
if (hasVCDir && vsIDEInstallDir[0]) { |
|
||||||
char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE"); |
|
||||||
if (p) |
|
||||||
*p = '\0'; |
|
||||||
path = vsIDEInstallDir; |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
if (hasVCExpressDir && vsExpressIDEInstallDir[0]) { |
|
||||||
char *p = (char*)strstr(vsExpressIDEInstallDir, "\\Common7\\IDE"); |
|
||||||
if (p) |
|
||||||
*p = '\0'; |
|
||||||
path = vsExpressIDEInstallDir; |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
// Try the environment.
|
|
||||||
const char *vs120comntools = getenv("VS120COMNTOOLS"); |
|
||||||
const char *vs110comntools = getenv("VS110COMNTOOLS"); |
|
||||||
const char *vs100comntools = getenv("VS100COMNTOOLS"); |
|
||||||
const char *vs90comntools = getenv("VS90COMNTOOLS"); |
|
||||||
const char *vs80comntools = getenv("VS80COMNTOOLS"); |
|
||||||
const char *vscomntools = NULL; |
|
||||||
|
|
||||||
// Try to find the version that we were compiled with
|
|
||||||
if(false) {} |
|
||||||
#if (_MSC_VER >= 1800) // VC120
|
|
||||||
else if (vs120comntools) { |
|
||||||
vscomntools = vs120comntools; |
|
||||||
} |
|
||||||
#elif (_MSC_VER == 1700) // VC110
|
|
||||||
else if (vs110comntools) { |
|
||||||
vscomntools = vs110comntools; |
|
||||||
} |
|
||||||
#elif (_MSC_VER == 1600) // VC100
|
|
||||||
else if(vs100comntools) { |
|
||||||
vscomntools = vs100comntools; |
|
||||||
} |
|
||||||
#elif (_MSC_VER == 1500) // VC80
|
|
||||||
else if(vs90comntools) { |
|
||||||
vscomntools = vs90comntools; |
|
||||||
} |
|
||||||
#elif (_MSC_VER == 1400) // VC80
|
|
||||||
else if(vs80comntools) { |
|
||||||
vscomntools = vs80comntools; |
|
||||||
} |
|
||||||
#endif |
|
||||||
// Otherwise find any version we can
|
|
||||||
else if (vs120comntools) |
|
||||||
vscomntools = vs120comntools; |
|
||||||
else if (vs110comntools) |
|
||||||
vscomntools = vs110comntools; |
|
||||||
else if (vs100comntools) |
|
||||||
vscomntools = vs100comntools; |
|
||||||
else if (vs90comntools) |
|
||||||
vscomntools = vs90comntools; |
|
||||||
else if (vs80comntools) |
|
||||||
vscomntools = vs80comntools; |
|
||||||
|
|
||||||
if (vscomntools && *vscomntools) { |
|
||||||
const char *p = strstr(vscomntools, "\\Common7\\Tools"); |
|
||||||
path = p ? std::string(vscomntools, p) : vscomntools; |
|
||||||
return true; |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
std::vector<std::string> GetWindowsSystemIncludeDirs() { |
|
||||||
std::vector<std::string> Paths; |
|
||||||
|
|
||||||
std::string VSDir; |
|
||||||
std::string WindowsSDKDir; |
|
||||||
|
|
||||||
// When built with access to the proper Windows APIs, try to actually find
|
|
||||||
// the correct include paths first.
|
|
||||||
if (getVisualStudioDir(VSDir)) { |
|
||||||
Paths.push_back(VSDir + "\\VC\\include"); |
|
||||||
if (getWindowsSDKDir(WindowsSDKDir)) |
|
||||||
Paths.push_back(WindowsSDKDir + "\\include"); |
|
||||||
else |
|
||||||
Paths.push_back(VSDir + "\\VC\\PlatformSDK\\Include"); |
|
||||||
} |
|
||||||
|
|
||||||
return Paths; |
|
||||||
} |
|
||||||
|
|
||||||
#endif |
|
Loading…
Reference in new issue