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 
    116 //===----------------------------------------------------------------------===//
    117 // String pools.
    118 //===----------------------------------------------------------------------===//
    119 
    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 
    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 
    137 CXStringBuf *getCXStringBuf(CXTranslationUnit TU) {
    138   return TU->StringPool->getCXStringBuf(TU);
    139 }
    140 
    141 void CXStringBuf::dispose() {
    142   TU->StringPool->Pool.push_back(this);
    143 }
    144 
    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" {
    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 
    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