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 clang.c.Index;
10 
11 import std.conv;
12 import std.stdio;
13 
14 immutable(char*)* strToCArray(string[] arr) @safe {
15     import std..string : toStringz;
16 
17     if (!arr)
18         return null;
19 
20     immutable(char*)[] cArr;
21     cArr.reserve(arr.length);
22 
23     foreach (str; arr)
24         cArr ~= str.toStringz;
25 
26     return &cArr[0];
27 }
28 
29 /**
30  * Trusted: on the assumption that clang_getCString is implemented by the LLVM
31  * community. Any bugs in them should by now be found.
32  */
33 string toD(CXString cxString) @trusted {
34     auto cstr = clang_getCString(cxString);
35     auto str = to!(string)(cstr).idup;
36     clang_disposeString(cxString);
37 
38     return str;
39 }
40 
41 template isCX(T) {
42     enum bool isCX = __traits(hasMember, T, "cx");
43 }
44 
45 template cxName(T) {
46     enum cxName = "CX" ~ T.stringof;
47 }
48 
49 U* toCArray(U, T)(T[] arr) @safe {
50     if (!arr)
51         return null;
52 
53     static if (is(typeof(T.init.cx)))
54         return arr.map!(e => e.cx).toArray.ptr;
55 
56     else
57         return &arr[0];
58 }
59 
60 mixin template CX(string name = "") {
61     static if (name.length == 0) {
62         mixin("private alias CType = " ~ cxName!(typeof(this)) ~ ";");
63     } else {
64         mixin("private alias  CType = CX" ~ name ~ ";");
65     }
66 
67     CType cx;
68     alias cx this;
69 
70     /**
71      * Trusted: on the assumption that dispose as implemented by the LLVM
72      * community is good _enough_. Any bugs should by now have been found.
73      */
74     void dispose() @trusted {
75         enum methodCall = "clang_dispose" ~ typeof(this).stringof ~ "(cx);";
76 
77         static if (false && __traits(compiles, methodCall))
78             mixin(methodCall);
79     }
80 
81     @property bool isValid() @safe pure nothrow const @nogc {
82         return cx !is CType.init;
83     }
84 }
85 
86 extern (C) int mkstemps(char*, int);
87 extern (C) int close(int);
88 
89 class NamedTempFileException : object.Exception {
90     this(string message, string file = __FILE__, size_t line = __LINE__) {
91         super(message, file, line);
92     }
93 }
94 
95 File namedTempFile(string prefix, string suffix) {
96     import std.random;
97     import std.file;
98     import std.path;
99     import std.format;
100 
101     void randstr(char[] slice) {
102         for (uint i = 0; i < slice.length; ++i)
103             slice[i] = uniform!("[]")('A', 'Z');
104     }
105 
106     string name = format("%sXXXXXXXXXXXXXXXX%s\0", prefix, suffix);
107     char[] path = buildPath(tempDir(), name).dup;
108     const size_t termAnd6XSize = 7;
109     randstr(path[$ - name.length + prefix.length .. $ - suffix.length - termAnd6XSize]);
110 
111     int fd = mkstemps(path.ptr, cast(int) suffix.length);
112     scope (exit)
113         close(fd);
114 
115     if (fd == -1)
116         throw new NamedTempFileException("Cannot create \"%s\" temporary file.".format(path));
117 
118     return File(path[0 .. $ - 1], "wb+");
119 }