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