1//===- CXString.cpp - Routines for manipulating CXStrings -----------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines routines for manipulating CXStrings. It should be the
11// only file that has internal knowledge of the encoding of the data in
12// CXStrings.
13//
14//===----------------------------------------------------------------------===//
15
16#include "CXString.h"
17#include "CXTranslationUnit.h"
18#include "clang-c/Index.h"
19#include "clang/Frontend/ASTUnit.h"
20#include "llvm/ADT/SmallString.h"
21#include "llvm/Support/ErrorHandling.h"
22
23using namespace clang;
24
25/// Describes the kind of underlying data in CXString.
26enum CXStringFlag {
27  /// CXString contains a 'const char *' that it doesn't own.
28  CXS_Unmanaged,
29
30  /// CXString contains a 'const char *' that it allocated with malloc().
31  CXS_Malloc,
32
33  /// CXString contains a CXStringBuf that needs to be returned to the
34  /// CXStringPool.
35  CXS_StringBuf
36};
37
38namespace clang {
39namespace cxstring {
40
41//===----------------------------------------------------------------------===//
42// Basic generation of CXStrings.
43//===----------------------------------------------------------------------===//
44
45CXString createEmpty() {
46  CXString Str;
47  Str.data = "";
48  Str.private_flags = CXS_Unmanaged;
49  return Str;
50}
51
52CXString createNull() {
53  CXString Str;
54  Str.data = nullptr;
55  Str.private_flags = CXS_Unmanaged;
56  return Str;
57}
58
59CXString createRef(const char *String) {
60  if (String && String[0] == '\0')
61    return createEmpty();
62
63  CXString Str;
64  Str.data = String;
65  Str.private_flags = CXS_Unmanaged;
66  return Str;
67}
68
69CXString createDup(const char *String) {
70  if (!String)
71    return createNull();
72
73  if (String[0] == '\0')
74    return createEmpty();
75
76  CXString Str;
77  Str.data = strdup(String);
78  Str.private_flags = CXS_Malloc;
79  return Str;
80}
81
82CXString createRef(StringRef String) {
83  // If the string is not nul-terminated, we have to make a copy.
84
85  // FIXME: This is doing a one past end read, and should be removed! For memory
86  // we don't manage, the API string can become unterminated at any time outside
87  // our control.
88
89  if (!String.empty() && String.data()[String.size()] != 0)
90    return createDup(String);
91
92  CXString Result;
93  Result.data = String.data();
94  Result.private_flags = (unsigned) CXS_Unmanaged;
95  return Result;
96}
97
98CXString createDup(StringRef String) {
99  CXString Result;
100  char *Spelling = static_cast<char *>(malloc(String.size() + 1));
101  memmove(Spelling, String.data(), String.size());
102  Spelling[String.size()] = 0;
103  Result.data = Spelling;
104  Result.private_flags = (unsigned) CXS_Malloc;
105  return Result;
106}
107
108CXString createCXString(CXStringBuf *buf) {
109  CXString Str;
110  Str.data = buf;
111  Str.private_flags = (unsigned) CXS_StringBuf;
112  return Str;
113}
114
115
116//===----------------------------------------------------------------------===//
117// String pools.
118//===----------------------------------------------------------------------===//
119
120CXStringPool::~CXStringPool() {
121  for (std::vector<CXStringBuf *>::iterator I = Pool.begin(), E = Pool.end();
122       I != E; ++I) {
123    delete *I;
124  }
125}
126
127CXStringBuf *CXStringPool::getCXStringBuf(CXTranslationUnit TU) {
128  if (Pool.empty())
129    return new CXStringBuf(TU);
130
131  CXStringBuf *Buf = Pool.back();
132  Buf->Data.clear();
133  Pool.pop_back();
134  return Buf;
135}
136
137CXStringBuf *getCXStringBuf(CXTranslationUnit TU) {
138  return TU->StringPool->getCXStringBuf(TU);
139}
140
141void CXStringBuf::dispose() {
142  TU->StringPool->Pool.push_back(this);
143}
144
145bool isManagedByPool(CXString str) {
146  return ((CXStringFlag) str.private_flags) == CXS_StringBuf;
147}
148
149} // end namespace cxstring
150} // end namespace clang
151
152//===----------------------------------------------------------------------===//
153// libClang public APIs.
154//===----------------------------------------------------------------------===//
155
156extern "C" {
157const char *clang_getCString(CXString string) {
158  if (string.private_flags == (unsigned) CXS_StringBuf) {
159    return static_cast<const cxstring::CXStringBuf *>(string.data)->Data.data();
160  }
161  return static_cast<const char *>(string.data);
162}
163
164void clang_disposeString(CXString string) {
165  switch ((CXStringFlag) string.private_flags) {
166    case CXS_Unmanaged:
167      break;
168    case CXS_Malloc:
169      if (string.data)
170        free(const_cast<void *>(string.data));
171      break;
172    case CXS_StringBuf:
173      static_cast<cxstring::CXStringBuf *>(
174          const_cast<void *>(string.data))->dispose();
175      break;
176  }
177}
178} // end: extern "C"
179
180