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