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
23 using namespace clang;
24
25 /// Describes the kind of underlying data in CXString.
26 enum 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
38 namespace clang {
39 namespace cxstring {
40
41 //===----------------------------------------------------------------------===//
42 // Basic generation of CXStrings.
43 //===----------------------------------------------------------------------===//
44
createEmpty()45 CXString createEmpty() {
46 CXString Str;
47 Str.data = "";
48 Str.private_flags = CXS_Unmanaged;
49 return Str;
50 }
51
createNull()52 CXString createNull() {
53 CXString Str;
54 Str.data = nullptr;
55 Str.private_flags = CXS_Unmanaged;
56 return Str;
57 }
58
createRef(const char * String)59 CXString 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
createDup(const char * String)69 CXString 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
createRef(StringRef String)82 CXString 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
createDup(StringRef String)98 CXString 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
createCXString(CXStringBuf * buf)108 CXString createCXString(CXStringBuf *buf) {
109 CXString Str;
110 Str.data = buf;
111 Str.private_flags = (unsigned) CXS_StringBuf;
112 return Str;
113 }
114
createSet(const std::vector<std::string> & Strings)115 CXStringSet *createSet(const std::vector<std::string> &Strings) {
116 CXStringSet *Set = new CXStringSet;
117 Set->Count = Strings.size();
118 Set->Strings = new CXString[Set->Count];
119 for (unsigned SI = 0, SE = Set->Count; SI < SE; ++SI)
120 Set->Strings[SI] = createDup(Strings[SI]);
121 return Set;
122 }
123
124
125 //===----------------------------------------------------------------------===//
126 // String pools.
127 //===----------------------------------------------------------------------===//
128
~CXStringPool()129 CXStringPool::~CXStringPool() {
130 for (std::vector<CXStringBuf *>::iterator I = Pool.begin(), E = Pool.end();
131 I != E; ++I) {
132 delete *I;
133 }
134 }
135
getCXStringBuf(CXTranslationUnit TU)136 CXStringBuf *CXStringPool::getCXStringBuf(CXTranslationUnit TU) {
137 if (Pool.empty())
138 return new CXStringBuf(TU);
139
140 CXStringBuf *Buf = Pool.back();
141 Buf->Data.clear();
142 Pool.pop_back();
143 return Buf;
144 }
145
getCXStringBuf(CXTranslationUnit TU)146 CXStringBuf *getCXStringBuf(CXTranslationUnit TU) {
147 return TU->StringPool->getCXStringBuf(TU);
148 }
149
dispose()150 void CXStringBuf::dispose() {
151 TU->StringPool->Pool.push_back(this);
152 }
153
isManagedByPool(CXString str)154 bool isManagedByPool(CXString str) {
155 return ((CXStringFlag) str.private_flags) == CXS_StringBuf;
156 }
157
158 } // end namespace cxstring
159 } // end namespace clang
160
161 //===----------------------------------------------------------------------===//
162 // libClang public APIs.
163 //===----------------------------------------------------------------------===//
164
165 extern "C" {
clang_getCString(CXString string)166 const char *clang_getCString(CXString string) {
167 if (string.private_flags == (unsigned) CXS_StringBuf) {
168 return static_cast<const cxstring::CXStringBuf *>(string.data)->Data.data();
169 }
170 return static_cast<const char *>(string.data);
171 }
172
clang_disposeString(CXString string)173 void clang_disposeString(CXString string) {
174 switch ((CXStringFlag) string.private_flags) {
175 case CXS_Unmanaged:
176 break;
177 case CXS_Malloc:
178 if (string.data)
179 free(const_cast<void *>(string.data));
180 break;
181 case CXS_StringBuf:
182 static_cast<cxstring::CXStringBuf *>(
183 const_cast<void *>(string.data))->dispose();
184 break;
185 }
186 }
187
clang_disposeStringSet(CXStringSet * set)188 void clang_disposeStringSet(CXStringSet *set) {
189 for (unsigned SI = 0, SE = set->Count; SI < SE; ++SI)
190 clang_disposeString(set->Strings[SI]);
191 delete[] set->Strings;
192 delete set;
193 }
194
195 } // end: extern "C"
196
197