Home | History | Annotate | Download | only in libclang
      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 
     45 CXString createEmpty() {
     46   CXString Str;
     47   Str.data = "";
     48   Str.private_flags = CXS_Unmanaged;
     49   return Str;
     50 }
     51 
     52 CXString createNull() {
     53   CXString Str;
     54   Str.data = nullptr;
     55   Str.private_flags = CXS_Unmanaged;
     56   return Str;
     57 }
     58 
     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 
     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 
     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 
     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 
    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 CXStringSet *createSet(const std::vector<std::string> &Strings) {
    116   CXStringSet *Set = new CXStringSet;
    117   Set->Count = Strings.size();
    118   Set->Strings = new CXString[Set->Count];
    119   for (unsigned SI = 0, SE = Set->Count; SI < SE; ++SI)
    120     Set->Strings[SI] = createDup(Strings[SI]);
    121   return Set;
    122 }
    123 
    124 
    125 //===----------------------------------------------------------------------===//
    126 // String pools.
    127 //===----------------------------------------------------------------------===//
    128 
    129 CXStringPool::~CXStringPool() {
    130   for (std::vector<CXStringBuf *>::iterator I = Pool.begin(), E = Pool.end();
    131        I != E; ++I) {
    132     delete *I;
    133   }
    134 }
    135 
    136 CXStringBuf *CXStringPool::getCXStringBuf(CXTranslationUnit TU) {
    137   if (Pool.empty())
    138     return new CXStringBuf(TU);
    139 
    140   CXStringBuf *Buf = Pool.back();
    141   Buf->Data.clear();
    142   Pool.pop_back();
    143   return Buf;
    144 }
    145 
    146 CXStringBuf *getCXStringBuf(CXTranslationUnit TU) {
    147   return TU->StringPool->getCXStringBuf(TU);
    148 }
    149 
    150 void CXStringBuf::dispose() {
    151   TU->StringPool->Pool.push_back(this);
    152 }
    153 
    154 bool isManagedByPool(CXString str) {
    155   return ((CXStringFlag) str.private_flags) == CXS_StringBuf;
    156 }
    157 
    158 } // end namespace cxstring
    159 } // end namespace clang
    160 
    161 //===----------------------------------------------------------------------===//
    162 // libClang public APIs.
    163 //===----------------------------------------------------------------------===//
    164 
    165 extern "C" {
    166 const char *clang_getCString(CXString string) {
    167   if (string.private_flags == (unsigned) CXS_StringBuf) {
    168     return static_cast<const cxstring::CXStringBuf *>(string.data)->Data.data();
    169   }
    170   return static_cast<const char *>(string.data);
    171 }
    172 
    173 void clang_disposeString(CXString string) {
    174   switch ((CXStringFlag) string.private_flags) {
    175     case CXS_Unmanaged:
    176       break;
    177     case CXS_Malloc:
    178       if (string.data)
    179         free(const_cast<void *>(string.data));
    180       break;
    181     case CXS_StringBuf:
    182       static_cast<cxstring::CXStringBuf *>(
    183           const_cast<void *>(string.data))->dispose();
    184       break;
    185   }
    186 }
    187 
    188 void clang_disposeStringSet(CXStringSet *set) {
    189   for (unsigned SI = 0, SE = set->Count; SI < SE; ++SI)
    190     clang_disposeString(set->Strings[SI]);
    191   delete[] set->Strings;
    192   delete set;
    193 }
    194 
    195 } // end: extern "C"
    196 
    197