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