1 //===- BuildSystem.cpp - Utilities for use by build systems ---------------===//
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 implements various utilities for use by build systems.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang-c/BuildSystem.h"
15 #include "CXString.h"
16 #include "llvm/ADT/ArrayRef.h"
17 #include "llvm/ADT/SmallString.h"
18 #include "llvm/Support/Path.h"
19 #include "llvm/Support/TimeValue.h"
20 #include "llvm/Support/raw_ostream.h"
21 
22 using namespace clang;
23 using namespace llvm::sys;
24 
25 unsigned long long clang_getBuildSessionTimestamp(void) {
26   return llvm::sys::TimeValue::now().toEpochTime();
27 }
28 
29 struct CXVirtualFileOverlayImpl {
30   std::vector<std::pair<std::string, std::string> > Mappings;
31 };
32 
33 CXVirtualFileOverlay clang_VirtualFileOverlay_create(unsigned) {
34   return new CXVirtualFileOverlayImpl();
35 }
36 
37 enum CXErrorCode
38 clang_VirtualFileOverlay_addFileMapping(CXVirtualFileOverlay VFO,
39                                         const char *virtualPath,
40                                         const char *realPath) {
41   if (!VFO || !virtualPath || !realPath)
42     return CXError_InvalidArguments;
43   if (!path::is_absolute(virtualPath))
44     return CXError_InvalidArguments;
45   if (!path::is_absolute(realPath))
46     return CXError_InvalidArguments;
47 
48   for (path::const_iterator
49          PI = path::begin(virtualPath),
50          PE = path::end(virtualPath); PI != PE; ++PI) {
51     StringRef Comp = *PI;
52     if (Comp == "." || Comp == "..")
53       return CXError_InvalidArguments;
54   }
55 
56   VFO->Mappings.push_back(std::make_pair(virtualPath, realPath));
57   return CXError_Success;
58 }
59 
60 namespace {
61 struct EntryTy {
62   std::string VPath;
63   std::string RPath;
64 
65   friend bool operator < (const EntryTy &LHS, const EntryTy &RHS) {
66     return LHS.VPath < RHS.VPath;
67   }
68 };
69 
70 class JSONVFSPrinter {
71   llvm::raw_ostream &OS;
72 
73 public:
74   JSONVFSPrinter(llvm::raw_ostream &OS) : OS(OS) {}
75 
76   /// Entries must be sorted.
77   void print(ArrayRef<EntryTy> Entries) {
78     OS << "{\n"
79           "  'version': 0,\n"
80           "  'roots': [\n";
81     printDirNodes(Entries, "", 4);
82     OS << "  ]\n"
83           "}\n";
84   }
85 
86 private:
87   ArrayRef<EntryTy> printDirNodes(ArrayRef<EntryTy> Entries,
88                                   StringRef ParentPath,
89                                   unsigned Indent) {
90     while (!Entries.empty()) {
91       const EntryTy &Entry = Entries.front();
92       OS.indent(Indent) << "{\n";
93       Indent += 2;
94       OS.indent(Indent) << "'type': 'directory',\n";
95       OS.indent(Indent) << "'name': \"";
96       StringRef DirName = containedPart(ParentPath,
97                                         path::parent_path(Entry.VPath));
98       OS.write_escaped(DirName) << "\",\n";
99       OS.indent(Indent) << "'contents': [\n";
100       Entries = printContents(Entries, Indent + 2);
101       OS.indent(Indent) << "]\n";
102       Indent -= 2;
103       OS.indent(Indent) << '}';
104       if (Entries.empty()) {
105         OS << '\n';
106         break;
107       }
108       StringRef NextVPath = Entries.front().VPath;
109       if (!containedIn(ParentPath, NextVPath)) {
110         OS << '\n';
111         break;
112       }
113       OS << ",\n";
114     }
115     return Entries;
116   }
117 
118   ArrayRef<EntryTy> printContents(ArrayRef<EntryTy> Entries,
119                                   unsigned Indent) {
120     while (!Entries.empty()) {
121       const EntryTy &Entry = Entries.front();
122       Entries = Entries.slice(1);
123       StringRef ParentPath = path::parent_path(Entry.VPath);
124       StringRef VName = path::filename(Entry.VPath);
125       OS.indent(Indent) << "{\n";
126       Indent += 2;
127       OS.indent(Indent) << "'type': 'file',\n";
128       OS.indent(Indent) << "'name': \"";
129       OS.write_escaped(VName) << "\",\n";
130       OS.indent(Indent) << "'external-contents': \"";
131       OS.write_escaped(Entry.RPath) << "\"\n";
132       Indent -= 2;
133       OS.indent(Indent) << '}';
134       if (Entries.empty()) {
135         OS << '\n';
136         break;
137       }
138       StringRef NextVPath = Entries.front().VPath;
139       if (!containedIn(ParentPath, NextVPath)) {
140         OS << '\n';
141         break;
142       }
143       OS << ",\n";
144       if (path::parent_path(NextVPath) != ParentPath) {
145         Entries = printDirNodes(Entries, ParentPath, Indent);
146       }
147     }
148     return Entries;
149   }
150 
151   bool containedIn(StringRef Parent, StringRef Path) {
152     return Path.startswith(Parent);
153   }
154 
155   StringRef containedPart(StringRef Parent, StringRef Path) {
156     assert(containedIn(Parent, Path));
157     if (Parent.empty())
158       return Path;
159     return Path.slice(Parent.size()+1, StringRef::npos);
160   }
161 };
162 }
163 
164 enum CXErrorCode
165 clang_VirtualFileOverlay_writeToBuffer(CXVirtualFileOverlay VFO, unsigned,
166                                        char **out_buffer_ptr,
167                                        unsigned *out_buffer_size) {
168   if (!VFO || !out_buffer_ptr || !out_buffer_size)
169     return CXError_InvalidArguments;
170 
171   llvm::SmallVector<EntryTy, 16> Entries;
172   for (unsigned i = 0, e = VFO->Mappings.size(); i != e; ++i) {
173     EntryTy Entry;
174     Entry.VPath = VFO->Mappings[i].first;
175     Entry.RPath = VFO->Mappings[i].second;
176     Entries.push_back(Entry);
177   }
178 
179   // FIXME: We should add options to determine if the paths are case sensitive
180   // or not. The following assumes that if paths are case-insensitive the caller
181   // did not mix cases in the virtual paths it provided.
182 
183   std::sort(Entries.begin(), Entries.end());
184 
185   llvm::SmallString<256> Buf;
186   llvm::raw_svector_ostream OS(Buf);
187   JSONVFSPrinter Printer(OS);
188   Printer.print(Entries);
189 
190   StringRef Data = OS.str();
191   *out_buffer_ptr = (char*)malloc(Data.size());
192   *out_buffer_size = Data.size();
193   memcpy(*out_buffer_ptr, Data.data(), Data.size());
194   return CXError_Success;
195 }
196 
197 void clang_VirtualFileOverlay_dispose(CXVirtualFileOverlay VFO) {
198   delete VFO;
199 }
200 
201 
202 struct CXModuleMapDescriptorImpl {
203   std::string ModuleName;
204   std::string UmbrellaHeader;
205 };
206 
207 CXModuleMapDescriptor clang_ModuleMapDescriptor_create(unsigned) {
208   return new CXModuleMapDescriptorImpl();
209 }
210 
211 enum CXErrorCode
212 clang_ModuleMapDescriptor_setFrameworkModuleName(CXModuleMapDescriptor MMD,
213                                                  const char *name) {
214   if (!MMD || !name)
215     return CXError_InvalidArguments;
216 
217   MMD->ModuleName = name;
218   return CXError_Success;
219 }
220 
221 enum CXErrorCode
222 clang_ModuleMapDescriptor_setUmbrellaHeader(CXModuleMapDescriptor MMD,
223                                             const char *name) {
224   if (!MMD || !name)
225     return CXError_InvalidArguments;
226 
227   MMD->UmbrellaHeader = name;
228   return CXError_Success;
229 }
230 
231 enum CXErrorCode
232 clang_ModuleMapDescriptor_writeToBuffer(CXModuleMapDescriptor MMD, unsigned,
233                                        char **out_buffer_ptr,
234                                        unsigned *out_buffer_size) {
235   if (!MMD || !out_buffer_ptr || !out_buffer_size)
236     return CXError_InvalidArguments;
237 
238   llvm::SmallString<256> Buf;
239   llvm::raw_svector_ostream OS(Buf);
240   OS << "framework module " << MMD->ModuleName << " {\n";
241   OS << "  umbrella header \"";
242   OS.write_escaped(MMD->UmbrellaHeader) << "\"\n";
243   OS << '\n';
244   OS << "  export *\n";
245   OS << "  module * { export * }\n";
246   OS << "}\n";
247 
248   StringRef Data = OS.str();
249   *out_buffer_ptr = (char*)malloc(Data.size());
250   *out_buffer_size = Data.size();
251   memcpy(*out_buffer_ptr, Data.data(), Data.size());
252   return CXError_Success;
253 }
254 
255 void clang_ModuleMapDescriptor_dispose(CXModuleMapDescriptor MMD) {
256   delete MMD;
257 }
258