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