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