1 /** 2 * Copyright: Copyright (c) 2011 Jacob Carlborg. All rights reserved. 3 * Authors: Jacob Carlborg 4 * Version: Initial created: Oct 1, 2011 5 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 6 */ 7 module clang.Util; 8 9 import std.conv; 10 import std.stdio; 11 import std.format; 12 13 import clang.c.Index; 14 15 immutable(char*)* strToCArray (const string[] arr) 16 { 17 import std..string : toStringz; 18 19 if (!arr) 20 return null; 21 22 immutable(char*)[] cArr; 23 cArr.reserve(arr.length); 24 25 foreach (str ; arr) 26 cArr ~= str.toStringz; 27 28 return cArr.ptr; 29 } 30 31 string toD (CXString cxString) 32 { 33 auto cstr = clang_getCString(cxString); 34 auto str = to!(string)(cstr).idup; 35 clang_disposeString(cxString); 36 37 return str; 38 } 39 40 template isCX (T) 41 { 42 enum bool isCX = __traits(hasMember, T, "cx"); 43 } 44 45 template cxName (T) 46 { 47 enum cxName = "CX" ~ T.stringof; 48 } 49 50 U* toCArray (U, T) (T[] arr) 51 { 52 if (!arr) 53 return null; 54 55 static if (is(typeof(T.init.cx))) 56 return arr.map!(e => e.cx).toArray.ptr; 57 58 else 59 return arr.ptr; 60 } 61 62 mixin template CX () 63 { 64 mixin("private alias " ~ cxName!(typeof(this)) ~ " CType;"); 65 66 CType cx; 67 alias cx this; 68 69 void dispose () 70 { 71 enum methodCall = "clang_dispose" ~ typeof(this).stringof ~ "(cx);"; 72 73 static if (false && __traits(compiles, methodCall)) 74 mixin(methodCall); 75 } 76 77 @property bool isValid () 78 { 79 return cx !is CType.init; 80 } 81 } 82 83 string clangVersionString() 84 { 85 import std..string : strip; 86 87 return strip(clang_getClangVersion().toD); 88 } 89 90 struct Version 91 { 92 uint major = 0; 93 uint minor = 0; 94 uint release = 0; 95 } 96 97 Version clangVersion() 98 { 99 import std.algorithm : find; 100 import std.conv : parse; 101 import std.ascii : isDigit; 102 import std.range; 103 104 Version result; 105 auto verstr = clangVersionString().find!(x => x.isDigit); 106 107 result.major = verstr.parse!uint; 108 verstr.popFront(); 109 result.minor = verstr.parse!uint; 110 verstr.popFront(); 111 112 if (!verstr.empty && verstr.back.isDigit) 113 result.release = verstr.parse!uint; 114 115 return result; 116 } 117 118 alias Set(T) = void[0][T]; 119 120 void add(T)(ref void[0][T] self, T value) { 121 self[value] = (void[0]).init; 122 } 123 124 void add(T)(ref void[0][T] self, void[0][T] set) { 125 foreach (key; set.byKey) { 126 self.add(key); 127 } 128 } 129 130 Set!T clone(T)(ref void[0][T] self) { 131 Set!T result; 132 result.add(self); 133 return result; 134 } 135 136 bool contains(T)(inout(void[0][T]) set, T value) { 137 return (value in set) !is null; 138 } 139 140 auto setFromList(T)(T[] list) 141 { 142 import std.traits; 143 144 Set!(Unqual!T) result; 145 146 foreach (item; list) 147 result.add(item); 148 149 return result; 150 } 151 152 version (Posix) 153 { 154 private extern (C) int mkstemps(char*, int); 155 private extern (C) char* mkdtemp(char*); 156 private extern (C) int close(int); 157 } 158 else 159 { 160 struct GUID { 161 uint Data1; 162 ushort Data2; 163 ushort Data3; 164 ubyte[8] Data4; 165 } 166 167 private extern (Windows) uint CoCreateGuid(GUID* pguid); 168 169 private string createGUID() 170 { 171 char toHex(uint x) 172 { 173 if (x < 10) 174 return cast(char) ('0' + x); 175 else 176 return cast(char) ('A' + x - 10); 177 } 178 179 GUID guid; 180 CoCreateGuid(&guid); 181 182 ubyte* data = cast(ubyte*)&guid; 183 char[32] result; 184 185 foreach (i; 0 .. 16) 186 { 187 result[i * 2 + 0] = toHex(data[i] & 0x0fu); 188 result[i * 2 + 1] = toHex(data[i] >> 16); 189 } 190 191 return result.idup; 192 } 193 } 194 195 class NamedTempFileException : object.Exception 196 { 197 immutable string path; 198 199 this (string path, string file = __FILE__, size_t line = __LINE__) 200 { 201 this.path = path; 202 super(format("Cannot create temporary file \"%s\".", path), file, line); 203 } 204 } 205 206 class NamedTempDirException : object.Exception 207 { 208 immutable string path; 209 210 this (string path, string file = __FILE__, size_t line = __LINE__) 211 { 212 this.path = path; 213 super( 214 format("Cannot create temporary directory \"%s\".", path), 215 file, 216 line); 217 } 218 } 219 220 private void randstr (char[] slice) 221 { 222 import std.random; 223 224 foreach (i; 0 .. slice.length) 225 slice[i] = uniform!("[]")('A', 'Z'); 226 } 227 228 File namedTempFile(string prefix, string suffix) 229 { 230 import std.file; 231 import std.path; 232 import std.format; 233 234 version (Posix) 235 { 236 string name = format("%sXXXXXXXXXXXXXXXX%s\0", prefix, suffix); 237 char[] path = buildPath(tempDir(), name).dup; 238 const size_t termAnd6XSize = 7; 239 240 immutable size_t begin = path.length - name.length + prefix.length; 241 immutable size_t end = path.length - suffix.length - termAnd6XSize; 242 243 randstr(path[begin .. end]); 244 245 int fd = mkstemps(path.ptr, cast(int) suffix.length); 246 scope (exit) close(fd); 247 248 path = path[0 .. $ - 1]; 249 250 if (fd == -1) 251 throw new NamedTempFileException(path.idup); 252 253 return File(path, "wb+"); 254 } 255 else 256 { 257 string name = format("%s%s%s", prefix, createGUID(), suffix); 258 string path = buildPath(tempDir(), name); 259 return File(path, "wb+"); 260 } 261 } 262 263 string namedTempDir(string prefix) 264 { 265 import std.file; 266 import std.path; 267 import std.format; 268 269 version (Posix) 270 { 271 string name = format("%sXXXXXXXXXXXXXXXX\0", prefix); 272 char[] path = buildPath(tempDir(), name).dup; 273 const size_t termAnd6XSize = 7; 274 275 immutable size_t begin = path.length - name.length + prefix.length; 276 277 randstr(path[begin .. $ - termAnd6XSize]); 278 279 char* result = mkdtemp(path.ptr); 280 281 path = path[0..$-1]; 282 283 if (result == null) 284 throw new NamedTempDirException(path.idup); 285 286 return path.idup; 287 } 288 else 289 { 290 string name = prefix ~ createGUID(); 291 string path = buildPath(tempDir(), name); 292 293 try 294 mkdirRecurse(path); 295 catch (FileException) 296 throw new NamedTempDirException(path); 297 298 return path; 299 } 300 } 301 302 string asAbsNormPath(string path) 303 { 304 import std.path; 305 import std.conv : to; 306 307 return to!string(path.asAbsolutePath.asNormalizedPath); 308 }