alternative to assert
[gtkD.git] / wrap / utils / HTODConvert.d
bloba4669e4a3a0a920c06ab0c51ed6dc259a7c58d1e
1 /*
2 * This file is part of duit.
3 *
4 * duit is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; either version 2.1 of the License, or
7 * (at your option) any later version.
8 *
9 * duit is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with duit; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 module utils.HTODConvert;
21 private import utils.DefReader;
22 private import utils.GtkWrapper;
24 private import std.stdio;
25 private import std.file;
26 private import std.string;
27 private import std.process;
29 //debug = flow;
30 //debug = processLine;
31 //debug = getDType;
32 //debug = functions;
34 public class Ranges
37 private struct Range
39 int vStart;
40 int vEnd;
41 bool exclude = true;
43 public bool contains(int pos)
45 return (pos>= vStart) && (pos<=vEnd);
48 public bool includes(int pos)
50 return contains(pos)
51 ? !exclude
52 : exclude
56 public bool matches(int start, int end)
58 return vStart == start
59 && vEnd == end;
63 private Range*[] ranges;
65 public void addRange(int start, int end, bool exclude)
67 Range* range = new Range;
68 range.vStart = start;
69 range.vEnd = end;
70 range.exclude = exclude;
71 ranges ~= range;
74 /**
75 * Finds the last range that contains the position and returns it's include value
76 * Params:
77 * pos =
79 public void include(int pos)
81 bool incl = true;
82 Range* range;
83 int i=ranges.length;
84 while ( i > 0 )
86 range = ranges[--i];
87 if ( range.contains(pos) )
89 i=0;
90 incl = !range.exclude;
93 return incl;
98 /**
99 * This is used to pos-process dm htod .d file for duit
100 * to create the htod .d file:
101 * - copy the original .h file to a working directory
102 * - remove all unecessary definitions
103 * - run `wine ~/dm/bin/htod.exe <file.h>`
104 * - run this on the generated .d file
106 public class HTODConvert
109 char[] dText;
111 DefReader defReader;
113 /** the library id on the system (for instance GL for libGL.so) */
114 char[] lib;
115 /** the .h (or .h pos-processed) to convert to .d */
116 char[] preFile;
117 /** the package */
118 char[] pack;
119 /** convert to dynamic loading */
120 bool dynLoad;
121 /** mark when the header was already added to the text */
122 bool dynLoadAlreadyOpen;
123 /** mar when the module and license where already added to the text */
124 bool headerAlreadyAdded;
125 char[][] functions;
126 char[][] comment;
129 this(char[] htodFilename)
131 defReader = new DefReader(htodFilename);
132 clearValues();
133 process();
136 void process()
138 debug(flow)(writefln("HTODConvert.process 1"));
139 while ( defReader.next().length > 0 )
141 switch ( defReader.getKey() )
143 case "prefile":
144 debug(flow)(writefln("HTODConvert.process case prefile"));
145 preFile = defReader.getValue();
146 break;
148 case "pack":
149 debug(flow)(writefln("HTODConvert.process case pack"));
150 pack = defReader.getValue();
151 break;
153 case "lib":
154 debug(flow)(writefln("HTODConvert.process case libe"));
155 lib = defReader.getValue();
156 break;
158 case "file":
159 debug(flow)(writefln("HTODConvert.process case file 1"));
160 if ( preFile.length > 0 )
162 debug(flow)(writefln("HTODConvert.process case file 2"));
163 processPreFile(preFile, defReader.getValue());
164 debug(flow)(writefln("HTODConvert.process case file 3"));
166 debug(flow)(writefln("HTODConvert.process case file 4"));
167 preFile.length = 0;
168 debug(flow)(writefln("HTODConvert.process case file 5"));
169 processFile(defReader.getValue());
170 debug(flow)(writefln("HTODConvert.process case file 6 "));
171 break;
173 case "dynload":
174 debug(flow)(writefln("HTODConvert.process case dynload"));
175 dynLoadAlreadyOpen = false;
176 headerAlreadyAdded = false;
177 dynLoad = true;
178 break;
180 case "outfile":
181 debug(flow)(writefln("HTODConvert.process case outfile"));
182 writeFile(defReader.getValue());
183 clearValues();
184 break;
186 default:
187 debug(flow)(writefln("HTODConvert.process case default"));
188 writefln("Unknown key/value = %s/%s", defReader.getKey(), defReader.getValue());
189 break;
195 void processPreFile(char[] preFileName, char[] fileName)
197 debug(flow)(writefln("HTODConvert.processPreFile files: %s > %s", preFileName, fileName));
198 char[][] args;
199 args ~= "/home/ruimt/dm/bin/htod.exe";
200 args ~= "/home/ruimt/dm/bin/htod.exe";
201 args ~= preFileName;
202 args ~= fileName;
205 std.process.execvp("wine", args);
207 catch ( Object e)
209 // ignore - it always fail - most of the time produces the file
213 void processFile(char[] fileName)
215 debug(flow)(writefln("HTODConvert.processFile"));
216 char[] hText = cast(char[])std.file.read(fileName);
217 char[][] hLines = std.string.splitlines(hText);
218 char[] line;
220 int i = 0;
221 while ( i < hLines.length )
223 line = hLines[i++];
224 if ( std.string.find(line,'(')>=0 )
226 int openBrace = 1;
227 if ( std.string.find(line,')')>=0 ) --openBrace;
228 while ( openBrace > 0
229 && i<hLines.length
232 char[] l = hLines[i++];
233 if ( std.string.find(l,')') >=0) --openBrace;
234 line ~= " " ~ std.string.strip(l);
237 addLine(dText, line);
240 if ( dynLoad )
242 closeDynLoad(dText);
246 void addLine(inout char[] dText, char[] line)
248 if ( !startsWith(line, "//C")
249 && line !="alias extern GLAPI;"
250 && line !="alias GLAPIENTRY APIENTRY;"
253 if ( line == "alias sbyte GLbyte;" )
255 line = "alias byte GLbyte;";
257 if ( line == "module wrap/cHeaders/GL/gl;" )
259 line = "module lib.gl;";
262 if ( line == "module wrap/cHeaders/GL/glu;" )
264 line = "module lib.glu;";
267 if ( line == "import std.c.gl;" )
269 line = "import lib.gl;";
272 if ( startsWith(line, "/* Converted to D from" ) )
274 line = GtkWrapper.license;
277 if ( dynLoad )
279 addLineDynLoad(dText, line);
281 else
283 dText ~= line~"\n";
290 * If the line is a function definition stores the line to include on the extern(C)
291 * and the symbols.
292 * for now a function is a line that ends with ");"
293 * Params:
294 * dText =
295 * line =
297 void addLineDynLoad(inout char[] dText, char[] line)
299 //debug(flow)(writefln("HTODConvert.addLineDynLoad"));
301 if ( headerAlreadyAdded
302 && !dynLoadAlreadyOpen
305 openDynLoad(dText);
308 if ( endsWith(line, ");") )
310 int i=0;
311 while ( i<comment.length )
313 functions ~= comment[i++];
315 comment.length = 0;
316 functions ~= line;
317 debug(functions)writefln("HTODConvert.addLineDynLoad function[%s] = %s",
318 functions.length, line);
320 else if ( startsWith(line, "/*")
321 || startsWith(line, " *")
322 || startsWith(line, " */")
323 || line.length == 0
326 comment ~= line;
328 else
330 if ( startsWith(line, "module") )
332 headerAlreadyAdded = true;
334 int i=0;
335 while ( i<comment.length )
337 dText ~= comment[i++]~"\n";
339 comment.length = 0;
340 dText ~= line~"\n";
344 void openDynLoad(inout char[] dText)
346 debug(flow)(writefln("HTODConvert.openDynLoad"));
347 dynLoadAlreadyOpen = true;
348 dText ~=
349 "\n"
350 "\n"
351 "private import std.stdio;\n"
352 "private import "~pack~"."~pack~"types;\n"
353 "private import lib.Loader;\n"
354 "private import lib.paths;\n"
355 "\n"
357 if ( lib == "GL"
358 || lib == "GLU" )
360 return;
362 dText ~=
363 "private Linker "~lib~"_Linker;\n"
364 "\n"
365 "static this()\n"
366 "{\n"
367 " "~lib~"_Linker = new Linker(libPath ~ importLibs[LIBRARY."~std.string.toupper(lib)~"] );\n"
368 " "~lib~"_Linker.link("~lib~"Links);\n"
369 " debug writefln(\"* Finished static this(): "~lib~"\");\n"
370 "}\n"
371 "\n"
372 "static ~this()\n"
373 "{\n"
374 " delete "~lib~"_Linker;\n"
375 " debug writefln(\"* Finished static ~this(): "~lib~"\");\n"
376 "}\n\n"
382 void closeDynLoad(inout char[] dText)
385 debug(flow)(writefln("HTODConvert.closeDynLoad"));
386 dText ~= "\n\nextern(C)\n{\n";
387 foreach ( char[] line ; functions )
389 dText ~= "\t" ~ line ~"\n";
391 dText ~= "} // extern(C)\n";
393 dText ~= "\n\nSymbol[] "~lib~"Links = \n";
394 dText ~= "[\n";
396 foreach ( char[] line ; functions )
398 if ( startsWith(line, "/*")
399 || startsWith(line, " *")
400 || startsWith(line, " */")
401 || line.length == 0
404 dText ~= "\t"~line~"\n";
406 else
408 int end = std.string.find(line,'(');
410 if ( end > 0 )
412 int start = end;
413 while ( start > 0 && line[start] > ' ' )
415 --start;
417 char[] functionName = line[start+1..end];
418 if ( functionName.length>1)
420 dText ~= "\t{ \""
421 ~functionName
422 ~"\", cast(void**)& "
423 ~functionName
424 ~"},\n"
432 dText ~= "];\n\n";
438 void clearValues()
440 debug(flow)(writefln("HTODConvert.clearValues"));
441 dText.length = 0;
442 dynLoad = false;
443 lib.length = 0;
444 preFile.length = 0;
445 pack.length = 0;
446 bool dynLoadAlreadyOpen = false;
447 bool headerAlreadyAdded = false;
448 functions.length = 0;
449 comment.length = 0;
453 void writeFile(char[] fileName)
455 debug(flow)(writefln("HTODConvert.writeFile"));
456 debug(flow)(writefln("HTODConvert.writeFile fileName = %s", fileName));
457 std.file.write(fileName, dText);
460 public static bit startsWith(char[] str, char[] prefix)
462 return str.length >= prefix.length
463 && str[0..prefix.length] == prefix;
466 public static bit startsWith(char[] str, char prefix)
468 return str.length > 0
469 && str[0] == prefix;
472 public static bit endsWith(char[] str, char[] prefix)
474 return str.length >= prefix.length
475 && str[str.length-prefix.length..str.length] == prefix;
478 public static bit endsWith(char[] str, char suffix)
480 return str.length >= 1
481 && str[str.length-1] == suffix;