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 44 CXString createEmpty() { 45 CXString Str; 46 Str.data = ""; 47 Str.private_flags = CXS_Unmanaged; 48 return Str; 49 } 50 51 CXString createNull() { 52 CXString Str; 53 Str.data = nullptr; 54 Str.private_flags = CXS_Unmanaged; 55 return Str; 56 } 57 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 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 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 97 CXString createDup(StringRef String) { 98 CXString Result; 99 char *Spelling = static_cast<char *>(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 107 CXString createCXString(CXStringBuf *buf) { 108 CXString Str; 109 Str.data = buf; 110 Str.private_flags = (unsigned) CXS_StringBuf; 111 return Str; 112 } 113 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 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 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 145 CXStringBuf *getCXStringBuf(CXTranslationUnit TU) { 146 return TU->StringPool->getCXStringBuf(TU); 147 } 148 149 void CXStringBuf::dispose() { 150 TU->StringPool->Pool.push_back(this); 151 } 152 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 164 extern "C" { 165 const char *clang_getCString(CXString string) { 166 if (string.private_flags == (unsigned) CXS_StringBuf) { 167 return static_cast<const cxstring::CXStringBuf *>(string.data)->Data.data(); 168 } 169 return static_cast<const char *>(string.data); 170 } 171 172 void clang_disposeString(CXString string) { 173 switch ((CXStringFlag) string.private_flags) { 174 case CXS_Unmanaged: 175 break; 176 case CXS_Malloc: 177 if (string.data) 178 free(const_cast<void *>(string.data)); 179 break; 180 case CXS_StringBuf: 181 static_cast<cxstring::CXStringBuf *>( 182 const_cast<void *>(string.data))->dispose(); 183 break; 184 } 185 } 186 187 void clang_disposeStringSet(CXStringSet *set) { 188 for (unsigned SI = 0, SE = set->Count; SI < SE; ++SI) 189 clang_disposeString(set->Strings[SI]); 190 delete[] set->Strings; 191 delete set; 192 } 193 194 } // end: extern "C" 195 196