1 /*
2 * This file is part of gtkD.
3 *
4 * gtkD is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License
6 * as published by the Free Software Foundation; either version 3
7 * of the License, or (at your option) any later version, with
8 * some exceptions, please read the COPYING file.
9 *
10 * gtkD is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with gtkD; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
18 */
19
20 module utils.GtkWrapper;
21
22 //debug=copyFile;
23 //debug=wrapFile;
24 //debug=wrapParameter;
25 //debug=createPackage;
26 //debug=aliases;
27 //debug=lookup;
28 //debug=file;
29 //debug=writeFile;
30
31 struct WError
32 {
33 private import std.stdio;
34
35 int lineNumber;
36 int code;
37 string filename;
38 string message;
39
40
41 static WError* create(string filename, int lineNumber, int code, string message)
42 {
43 WError* error = new WError;
44 error.lineNumber = lineNumber;
45 error.code = code;
46 error.filename = filename;
47 error.message = message;
48 return error;
49 }
50
51 void print ()
52 {
53 writefln("%s(%s), code %s: %s.", filename, lineNumber, code, message);
54 }
55 }
56
57
58 private import utils.WrapperIF;
59 private import utils.HTODConvert;
60
61
62 /*
63 Paths:
64 outputRoot: Where all the wrapper files go.
65 srcDir: Wrapper files subdir (src vs srcgl)
66 inputRoot: Where the html files are
67 apiRoot: Where the API files are
68
69 buildDir: Where the build files go.
70 bindingsDir: Where the C Bindings files go.
71
72 */
73
74 private import std.path;
75
76 string joinRootDirFile(string root, string dir, string file)
77 {
78 return buildPath(std.path.buildPath(root,dir),file);
79 }
80
81 //Moved here because of dsss:
82 private import utils.DefReader;
83 private import utils.GtkDClass;
84 private import utils.convparms;
85 private import utils.IndentedStringBuilder;
86
87 /**
88 * converts and wrap the GTK libs
89 */
90 public class GtkWrapper : WrapperIF
91 {
92 private import std.file;
93 private import std.path;
94 private import std.stdio;
95 private import std.string;
96 private import std.array;
97
98 private string buildText; /// to build the build.d
99 private string buildTextLibs; /// to build the build.d libs
100
101 string srcOut = "src"; /// the src output directory
102 string srcDir;
103 string apiRoot;
104 string inputRoot;
105 string outputRoot;
106 string buildDir = "build";
107 string buildPath;
108 string buildFile = "gtkD.d";
109 string bindingsDir;
110
111 public static string license;
112
113 private bool currIncludeComments;
114
115 enum {
116
117 ERR_NONE = 1000,
118 ERR_UNKNOWNE,
119 ERR_NO_LICENSE,
120 ERR_INVALID_ALIAS,
121 ERR_NO_IN_ROOT,
122 ERR_NO_OUT_ROOT,
123 ERR_COPY_FILE,
124 ERR_FILE_DEFINITION,
125 ERR_CREATE_PACKAGE,
126 }
127
128 string[string] aliases;
129
130 string[string] enumTypes;
131
132 DefReader defReader;
133
134
135 string[string] packages;
136
137 WError*[] errors;
138
139 private string[] externalDeclarations; /// the information to build the loader tables
140
141 private string[] collectedAliases; /// public, module level type aliases
142 private string[] collectedEnums; /// public, module level definitions of enums
143 private string[] stockEnums; /// special enums for StockID
144 private string[] stockChars; /// the string values for StockIDs
145 private string[] gTypes; /// special enums for G_TYPE_*
146 private string[] collectedStructs; /// public, module level definitions of structs
147 private string[] collectedTypes; /// public, module level definitions of other types
148 private string[] collectedFuncts; /// public, module level definitions of functions
149 private string[] collectedUnions; /// public, module level definitions of unions
150 private string[] collectedConstants;/// public, module level type contants
151
152 private string[] lookupTypedefs; /// lookup file definitions to be included on the typedefs.d
153 private string[] lookupAliases; /// lookup file aliases definitions
154 private string[] lookupEnums; /// lookup file enum definitions
155 private string[] lookupStructs; /// lookup file struct definitions
156 private string[] lookupTypes; /// lookup file type definitions
157 private string[] lookupFuncts; /// lookup file functs definitions
158 private string[] lookupUnions; /// lookup file unions definitions
159 private string[] lookupConstants; /// lookup file constants definitions
160
161 DefReader[] defReaders;
162
163 this(string apiRoot)
164 {
165 this.apiRoot = apiRoot;
166 //srcOut = "src";
167 //if (!std.file.exists(std.path.buildPath(outputRoot,srcOut)))
168 //{
169 // std.file.mkdir(std.path.buildPath(outputRoot,srcOut));
170 //}
171
172 }
173
174
175 private void startBuildText()
176 {
177 buildText =
178 "/*"
179 "\n * Automatically generated build imports from"
180 "\n * the initial version generouselly given by:"
181 "\n * John Reimer"
182 "\n */"
183 "\n"
184 "\nmodule build;"
185 "\n"
186 "\nversion( build )"
187 "\n{"
188 "\n pragma (nolink);"
189 "\n"
190 "\n version (Windows) pragma (target, \"GtkD.lib\" );"
191 "\n version (linux) pragma (target, \"libgtkd.a\" );"
192 "\n}"
193 "\n"
194 ;
195
196 buildTextLibs.length = 0;
197
198 }
199
200 public void writeBuildText()
201 {
202 string outfile;
203
204 buildPath = std.path.buildPath(std.path.buildPath(outputRoot,srcDir),buildDir);
205 if (!std.file.exists(buildPath))
206 {
207 std.file.mkdir(buildPath);
208
209 }
210 outfile = std.path.buildPath(buildPath,buildFile);
211 writefln("writeBuildText: %s",outfile);
212
213 std.file.write(outfile, buildText~"\n\n"~buildTextLibs);
214 }
215
216 int process(string apiLookupDefinition)
217 {
218
219 startBuildText();
220
221 int status = ERR_NONE;
222 defReader = new DefReader(std.path.buildPath(apiRoot,apiLookupDefinition));
223
224 if ( status==ERR_NONE && "license" == defReader.next() )
225 {
226 loadLicense();
227 }
228 else
229 {
230 status = ERR_NO_LICENSE;
231 errors ~= WError.create(defReader.fileName, defReader.getLineNumber(), status, "Missing license as the first definition");
232 }
233
234 if ( "includeComments" == defReader.next() )
235 {
236 currIncludeComments = defReader.getValueBit();
237 defReader.next();
238 }
239
240 debug(aliases) writefln("key before alias = ",defReader.getKey());
241 while ( "alias" == defReader.getKey() )
242 {
243 status = loadAA(aliases, defReader, errors);
244 defReader.next();
245 }
246
247 while ( "enumType" == defReader.getKey() )
248 {
249 status = loadAA(enumTypes, defReader, errors);
250 defReader.next();
251 }
252
253 debug(aliases) writefln("key after alias = ",defReader.getKey());
254
255 debug(aliases) foreach(string key ; aliases.keys.sort)
256 {
257 writefln("alias %s = %s",key, aliases[key]);
258 }
259 if ( status==ERR_NONE && "inputRoot" == defReader.getKey() )
260 {
261 inputRoot = defReader.getValue();
262 }
263 else
264 {
265 status = ERR_NO_IN_ROOT;
266 errors ~= WError.create(defReader.fileName, defReader.getLineNumber(), status, "Cannot determine input root");
267 }
268
269 if ( status==ERR_NONE && "outputRoot" == defReader.next() )
270 {
271 outputRoot = defReader.getValue();
272 }
273 else
274 {
275 status = ERR_NO_OUT_ROOT;
276 errors ~= WError.create(defReader.fileName, defReader.getLineNumber(), status, "Cannot determine output root");
277 }
278
279 string key = defReader.next();
280
281 while ( status==ERR_NONE && ( "srcdir" == key ))
282 {
283 srcDir = defReader.getValue();
284 string chkdir = std.path.buildPath(outputRoot,srcDir);
285 if (!std.file.exists(chkdir))
286 {
287 std.file.mkdir(chkdir);
288 }
289 key = defReader.next();
290 while ( status==ERR_NONE && ( "package" == key || "bind" == key ))
291 {
292
293 status = createPackage(outputRoot, defReader.getValue());
294 key = defReader.next();
295 }
296 }
297
298
299
300 if ( status==ERR_NONE )
301 {
302 string pack;
303 string outPack;
304 string prevPack;
305 while ( status==ERR_NONE && defReader !is null
306 //&& ("wrap" == defReader.getKey() || "lookup" == defReader.getKey())
307 )
308 {
309 debug(lookup)writefln("(%s) %s=%s", defReader.getFileName(), defReader.getKey(), defReader.getValue() );
310 switch ( defReader.getKey() )
311 {
312 case "alias": loadAA(aliases, defReader, errors); defReader.next(); break;
313 case "addTypedefs": lookupTypedefs ~= loadTextMultiLine("addTypedefs"); defReader.next();break;
314 case "addAliases": lookupAliases ~= loadTextMultiLine("addAliases"); defReader.next();break;
315 case "addEnums": lookupEnums ~= loadTextMultiLine("addEnums"); defReader.next();break;
316 case "addStructs": lookupStructs ~= loadTextMultiLine("addStructs"); defReader.next();break;
317 case "addTypes": lookupTypes ~= loadTextMultiLine("addTypes"); defReader.next();break;
318 case "addFuncts": lookupFuncts ~= loadTextMultiLine("addFuncts"); defReader.next();break;
319 case "addUnions": lookupUnions ~= loadTextMultiLine("addUnions"); defReader.next();break;
320 case "addConstants": lookupConstants ~= loadTextMultiLine("addConstants"); defReader.next();break;
321 case "enumType": loadAA(enumTypes, defReader, errors); defReader.next(); break;
322 case "srcout": srcOut =
323 defReader.getValue();defReader.next(); break;
324 case "srcdir": srcDir = defReader.getValue();
325 defReader.next();
326 case "bindDir": bindingsDir = defReader.getValue();
327 defReader.next();break;
328 case "wrap":
329 //package = key packagename
330 // = pack outpack
331 pack = defReader.getValue();
332
333 outPack = packages[pack];
334 debug(lookup)writefln("wrap %s", outPack);
335 if ( outPack !is null )
336 {
337 buildText ~= "\n";
338 if ( outPack != "lib" )
339 {
340 buildTextLibs ~= "private import "~bindingsDir~"."~outPack~";\n";
341 }
342 status = wrapFile(pack, outPack);
343 }
344 if ( prevPack.length>0 && outPack!=prevPack )
345 {
346 buildTypedefs(outPack);
347 buildLoaderTable(outPack, externalDeclarations);
348 externalDeclarations.length = 0;
349 }
350 prevPack = outPack;
351 break;
352
353 case "lookup":
354 defReaders ~= defReader;
355 defReader = new DefReader(std.path.buildPath(apiRoot,defReader.getValue()));
356 defReader.next();
357 debug(lookup)writefln("lookup on file %s (%s=%s)", defReader.getFileName(), defReader.getKey(), defReader.getValue() );
358 break;
359
360 case "htod":
361 // not as clean as lookup...
362 // WARNING!!! writefln's are needed to avoid hang.
363 writefln("start htod");
364 new
365 HTODConvert(defReader.getValue(),outputRoot,apiRoot);
366 writefln("end htod");
367 defReader.next();
368 break;
369
370 default:
371 if ( defReader.getKey().length == 0 )
372 {
373 if ( defReaders.length > 0 )
374 {
375 defReader = defReaders[defReaders.length-1];
376 defReaders.length = defReaders.length -1;
377 debug(lookup)writefln("lookup back to %s (%s=%s)", defReader.getFileName(), defReader.getKey(), defReader.getValue() );
378 defReader.next();
379 debug(lookup)writefln("lookup next == %s (%s=%s)", defReader.getFileName(), defReader.getKey(), defReader.getValue() );
380 }
381 else
382 {
383 defReader = null;
384 }
385 }
386 break;
387 }
388 debug(lookup)if(defReader!is null)writefln("loop (%s) %s=%s", defReader.getFileName(), defReader.getKey(), defReader.getValue() );
389 }
390 }
391 else
392 {
393 //writefln("status = %s",status);
394 }
395
396 return status;
397 }
398
399 /**
400 * Creates an entry on a string[string] associative array
401 * Params:
402 * aa =
403 * defReader =
404 * Returns:
405 */
406 private static int loadAA(ref string[string] aa, DefReader defReader, WError*[] errors = null)
407 {
408 int status = ERR_NONE;
409 string[] vals = std..string.split(defReader.getValue());
410 if ( vals.length == 1 )
411 {
412 vals ~= "";
413 }
414 if ( vals.length == 2 )
415 {
416 aa[vals[0]] = vals[1];
417 debug(aa) writefln("added alias %s = %s", vals[0], vals[1]);
418 }
419 else
420 {
421 status = ERR_INVALID_ALIAS;
422 if ( errors !is null )
423 {
424 errors ~= WError.create(defReader.fileName, defReader.getLineNumber(), status, "Invalid alias");
425 }
426 }
427 return status;
428 }
429
430 /**
431 * Creates an entry on a string[][string] associative array
432 * Params:
433 * aa =
434 * defReader =
435 * Returns:
436 */
437 private static int loadAA(ref string[][string] aa, DefReader defReader, WError*[] errors = null)
438 {
439 int status = ERR_NONE;
440 string[] vals = std..string.split(defReader.getValue());
441 if ( vals.length == 1 )
442 {
443 vals ~= "";
444 }
445 if ( vals.length == 2 )
446 {
447 aa[vals[0]] ~= vals[1];
448 debug(aa) writefln("added alias %s = %s", vals[0], vals[1]);
449 }
450 else
451 {
452 status = ERR_INVALID_ALIAS;
453 if ( errors !is null )
454 {
455 errors ~= WError.create(defReader.fileName, defReader.getLineNumber(), status, "Invalid alias");
456 }
457 }
458 return status;
459 }
460
461 /**
462 * Creates an entry on a string[][string] associative array
463 * Params:
464 * aa =
465 * defReader =
466 * Returns:
467 */
468 private static int loadAAA(ref string[string][string] aa, DefReader defReader, WError*[] errors = null)
469 {
470 int status = ERR_NONE;
471 string[] vals = std..string.split(defReader.getValue());
472 if ( vals.length == 1 )
473 {
474 vals ~= "";
475 }
476 if ( vals.length == 2 )
477 {
478 vals ~= "";
479 }
480 if ( vals.length == 3 )
481 {
482 aa[vals[0]][vals[1]] ~= vals[2];
483 debug(aa) writefln("added alias [%s][%s] = %s", vals[0], vals[1], vals[2]);
484 }
485 else
486 {
487 status = ERR_INVALID_ALIAS;
488 if ( errors !is null )
489 {
490 errors ~= WError.create(defReader.fileName, defReader.getLineNumber(), status, "Invalid alias");
491 }
492 }
493 return status;
494 }
495
496 private string loadLicense()
497 {
498 license = loadText("license");
499 return license;
500 }
501
502 private string loadText(string key)
503 {
504 string text;
505
506 while ( key!=defReader.next(false) && "end"!=defReader.getValue() )
507 {
508 if ( text.length > 0 )
509 {
510 text ~= "\n" ~ defReader.getFullLine();
511 }
512 else
513 {
514 text ~= defReader.getFullLine();
515 }
516 }
517
518 return text;
519 }
520
521 private string[] loadTextMultiLine(string key)
522 {
523 string[] text;
524
525 while ( key!=defReader.next(false) && "end"!=defReader.getValue() )
526 {
527 text ~= defReader.getFullLine();
528 }
529
530 return text;
531 }
532
533 private int copyFile(string fromDir, string toDir, string fileName)
534 {
535 debug(writeFile)writefln("GtkWrapper.copyFile %s", fileName);
536 int status = ERR_NONE;
537 debug(file)writefln("(1)GtkWrapper.copyFile %s %s", fromDir, fileName);
538 void[] text = std.file.read(std.path.buildPath(fromDir, fileName));
539 try
540 {
541 //debug(copyFile)
542 writefln("copying file [%s] to [%s]", std.path.buildPath(fromDir, fileName), std.path.buildPath(toDir, fileName));
543 if (!std.file.exists(toDir))
544 {
545 std.file.mkdir(toDir);
546 }
547 std.file.write(std.path.buildPath(toDir, fileName), text);
548 }
549 catch ( Exception e)
550 {
551 status = ERR_COPY_FILE;
552 errors ~= WError.create(defReader.fileName, defReader.getLineNumber(), status, "Cannot copy file "~fileName);
553 }
554
555 writefln("Wrappde %s", fileName);
556
557 return status;
558 }
559
560 private int wrapFile(string pack, string outPack)
561 {
562 debug(file)writefln("GtkWrapper.wrapFile pack=%s outPack=%s", pack, outPack);
563 int status = ERR_NONE;
564
565 GtkDClass gtkDClass;
566
567 ConvParms* convParms = new ConvParms;
568
569 string text;
570
571 string key = defReader.next();
572
573 string keys = " file text struct realStruct ctorStruct class template interface extend implements prefix strictPrefix"
574 " openFile mergeFile closeFile outFile"
575 " copy import import(tango) structWrap alias moduleAlias override"
576 " noprefix nostruct nocode nosignal"
577 " code interfaceCode"
578 " srcout out inout array"
579 ;
580 if (outPack == "lib") {string tmp = pack; pack = outPack; outPack = tmp;} //undo Bind hack...oupPack now holds bind dir.
581 convParms.outPack = outPack;
582 convParms.bindDir = bindingsDir;
583
584 while ( std..string.indexOf(keys, key) > 0 )
585 {
586 debug(wrapParameter)writefln("wrapFile [%s] = %s", key, defReader.getValue());
587 switch ( key )
588 {
589 case "copy": status = copyFile(apiRoot,std.path.buildPath(srcOut,outPack),defReader.getValue());
590 buildTextLibs ~= "private import " ~outPack~ "." ~defReader.getValue()[0..$-2]~ ";\n";
591 break;
592 case "srcout": srcOut = defReader.getValue(); break;
593 case "struct": convParms.strct = defReader.getValue(); break;
594 case "realStruct": convParms.realStrct = defReader.getValue(); break;
595 case "ctorStruct": convParms.ctorStrct = defReader.getValue(); break;
596 case "class": convParms.clss = defReader.getValue(); break;
597 case "extend": convParms.extend = defReader.getValue(); break;
598 case "implements": convParms.impl ~= defReader.getValue(); break;
599 case "template": convParms.templ ~= defReader.getValue(); break;
600 case "prefix": convParms.prefixes ~= defReader.getValue(); break;
601 case "strictPrefix": convParms.strictPrefix = defReader.getValueBit(); break;
602 case "noprefix": convParms.noPrefixes ~= defReader.getValue(); break;
603 case "nocode": convParms.noCode ~= defReader.getValue(); break;
604 case "nosignal": convParms.noSignals ~= defReader.getValue(); break;
605 case "nostruct": convParms.noStructs ~= defReader.getValue(); break;
606 case "import": convParms.imprts ~= defReader.getValue(); break;
607 case "import(tango)": /*ignore for now*/defReader.getValue(); break;
608 case "structWrap": loadAA(convParms.structWrap, defReader, errors); break;
609 case "alias": loadAA(convParms.aliases, defReader, errors); break;
610 case "moduleAlias": loadAA(convParms.mAliases, defReader, errors); break;
611 case "override": convParms.overrides ~= defReader.getValue(); break;
612 case "out": loadAA(convParms.outParms, defReader, errors); break;
613 case "inout": loadAA(convParms.inoutParms, defReader, errors); break;
614 case "array": loadAAA(convParms.array, defReader, errors); break;
615 case "text":
616 convParms.text ~= loadTextMultiLine("text");
617 break;
618 case "code":
619 convParms.classCode ~= loadText("code");
620 break;
621 case "interfaceCode":
622 convParms.interfaceCode ~= loadText("interfaceCode");
623 break;
624
625 case "openFile":
626 gtkDClass = openFile(outPack, text, convParms);
627 text.length = 0;
628 break;
629 case "mergeFile":
630 gtkDClass.mergeGtkDClass(text, convParms);
631 text.length = 0;
632 break;
633 case "closeFile":
634 buildText ~= "\nprivate import "
635 ~convParms.outPack~"."
636 ~defReader.getValue()~";";
637 closeFile(text, gtkDClass, convParms);
638 text.length = 0;
639 break;
640 case "interface":
641 convParms.interf = defReader.getValue();
642 string saveClass = convParms.clss;
643 string[] saveTempl = convParms.templ;
644 convParms.templ.length = 0;
645 convParms.outFile = convParms.interf;
646 convParms.isInterface = true;
647 buildText ~= "\nprivate import "
648 ~convParms.outPack~"."
649 ~defReader.getValue()~";";
650 outFile(outPack, text, convParms);
651 convParms.clss = saveClass;
652 convParms.templ = saveTempl;
653 // mark not interface (anymore)
654 convParms.isInterface = false;
655 // as outFile is always the last definition
656 // there is no need to restore it
657 break;
658 case "outFile":
659 buildText ~= "\nprivate import "
660 ~convParms.outPack~"."
661 ~defReader.getValue()~";";
662 outFile(outPack, text, convParms);
663 break;
664 case "file":
665 convParms.inFile = std..string.strip(defReader.getValue());
666 if ( convParms.inFile.length > 0 )
667 {
668 if ( startsWith(convParms.inFile, "/") )
669 {
670 debug(file)writefln("GtkWrapper.wrapFile convParms:\n%s", convParms.toString());
671 debug(file)writefln("GtkWrapper.wrapFile convParms:\n%s", defReader.toString());
672 debug(file)writefln("(2)GtkWrapper.wrapFile %s", convParms.inFile);
673 text = cast(string) std.file.read(convParms.inFile);
674 }
675 else
676 {
677 debug(file)writefln("(3)GtkWrapper.wrapFile %s", convParms.inFile);
678 text = cast(string) std.file.read(std.path.buildPath(std.path.buildPath(inputRoot,pack),convParms.inFile));
679 }
680 }
681 else
682 {
683 text.length = 0;
684 }
685 break;
686 default:
687 status = ERR_FILE_DEFINITION;
688 errors ~= WError.create(defReader.fileName, defReader.getLineNumber(), status, "Invalid file definition");
689 break;
690 }
691 key = defReader.next();
692 }
693
694 return status;
695 }
696
697 /**
698 * Opens, reads and closes a file
699 * Params:
700 * outPack =
701 * text =
702 * convParms =
703 */
704 private void outFile(string outPack, string text, ConvParms* convParms)
705 {
706 GtkDClass gtkDClass = openFile(outPack, text, convParms);
707 closeFile("", gtkDClass, convParms);
708 }
709
710 /**
711 * Opens and reads a file
712 * Params:
713 * outPack =
714 * text =
715 * convParms =
716 * Returns:
717 */
718 private GtkDClass openFile(string outPack, string text, ConvParms* convParms)
719 {
720 convParms.outFile = defReader.getValue();
721 debug(wrapFile)writefln("######### gtkDClass for %s.%s (%s)
722 bound at %s", outPack, convParms.clss,
723 convParms.outFile,convParms.bindDir);
724 GtkDClass gtkDClass = new GtkDClass(this);
725 convParms.bindDir = bindingsDir;
726 gtkDClass.openGtkDClass(text, convParms);
727
728 return gtkDClass;
729 }
730
731 private void closeFile(string text, GtkDClass gtkDClass, ConvParms* convParms)
732 {
733 debug(writeFile)writefln("GtkWrapper.closeFile %s",
734 gtkDClass.getOutFile(outputRoot, srcDir));
735 string gtkDText = gtkDClass.closeGtkDClass(text, convParms);
736 string writeDir = std.path.buildPath(outputRoot, srcDir);
737 if ( gtkDClass.getError() == 0 )
738 {
739 if (!std.file.exists(writeDir))
740 {
741 std.file.mkdir(writeDir);
742 }
743 std.file.write(gtkDClass.getOutFile(outputRoot,srcDir),gtkDText);
744 }
745 writefln("gtk Wrapped %s", gtkDClass.getOutFile(outputRoot, srcDir));
746 if ( !convParms.isInterface )
747 {
748 convParms.clearAll();
749 }
750
751 externalDeclarations ~= gtkDClass.getExternalDeclarations();
752 collectedAliases ~= gtkDClass.getAliases();
753 collectedEnums ~= gtkDClass.getEnums();
754 collectedFuncts ~= gtkDClass.getFuncts();
755 collectedStructs ~= gtkDClass.getStructs();
756 collectedTypes ~= gtkDClass.getTypes();
757 collectedUnions ~= gtkDClass.getUnions();
758 collectedConstants ~= gtkDClass.getConstants();
759 stockEnums ~= gtkDClass.getStockEnums();
760 stockChars ~= gtkDClass.getStockChars();
761 gTypes ~= gtkDClass.getGTypes();
762 }
763
764 /**
765 * Assumes input and output packages contains no spaces and are separated by a space
766 * Params:
767 * outputRoot =
768 * pack =
769 * Returns:
770 */
771 private int createPackage(string outputRoot, string packagevalue)
772 {
773 int status = ERR_NONE;
774
775 string[] packages = std..string.split(packagevalue, " ");
776 string packageDir;
777
778 if ( packages.length == 1 && "bind" == defReader.getKey() )
779 {
780 packages ~="lib";
781 packageDir = packages[0];
782 }
783 else if ( packages.length == 2 && "package" == defReader.getKey() )
784 {
785 packageDir = packages[1];
786 // nothing here
787 }
788 else
789 {
790 status = ERR_CREATE_PACKAGE;
791 }
792
793 if ( status==ERR_NONE )
794 {
795 debug(createPackage)writefln("adding (%s) %s %s", defReader.getKey(), packages[0], packages[1]);
796 this.packages[packages[0]] = packages[1];
797 try
798 {
799 std.file.mkdir(joinRootDirFile(outputRoot,srcDir,packageDir));
800 }
801 catch ( Exception e)
802 {
803 //status = 4;
804 //errors ~= WError.create(defReader.fileName, defReader.getLineNumber(), status, "Cannot create src package: "~pack);
805 }
806 try
807 {
808 std.file.mkdir(joinRootDirFile(outputRoot,"obj",
809 packageDir));
810 }
811 catch ( Exception e)
812 {
813 //status = 5;
814 //errors ~= WError.create(defReader.fileName, defReader.getLineNumber(), status, "Cannot create obj package: "~pack);
815 }
816 }
817
818 if ( status != ERR_NONE )
819 {
820 errors ~= WError.create(defReader.fileName, defReader.getLineNumber(), status,
821 "Invalid package/src definition (need in and out packages or lib name): "~packagevalue);
822 }
823
824 return status;
825 }
826
827 public void printErrors()
828 {
829 writefln("printing %s errors", errors.length);
830 foreach ( WError* error ; errors)
831 {
832 error.print();
833 }
834 }
835
836 public string getLicense()
837 {
838 return license;
839 }
840
841 public string[string] getAliases()
842 {
843 return aliases;
844 }
845
846 public string[string] getEnumTypes()
847 {
848 return enumTypes;
849 }
850
851 public bool includeComments()
852 {
853 return currIncludeComments;
854 }
855
856 void buildLoaderTable(string loaderTableName, string[] declarations)
857 {
858 string externalText = license;
859
860 externalText ~= "\nmodule "~bindingsDir~"."~loaderTableName~";\n"
861 "\nversion(Tango)"
862 "\n private import tango.stdc.stdio;"
863 "\nelse"
864 "\n private import std.stdio;\n"
865 "\nprivate import "~bindingsDir~"." ~loaderTableName~"types;";
866
867 if ( loaderTableName == "glib" )
868 {
869 externalText ~= "\nprivate import "~bindingsDir~".gthreadtypes;";
870 }
871 if ( loaderTableName == "gdk" || loaderTableName == "pango" )
872 {
873 externalText ~= "\nprivate import "~bindingsDir~".cairotypes;";
874 }
875
876 if ( loaderTableName != "gl" &&
877 loaderTableName != "glu" &&
878 loaderTableName != "glx"
879 )
880 {
881 externalText ~= "\nprivate import gtkc.Loader;"
882 "\nprivate import gtkc.paths;\n"
883 "\nmixin( _shared ~ \"static this()"
884 "\n{";
885
886 string library = "LIBRARY."~ toUpper(loaderTableName);
887
888 //Returns an array of libraries to try and link with.
889 string getLibrary(string funct)
890 {
891 if ( GtkDClass.startsWith(funct, "gdk") )
892 return library ~ ", LIBRARY.GDKPIXBUF";
893 else if ( GtkDClass.startsWith(funct, "pango_cairo") )
894 return library ~ ", LIBRARY.PANGOCAIRO";
895 else if ( GtkDClass.startsWith(funct, "g_module") )
896 return library ~ ", LIBRARY.GMODULE";
897 else
898 return library;
899 }
900
901 //Generate the static this, where the linking takes place
902 foreach ( string declaration; declarations )
903 {
904 string dec = std..string.strip(declaration);
905 sizediff_t pos = std..string.lastIndexOf(dec,')');
906
907 if (dec.length == 0)
908 continue;
909
910 if ( GtkDClass.startsWith(dec, "//") )
911 externalText ~= "\n\t"~ dec ~"\n\n";
912
913 if ( pos > 0 )
914 {
915 externalText ~= '\t';
916
917 if ( dec[0]=='#' )
918 {
919 externalText ~= "// ";
920 }
921 else
922 {
923 string functName = std..string.strip(dec[pos+1..$]);
924 if ( functName.length > 0 )
925 {
926 externalText ~= "Linker.link("~ functName ~", \\\""~ functName ~"\\\", "~ getLibrary(functName) ~");";
927 }
928 }
929 externalText ~= '\n';
930 }
931 }
932
933 externalText ~= "}\");\n\n"
934 "mixin( gshared ~\"extern(C)\n"
935 "{";
936
937 //Generate the functions.
938 foreach(string declaration ; declarations)
939 {
940 string dec = std..string.strip(declaration);
941
942 if (dec.length == 0)
943 continue;
944
945 if ( GtkDClass.startsWith(dec, "//") )
946 {
947 externalText ~= "\n\t"~ dec ~"\n\n";
948 continue;
949 }
950
951 if ( loaderTableName == "glib" || loaderTableName == "pango" )
952 dec = replace(dec, "FILE*", "void*"); //Phobos workaround.
953
954 sizediff_t pos = std..string.lastIndexOf(dec,')') + 1;
955 externalText ~= '\t';
956
957 if ( dec[0]=='#' )
958 externalText ~= "// ";
959
960 if ( !GtkDClass.startsWith(dec, "//") && dec[0]!='#' )
961 externalText ~= dec[0..pos] ~" c_"~ dec[pos..$] ~';';
962 else
963 externalText ~= dec;
964
965 externalText ~= '\n';
966 }
967
968 externalText ~= "}\");\n";
969
970 //Generate the aliases.
971 foreach ( string declaration; declarations )
972 {
973 string dec = std..string.strip(declaration);
974 sizediff_t pos = std..string.lastIndexOf(dec,')');
975
976 if (dec.length == 0)
977 continue;
978
979 if ( GtkDClass.startsWith(dec, "//") )
980 externalText ~= '\n'~ dec ~"\n\n";
981
982 if ( pos > 0 )
983 {
984 if ( dec[0]=='#' )
985 {
986 externalText ~= "// ";
987 }
988 else
989 {
990 string functName = std..string.strip(dec[pos+1..$]);
991 if ( functName.length > 0 )
992 {
993 externalText ~= "alias c_"~ functName ~" "~ functName ~";";
994 }
995 }
996 externalText ~= '\n';
997 }
998 }
999 }
1000
1001 string pathname = joinRootDirFile(std.path.buildPath(outputRoot,srcDir),bindingsDir,loaderTableName~".d");
1002 std.file.write(pathname,externalText);
1003 }
1004
1005 void buildTypedefs(string outPack)
1006 {
1007
1008 string def = license;
1009 def ~= "module "~bindingsDir~"."~outPack~"types;\n\n";
1010
1011 auto indenter = new IndentedStringBuilder();
1012
1013 def ~= indenter.format(lookupTypedefs);
1014
1015 if ( gTypes.length > 0 )
1016 {
1017 def ~= "\n\n// G_TYPE_*";
1018 def ~= "\nenum GType : size_t";
1019 def ~= "\n{\n";
1020 indenter.setIndent("\t");
1021 def ~= indenter.format(gTypes);
1022 def ~= "\n}\n\n";
1023 }
1024 indenter.setIndent("");
1025
1026 def ~= indenter.format(lookupConstants);
1027 def ~= indenter.format(lookupAliases);
1028 def ~= indenter.format(collectedAliases);
1029
1030 indenter.setIndent("");
1031 def ~= indenter.format(lookupEnums);
1032 def ~= indenter.format(collectedEnums);
1033
1034 indenter.setIndent("");
1035 def ~= indenter.format(lookupStructs);
1036 def ~= indenter.format(collectedStructs);
1037
1038 indenter.setIndent("");
1039 def ~= indenter.format(lookupTypes);
1040 def ~= indenter.format(collectedTypes);
1041
1042 indenter.setIndent("");
1043 def ~= indenter.format(lookupFuncts);
1044 def ~= indenter.format(collectedFuncts);
1045
1046 indenter.setIndent("");
1047 def ~= indenter.format(lookupUnions);
1048 def ~= indenter.format(collectedUnions);
1049
1050 if ( stockEnums.length > 0 )
1051 {
1052 def ~= "\n\n// StockIDs";
1053 def ~= "\nenum StockID";
1054 def ~= "\n{\n";
1055 indenter.setIndent("\t");
1056 def ~= indenter.format(stockEnums);
1057 def ~= "\n}";
1058 def ~= "\n\n// Stock strings";
1059 def ~= "\nstring[] StockDesc = ";
1060 def ~= "\n[";
1061 indenter.setIndent("\t");
1062 def ~= indenter.format(stockChars);
1063 def ~= "\n];";
1064 }
1065 indenter.setIndent("");
1066 def ~= indenter.format(collectedConstants);
1067
1068 string pathname =
1069 joinRootDirFile(std.path.buildPath(outputRoot,srcDir), bindingsDir, outPack~"types.d");
1070 std.file.write(pathname,def);
1071
1072 lookupTypedefs.length = 0;
1073 lookupAliases.length = 0;
1074 lookupEnums.length = 0;
1075 lookupStructs.length = 0;
1076 lookupTypes.length = 0;
1077 lookupFuncts.length = 0;
1078 lookupUnions.length = 0;
1079 lookupConstants.length = 0;
1080
1081 collectedAliases.length = 0;
1082 collectedEnums.length = 0;
1083 collectedStructs.length = 0;
1084 collectedTypes.length = 0;
1085 collectedFuncts.length = 0;
1086 collectedUnions.length = 0;
1087 collectedConstants.length = 0;
1088
1089 stockEnums.length = 0;
1090 stockChars.length = 0;
1091 gTypes.length = 0;
1092 }
1093 }
1094
1095 int main()
1096 {
1097 GtkWrapper wrapper = new GtkWrapper("./"); //Run gtkwrapper from the project directory... Make this a config option later.
1098 int status = wrapper.process("APILookup.txt");
1099 wrapper.printErrors();
1100 if ( wrapper.errors.length == 0 )
1101 {
1102 wrapper.writeBuildText();
1103 }
1104 return status;
1105 }