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 | return createDup(String); |
91 | } |
92 | |
93 | CXString createDup(StringRef String) { |
94 | CXString Result; |
95 | char *Spelling = static_cast<char *>(llvm::safe_malloc(Sz: String.size() + 1)); |
96 | memmove(dest: Spelling, src: String.data(), n: String.size()); |
97 | Spelling[String.size()] = 0; |
98 | Result.data = Spelling; |
99 | Result.private_flags = (unsigned) CXS_Malloc; |
100 | return Result; |
101 | } |
102 | |
103 | CXString createCXString(CXStringBuf *buf) { |
104 | CXString Str; |
105 | Str.data = buf; |
106 | Str.private_flags = (unsigned) CXS_StringBuf; |
107 | return Str; |
108 | } |
109 | |
110 | CXStringSet *createSet(const std::vector<std::string> &Strings) { |
111 | CXStringSet *Set = new CXStringSet; |
112 | Set->Count = Strings.size(); |
113 | Set->Strings = new CXString[Set->Count]; |
114 | for (unsigned SI = 0, SE = Set->Count; SI < SE; ++SI) |
115 | Set->Strings[SI] = createDup(String: Strings[SI]); |
116 | return Set; |
117 | } |
118 | |
119 | |
120 | //===----------------------------------------------------------------------===// |
121 | // String pools. |
122 | //===----------------------------------------------------------------------===// |
123 | |
124 | CXStringPool::~CXStringPool() { |
125 | for (std::vector<CXStringBuf *>::iterator I = Pool.begin(), E = Pool.end(); |
126 | I != E; ++I) { |
127 | delete *I; |
128 | } |
129 | } |
130 | |
131 | CXStringBuf *CXStringPool::getCXStringBuf(CXTranslationUnit TU) { |
132 | if (Pool.empty()) |
133 | return new CXStringBuf(TU); |
134 | |
135 | CXStringBuf *Buf = Pool.back(); |
136 | Buf->Data.clear(); |
137 | Pool.pop_back(); |
138 | return Buf; |
139 | } |
140 | |
141 | CXStringBuf *getCXStringBuf(CXTranslationUnit TU) { |
142 | return TU->StringPool->getCXStringBuf(TU); |
143 | } |
144 | |
145 | void CXStringBuf::dispose() { |
146 | TU->StringPool->Pool.push_back(x: this); |
147 | } |
148 | |
149 | bool isManagedByPool(CXString str) { |
150 | return ((CXStringFlag) str.private_flags) == CXS_StringBuf; |
151 | } |
152 | |
153 | } // end namespace cxstring |
154 | } // end namespace clang |
155 | |
156 | //===----------------------------------------------------------------------===// |
157 | // libClang public APIs. |
158 | //===----------------------------------------------------------------------===// |
159 | |
160 | const char *clang_getCString(CXString string) { |
161 | if (string.private_flags == (unsigned) CXS_StringBuf) { |
162 | return static_cast<const cxstring::CXStringBuf *>(string.data)->Data.data(); |
163 | } |
164 | return static_cast<const char *>(string.data); |
165 | } |
166 | |
167 | void clang_disposeString(CXString string) { |
168 | switch ((CXStringFlag) string.private_flags) { |
169 | case CXS_Unmanaged: |
170 | break; |
171 | case CXS_Malloc: |
172 | if (string.data) |
173 | free(ptr: const_cast<void *>(string.data)); |
174 | break; |
175 | case CXS_StringBuf: |
176 | static_cast<cxstring::CXStringBuf *>( |
177 | const_cast<void *>(string.data))->dispose(); |
178 | break; |
179 | } |
180 | } |
181 | |
182 | void clang_disposeStringSet(CXStringSet *set) { |
183 | for (unsigned SI = 0, SE = set->Count; SI < SE; ++SI) |
184 | clang_disposeString(string: set->Strings[SI]); |
185 | delete[] set->Strings; |
186 | delete set; |
187 | } |
188 | |
189 | |