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(String); |
76 | Str.private_flags = CXS_Malloc; |
77 | return Str; |
78 | } |
79 | |
80 | CXString createRef(StringRef String) { |
81 | // If the string is not nul-terminated, we have to make a copy. |
82 | |
83 | // FIXME: This is doing a one past end read, and should be removed! For memory |
84 | // we don't manage, the API string can become unterminated at any time outside |
85 | // our control. |
86 | |
87 | if (!String.empty() && String.data()[String.size()] != 0) |
88 | return createDup(String); |
89 | |
90 | CXString Result; |
91 | Result.data = String.data(); |
92 | Result.private_flags = (unsigned) CXS_Unmanaged; |
93 | return Result; |
94 | } |
95 | |
96 | CXString createDup(StringRef String) { |
97 | CXString Result; |
98 | char *Spelling = static_cast<char *>(llvm::safe_malloc(String.size() + 1)); |
99 | memmove(Spelling, String.data(), String.size()); |
100 | Spelling[String.size()] = 0; |
101 | Result.data = Spelling; |
102 | Result.private_flags = (unsigned) CXS_Malloc; |
103 | return Result; |
104 | } |
105 | |
106 | CXString createCXString(CXStringBuf *buf) { |
107 | CXString Str; |
108 | Str.data = buf; |
109 | Str.private_flags = (unsigned) CXS_StringBuf; |
110 | return Str; |
111 | } |
112 | |
113 | CXStringSet *createSet(const std::vector<std::string> &Strings) { |
114 | CXStringSet *Set = new CXStringSet; |
115 | Set->Count = Strings.size(); |
116 | Set->Strings = new CXString[Set->Count]; |
117 | for (unsigned SI = 0, SE = Set->Count; SI < SE; ++SI) |
118 | Set->Strings[SI] = createDup(Strings[SI]); |
119 | return Set; |
120 | } |
121 | |
122 | |
123 | //===----------------------------------------------------------------------===// |
124 | // String pools. |
125 | //===----------------------------------------------------------------------===// |
126 | |
127 | CXStringPool::~CXStringPool() { |
128 | for (std::vector<CXStringBuf *>::iterator I = Pool.begin(), E = Pool.end(); |
129 | I != E; ++I) { |
130 | delete *I; |
131 | } |
132 | } |
133 | |
134 | CXStringBuf *CXStringPool::getCXStringBuf(CXTranslationUnit TU) { |
135 | if (Pool.empty()) |
136 | return new CXStringBuf(TU); |
137 | |
138 | CXStringBuf *Buf = Pool.back(); |
139 | Buf->Data.clear(); |
140 | Pool.pop_back(); |
141 | return Buf; |
142 | } |
143 | |
144 | CXStringBuf *getCXStringBuf(CXTranslationUnit TU) { |
145 | return TU->StringPool->getCXStringBuf(TU); |
146 | } |
147 | |
148 | void CXStringBuf::dispose() { |
149 | TU->StringPool->Pool.push_back(this); |
150 | } |
151 | |
152 | bool isManagedByPool(CXString str) { |
153 | return ((CXStringFlag) str.private_flags) == CXS_StringBuf; |
154 | } |
155 | |
156 | } // end namespace cxstring |
157 | } // end namespace clang |
158 | |
159 | //===----------------------------------------------------------------------===// |
160 | // libClang public APIs. |
161 | //===----------------------------------------------------------------------===// |
162 | |
163 | const char *clang_getCString(CXString string) { |
164 | if (string.private_flags == (unsigned) CXS_StringBuf) { |
165 | return static_cast<const cxstring::CXStringBuf *>(string.data)->Data.data(); |
166 | } |
167 | return static_cast<const char *>(string.data); |
168 | } |
169 | |
170 | void clang_disposeString(CXString string) { |
171 | switch ((CXStringFlag) string.private_flags) { |
172 | case CXS_Unmanaged: |
173 | break; |
174 | case CXS_Malloc: |
175 | if (string.data) |
176 | free(const_cast<void *>(string.data)); |
177 | break; |
178 | case CXS_StringBuf: |
179 | static_cast<cxstring::CXStringBuf *>( |
180 | const_cast<void *>(string.data))->dispose(); |
181 | break; |
182 | } |
183 | } |
184 | |
185 | void clang_disposeStringSet(CXStringSet *set) { |
186 | for (unsigned SI = 0, SE = set->Count; SI < SE; ++SI) |
187 | clang_disposeString(set->Strings[SI]); |
188 | delete[] set->Strings; |
189 | delete set; |
190 | } |
191 | |
192 |