2010-11-16 10:03:55 +08:00
|
|
|
//===- CXString.cpp - Routines for manipulating CXStrings -----------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file defines routines for manipulating CXStrings. It should be the
|
|
|
|
// only file that has internal knowledge of the encoding of the data in
|
|
|
|
// CXStrings.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "CXString.h"
|
2010-11-18 07:24:11 +08:00
|
|
|
#include "CXTranslationUnit.h"
|
2010-11-16 10:03:55 +08:00
|
|
|
#include "clang-c/Index.h"
|
2012-12-04 17:25:21 +08:00
|
|
|
#include "clang/Frontend/ASTUnit.h"
|
2010-11-16 16:15:36 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
2010-11-16 10:03:55 +08:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
|
|
|
|
using namespace clang;
|
|
|
|
|
2013-02-02 00:36:31 +08:00
|
|
|
/// Describes the kind of underlying data in CXString.
|
|
|
|
enum CXStringFlag {
|
|
|
|
/// CXString contains a 'const char *' that it doesn't own.
|
|
|
|
CXS_Unmanaged,
|
|
|
|
|
|
|
|
/// CXString contains a 'const char *' that it allocated with malloc().
|
|
|
|
CXS_Malloc,
|
|
|
|
|
|
|
|
/// CXString contains a CXStringBuf that needs to be returned to the
|
|
|
|
/// CXStringPool.
|
|
|
|
CXS_StringBuf
|
|
|
|
};
|
2010-11-16 16:15:36 +08:00
|
|
|
|
2013-02-03 21:54:26 +08:00
|
|
|
namespace clang {
|
|
|
|
namespace cxstring {
|
|
|
|
|
2010-11-16 16:15:36 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Basic generation of CXStrings.
|
|
|
|
//===----------------------------------------------------------------------===//
|
2010-11-16 10:03:55 +08:00
|
|
|
|
2013-02-03 21:54:26 +08:00
|
|
|
CXString createEmpty() {
|
2013-02-01 22:21:22 +08:00
|
|
|
CXString Str;
|
|
|
|
Str.data = "";
|
|
|
|
Str.private_flags = CXS_Unmanaged;
|
|
|
|
return Str;
|
|
|
|
}
|
|
|
|
|
2013-02-03 21:54:26 +08:00
|
|
|
CXString createNull() {
|
2013-02-01 22:13:32 +08:00
|
|
|
CXString Str;
|
2014-06-08 16:38:04 +08:00
|
|
|
Str.data = nullptr;
|
2013-02-01 22:13:32 +08:00
|
|
|
Str.private_flags = CXS_Unmanaged;
|
|
|
|
return Str;
|
|
|
|
}
|
|
|
|
|
2013-02-03 21:54:26 +08:00
|
|
|
CXString createRef(const char *String) {
|
2013-02-02 08:02:12 +08:00
|
|
|
if (String && String[0] == '\0')
|
2013-02-03 21:54:26 +08:00
|
|
|
return createEmpty();
|
2013-02-02 08:02:12 +08:00
|
|
|
|
|
|
|
CXString Str;
|
|
|
|
Str.data = String;
|
|
|
|
Str.private_flags = CXS_Unmanaged;
|
|
|
|
return Str;
|
|
|
|
}
|
|
|
|
|
2013-02-03 21:54:26 +08:00
|
|
|
CXString createDup(const char *String) {
|
2013-02-02 08:02:12 +08:00
|
|
|
if (!String)
|
2013-02-03 21:54:26 +08:00
|
|
|
return createNull();
|
2013-02-02 08:02:12 +08:00
|
|
|
|
|
|
|
if (String[0] == '\0')
|
2013-02-03 21:54:26 +08:00
|
|
|
return createEmpty();
|
2013-02-02 08:02:12 +08:00
|
|
|
|
2010-11-16 10:03:55 +08:00
|
|
|
CXString Str;
|
2013-02-02 08:02:12 +08:00
|
|
|
Str.data = strdup(String);
|
|
|
|
Str.private_flags = CXS_Malloc;
|
2010-11-16 10:03:55 +08:00
|
|
|
return Str;
|
|
|
|
}
|
|
|
|
|
2013-02-03 21:54:26 +08:00
|
|
|
CXString createRef(StringRef String) {
|
2013-02-02 10:19:29 +08:00
|
|
|
// If the string is not nul-terminated, we have to make a copy.
|
2014-06-08 07:30:53 +08:00
|
|
|
|
|
|
|
// FIXME: This is doing a one past end read, and should be removed! For memory
|
|
|
|
// we don't manage, the API string can become unterminated at any time outside
|
|
|
|
// our control.
|
|
|
|
|
2013-02-02 10:19:29 +08:00
|
|
|
if (!String.empty() && String.data()[String.size()] != 0)
|
2013-02-03 21:54:26 +08:00
|
|
|
return createDup(String);
|
2013-02-02 10:19:29 +08:00
|
|
|
|
2010-11-16 10:03:55 +08:00
|
|
|
CXString Result;
|
2013-02-02 10:19:29 +08:00
|
|
|
Result.data = String.data();
|
|
|
|
Result.private_flags = (unsigned) CXS_Unmanaged;
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2013-02-03 21:54:26 +08:00
|
|
|
CXString createDup(StringRef String) {
|
2013-02-02 10:19:29 +08:00
|
|
|
CXString Result;
|
|
|
|
char *Spelling = static_cast<char *>(malloc(String.size() + 1));
|
|
|
|
memmove(Spelling, String.data(), String.size());
|
|
|
|
Spelling[String.size()] = 0;
|
|
|
|
Result.data = Spelling;
|
|
|
|
Result.private_flags = (unsigned) CXS_Malloc;
|
2010-11-16 10:03:55 +08:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2013-02-03 21:54:26 +08:00
|
|
|
CXString createCXString(CXStringBuf *buf) {
|
2010-11-16 16:15:36 +08:00
|
|
|
CXString Str;
|
|
|
|
Str.data = buf;
|
|
|
|
Str.private_flags = (unsigned) CXS_StringBuf;
|
|
|
|
return Str;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// String pools.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2013-02-03 21:54:26 +08:00
|
|
|
CXStringPool::~CXStringPool() {
|
2013-01-27 06:44:19 +08:00
|
|
|
for (std::vector<CXStringBuf *>::iterator I = Pool.begin(), E = Pool.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
delete *I;
|
|
|
|
}
|
2010-11-16 16:15:36 +08:00
|
|
|
}
|
|
|
|
|
2013-02-03 21:54:26 +08:00
|
|
|
CXStringBuf *CXStringPool::getCXStringBuf(CXTranslationUnit TU) {
|
2013-01-27 06:44:19 +08:00
|
|
|
if (Pool.empty())
|
|
|
|
return new CXStringBuf(TU);
|
|
|
|
|
|
|
|
CXStringBuf *Buf = Pool.back();
|
|
|
|
Buf->Data.clear();
|
|
|
|
Pool.pop_back();
|
|
|
|
return Buf;
|
2010-11-16 16:15:36 +08:00
|
|
|
}
|
|
|
|
|
2013-02-03 21:54:26 +08:00
|
|
|
CXStringBuf *getCXStringBuf(CXTranslationUnit TU) {
|
2013-01-27 06:44:19 +08:00
|
|
|
return TU->StringPool->getCXStringBuf(TU);
|
2010-11-16 16:15:36 +08:00
|
|
|
}
|
|
|
|
|
2013-02-03 21:54:26 +08:00
|
|
|
void CXStringBuf::dispose() {
|
2013-01-27 06:44:19 +08:00
|
|
|
TU->StringPool->Pool.push_back(this);
|
2010-11-16 16:15:36 +08:00
|
|
|
}
|
|
|
|
|
2013-02-03 21:54:26 +08:00
|
|
|
bool isManagedByPool(CXString str) {
|
2011-08-18 06:19:53 +08:00
|
|
|
return ((CXStringFlag) str.private_flags) == CXS_StringBuf;
|
|
|
|
}
|
|
|
|
|
2013-02-03 21:54:26 +08:00
|
|
|
} // end namespace cxstring
|
|
|
|
} // end namespace clang
|
|
|
|
|
2010-11-16 10:03:55 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// libClang public APIs.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
const char *clang_getCString(CXString string) {
|
2010-11-16 16:15:36 +08:00
|
|
|
if (string.private_flags == (unsigned) CXS_StringBuf) {
|
2013-02-03 21:54:26 +08:00
|
|
|
return static_cast<const cxstring::CXStringBuf *>(string.data)->Data.data();
|
2010-11-16 16:15:36 +08:00
|
|
|
}
|
2013-01-12 07:13:36 +08:00
|
|
|
return static_cast<const char *>(string.data);
|
2010-11-16 10:03:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void clang_disposeString(CXString string) {
|
2010-11-16 16:15:36 +08:00
|
|
|
switch ((CXStringFlag) string.private_flags) {
|
|
|
|
case CXS_Unmanaged:
|
|
|
|
break;
|
|
|
|
case CXS_Malloc:
|
|
|
|
if (string.data)
|
2013-01-12 07:08:18 +08:00
|
|
|
free(const_cast<void *>(string.data));
|
2010-11-16 16:15:36 +08:00
|
|
|
break;
|
|
|
|
case CXS_StringBuf:
|
2013-02-03 21:54:26 +08:00
|
|
|
static_cast<cxstring::CXStringBuf *>(
|
2013-01-27 06:44:19 +08:00
|
|
|
const_cast<void *>(string.data))->dispose();
|
2010-11-16 16:15:36 +08:00
|
|
|
break;
|
|
|
|
}
|
2010-11-16 10:03:55 +08:00
|
|
|
}
|
|
|
|
} // end: extern "C"
|
|
|
|
|