• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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