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) int close(int); 156 } 157 else 158 { 159 import core.sys.windows.objbase : CoCreateGuid; 160 import core.sys.windows.basetyps : GUID; 161 162 string createGUID() 163 { 164 char toHex(uint x) 165 { 166 if (x < 10) 167 return cast(char) ('0' + x); 168 else 169 return cast(char) ('A' + x - 10); 170 } 171 172 GUID guid; 173 CoCreateGuid(&guid); 174 175 ubyte* data = cast(ubyte*)&guid; 176 char[32] result; 177 178 foreach (i; 0 .. 16) 179 { 180 result[i * 2 + 0] = toHex(data[i] & 0x0fu); 181 result[i * 2 + 1] = toHex(data[i] >> 16); 182 } 183 184 return result.idup; 185 } 186 } 187 188 class NamedTempFileException : object.Exception 189 { 190 immutable string path; 191 192 this (string path, string file = __FILE__, size_t line = __LINE__) 193 { 194 this.path = path; 195 super(format("Cannot create temporary file \"%s\".", path), file, line); 196 } 197 } 198 199 File namedTempFile(string prefix, string suffix) 200 { 201 import std.file; 202 import std.path; 203 import std.format; 204 205 version (Posix) 206 { 207 static void randstr (char[] slice) 208 { 209 import std.random; 210 211 foreach (i; 0 .. slice.length) 212 slice[i] = uniform!("[]")('A', 'Z'); 213 } 214 215 string name = format("%sXXXXXXXXXXXXXXXX%s\0", prefix, suffix); 216 char[] path = buildPath(tempDir(), name).dup; 217 const size_t termAnd6XSize = 7; 218 219 immutable size_t begin = path.length - name.length + prefix.length; 220 immutable size_t end = path.length - suffix.length - termAnd6XSize; 221 222 randstr(path[begin .. end]); 223 224 int fd = mkstemps(path.ptr, cast(int) suffix.length); 225 scope (exit) close(fd); 226 227 path = path[0 .. $ - 1]; 228 229 if (fd == -1) 230 throw new NamedTempFileException(path.idup); 231 232 return File(path, "wb+"); 233 } 234 else 235 { 236 string name = format("%s%s%s", prefix, createGUID(), suffix); 237 string path = buildPath(tempDir(), name); 238 return File(path, "wb+"); 239 } 240 } 241 242 string asAbsNormPath(string path) 243 { 244 import std.path; 245 import std.conv : to; 246 247 return to!string(path.asAbsolutePath.asNormalizedPath); 248 }