text: //===- CIndex.cpp - Clang-C Source Indexing Library -----------------------===//
  //
  //                     The LLVM Compiler Infrastructure
  //
  // This file is distributed under the University of Illinois Open Source
  // License. See LICENSE.TXT for details.
  //
  //===----------------------------------------------------------------------===//
  //
  // This file implements the Clang-C Source Indexing library.
  //
  //===----------------------------------------------------------------------===//
  
  #include "CIndexer.h"
  
  #include "clang/AST/Decl.h"
  #include "clang/AST/DeclVisitor.h"
  #include "clang/AST/StmtVisitor.h"
  #include "clang/Basic/FileManager.h"
  #include "clang/Basic/SourceManager.h"
  #include "clang/Basic/Version.h"
  #include "clang/Sema/CodeCompleteConsumer.h"
  #include "llvm/ADT/StringExtras.h"
  #include "llvm/Config/llvm-config.h"
  #include "llvm/Support/Compiler.h"
  #include "llvm/Support/MemoryBuffer.h"
  #include "llvm/Support/raw_ostream.h"
  #include "llvm/Support/Program.h"
  
  #include <cstdio>
  #include <vector>
  #include <sstream>
  
  #ifdef __CYGWIN__
  #include <cygwin/version.h>
  #include <sys/cygwin.h>
  #define LLVM_ON_WIN32 1
  #endif
  
  #ifdef LLVM_ON_WIN32
  #include <windows.h>
  #else
  #include <dlfcn.h>
  #endif
  
  using namespace clang;
  
  std::string CIndexer::getClangResourcesPath() {
    // Did we already compute the path?
    if (!ResourcesPath.empty())
      return ResourcesPath.str();
    
    // Find the location where this library lives (libclang.dylib).
  #ifdef LLVM_ON_WIN32
    MEMORY_BASIC_INFORMATION mbi;
    char path[MAX_PATH];
    VirtualQuery((void *)(uintptr_t)clang_createTranslationUnit, &mbi,
                 sizeof(mbi));
    GetModuleFileNameA((HINSTANCE)mbi.AllocationBase, path, MAX_PATH);
  
  #ifdef __CYGWIN__
    char w32path[MAX_PATH];
    strcpy(w32path, path);
  #if CYGWIN_VERSION_API_MAJOR > 0 || CYGWIN_VERSION_API_MINOR >= 181
    cygwin_conv_path(CCP_WIN_A_TO_POSIX, w32path, path, MAX_PATH);
  #else
    cygwin_conv_to_full_posix_path(w32path, path);
  #endif
  #endif
  
    llvm::sys::Path LibClangPath(path);
    LibClangPath.eraseComponent();
  #else
    // This silly cast below avoids a C++ warning.
    Dl_info info;
    if (dladdr((void *)(uintptr_t)clang_createTranslationUnit, &info) == 0)
      llvm_unreachable("Call to dladdr() failed");
    
    llvm::sys::Path LibClangPath(info.dli_fname);
    
    // We now have the CIndex directory, locate clang relative to it.
    LibClangPath.eraseComponent();
  #endif
    
    LibClangPath.appendComponent("clang");
    LibClangPath.appendComponent(CLANG_VERSION_STRING);
  
    // Cache our result.
    ResourcesPath = LibClangPath;
    return LibClangPath.str();
  }
  
  static llvm::sys::Path GetTemporaryPath() {
    // FIXME: This is lame; sys::Path should provide this function (in particular,
    // it should know how to find the temporary files dir).
    std::string Error;
    const char *TmpDir = ::getenv("TMPDIR");
    if (!TmpDir)
      TmpDir = ::getenv("TEMP");
    if (!TmpDir)
      TmpDir = ::getenv("TMP");
    if (!TmpDir)
      TmpDir = "/tmp";
    llvm::sys::Path P(TmpDir);
    P.appendComponent("remap");
    if (P.makeUnique(false, &Error))
      return llvm::sys::Path("");
  
    // FIXME: Grumble, makeUnique sometimes leaves the file around!?  PR3837.
    P.eraseFromDisk(false, 0);
  
    return P;
  }
  
  bool clang::RemapFiles(unsigned num_unsaved_files,
                         struct CXUnsavedFile *unsaved_files,
                         std::vector<std::string> &RemapArgs,
                         std::vector<llvm::sys::Path> &TemporaryFiles) {
    for (unsigned i = 0; i != num_unsaved_files; ++i) {
      // Write the contents of this unsaved file into the temporary file.
      llvm::sys::Path SavedFile(GetTemporaryPath());
      if (SavedFile.empty())
        return true;
  
      std::string ErrorInfo;
      llvm::raw_fd_ostream OS(SavedFile.c_str(), ErrorInfo,
                              llvm::raw_fd_ostream::F_Binary);
      if (!ErrorInfo.empty())
        return true;
      
      OS.write(unsaved_files[i].Contents, unsaved_files[i].Length);
      OS.close();
      if (OS.has_error()) {
        SavedFile.eraseFromDisk();
        OS.clear_error();
        return true;
      }
      
      // Remap the file.
      std::string RemapArg = unsaved_files[i].Filename;
      RemapArg += ';';
      RemapArg += SavedFile.str();
      RemapArgs.push_back("-Xclang");
      RemapArgs.push_back("-remap-file");
      RemapArgs.push_back("-Xclang");
      RemapArgs.push_back(RemapArg);
      TemporaryFiles.push_back(SavedFile);
    }
    
    return false;
  }
  
  