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 status = wrapFile(pack, outPack); 341 } 342 if ( prevPack.length>0 && outPack!=prevPack ) 343 { 344 buildTypedefs(outPack); 345 buildLoaderTable(outPack, externalDeclarations); 346 externalDeclarations.length = 0; 347 } 348 prevPack = outPack; 349 break; 350 351 case "lookup": 352 defReaders ~= defReader; 353 defReader = new DefReader(std.path.buildPath(apiRoot,defReader.getValue())); 354 defReader.next(); 355 debug(lookup)writefln("lookup on file %s (%s=%s)", defReader.getFileName(), defReader.getKey(), defReader.getValue() ); 356 break; 357 358 case "htod": 359 // not as clean as lookup... 360 // WARNING!!! writefln's are needed to avoid hang. 361 writefln("start htod"); 362 new 363 HTODConvert(defReader.getValue(),outputRoot,apiRoot); 364 writefln("end htod"); 365 defReader.next(); 366 break; 367 368 default: 369 if ( defReader.getKey().length == 0 ) 370 { 371 if ( defReaders.length > 0 ) 372 { 373 defReader = defReaders[defReaders.length-1]; 374 defReaders.length = defReaders.length -1; 375 debug(lookup)writefln("lookup back to %s (%s=%s)", defReader.getFileName(), defReader.getKey(), defReader.getValue() ); 376 defReader.next(); 377 debug(lookup)writefln("lookup next == %s (%s=%s)", defReader.getFileName(), defReader.getKey(), defReader.getValue() ); 378 } 379 else 380 { 381 defReader = null; 382 } 383 } 384 break; 385 } 386 debug(lookup)if(defReader!is null)writefln("loop (%s) %s=%s", defReader.getFileName(), defReader.getKey(), defReader.getValue() ); 387 } 388 } 389 else 390 { 391 //writefln("status = %s",status); 392 } 393 394 return status; 395 } 396 397 /** 398 * Creates an entry on a string[string] associative array 399 * Params: 400 * aa = 401 * defReader = 402 * Returns: 403 */ 404 private static int loadAA(ref string[string] aa, DefReader defReader, WError*[] errors = null) 405 { 406 int status = ERR_NONE; 407 string[] vals = std..string.split(defReader.getValue()); 408 if ( vals.length == 1 ) 409 { 410 vals ~= ""; 411 } 412 if ( vals.length == 2 ) 413 { 414 aa[vals[0]] = vals[1]; 415 debug(aa) writefln("added alias %s = %s", vals[0], vals[1]); 416 } 417 else 418 { 419 status = ERR_INVALID_ALIAS; 420 if ( errors !is null ) 421 { 422 errors ~= WError.create(defReader.fileName, defReader.getLineNumber(), status, "Invalid alias"); 423 } 424 } 425 return status; 426 } 427 428 /** 429 * Creates an entry on a string[][string] associative array 430 * Params: 431 * aa = 432 * defReader = 433 * Returns: 434 */ 435 private static int loadAA(ref string[][string] aa, DefReader defReader, WError*[] errors = null) 436 { 437 int status = ERR_NONE; 438 string[] vals = std..string.split(defReader.getValue()); 439 if ( vals.length == 1 ) 440 { 441 vals ~= ""; 442 } 443 if ( vals.length == 2 ) 444 { 445 aa[vals[0]] ~= vals[1]; 446 debug(aa) writefln("added alias %s = %s", vals[0], vals[1]); 447 } 448 else 449 { 450 status = ERR_INVALID_ALIAS; 451 if ( errors !is null ) 452 { 453 errors ~= WError.create(defReader.fileName, defReader.getLineNumber(), status, "Invalid alias"); 454 } 455 } 456 return status; 457 } 458 459 /** 460 * Creates an entry on a string[][string] associative array 461 * Params: 462 * aa = 463 * defReader = 464 * Returns: 465 */ 466 private static int loadAAA(ref string[string][string] aa, DefReader defReader, WError*[] errors = null) 467 { 468 int status = ERR_NONE; 469 string[] vals = std..string.split(defReader.getValue()); 470 if ( vals.length == 1 ) 471 { 472 vals ~= ""; 473 } 474 if ( vals.length == 2 ) 475 { 476 vals ~= ""; 477 } 478 if ( vals.length == 3 ) 479 { 480 aa[vals[0]][vals[1]] ~= vals[2]; 481 debug(aa) writefln("added alias [%s][%s] = %s", vals[0], vals[1], vals[2]); 482 } 483 else 484 { 485 status = ERR_INVALID_ALIAS; 486 if ( errors !is null ) 487 { 488 errors ~= WError.create(defReader.fileName, defReader.getLineNumber(), status, "Invalid alias"); 489 } 490 } 491 return status; 492 } 493 494 private string loadLicense() 495 { 496 license = loadText("license"); 497 return license; 498 } 499 500 private string loadText(string key) 501 { 502 string text; 503 504 while ( key!=defReader.next(false) && "end"!=defReader.getValue() ) 505 { 506 if ( text.length > 0 ) 507 { 508 text ~= "\n" ~ defReader.getFullLine(); 509 } 510 else 511 { 512 text ~= defReader.getFullLine(); 513 } 514 } 515 516 return text; 517 } 518 519 private string[] loadTextMultiLine(string key) 520 { 521 string[] text; 522 523 while ( key!=defReader.next(false) && "end"!=defReader.getValue() ) 524 { 525 text ~= defReader.getFullLine(); 526 } 527 528 return text; 529 } 530 531 private int copyFile(string fromDir, string toDir, string fileName) 532 { 533 debug(writeFile)writefln("GtkWrapper.copyFile %s", fileName); 534 int status = ERR_NONE; 535 debug(file)writefln("(1)GtkWrapper.copyFile %s %s", fromDir, fileName); 536 void[] text = std.file.read(std.path.buildPath(fromDir, fileName)); 537 try 538 { 539 //debug(copyFile) 540 writefln("copying file [%s] to [%s]", std.path.buildPath(fromDir, fileName), std.path.buildPath(toDir, fileName)); 541 if (!std.file.exists(toDir)) 542 { 543 std.file.mkdir(toDir); 544 } 545 std.file.write(std.path.buildPath(toDir, fileName), text); 546 } 547 catch ( Exception e) 548 { 549 status = ERR_COPY_FILE; 550 errors ~= WError.create(defReader.fileName, defReader.getLineNumber(), status, "Cannot copy file "~fileName); 551 } 552 553 writefln("Wrappde %s", fileName); 554 555 return status; 556 } 557 558 private int wrapFile(string pack, string outPack) 559 { 560 debug(file)writefln("GtkWrapper.wrapFile pack=%s outPack=%s", pack, outPack); 561 int status = ERR_NONE; 562 563 GtkDClass gtkDClass; 564 565 ConvParms* convParms = new ConvParms; 566 567 string text; 568 569 string key = defReader.next(); 570 571 string keys = " file text struct realStruct ctorStruct class template interface extend implements prefix strictPrefix" 572 " openFile mergeFile closeFile outFile" 573 " copy import import(tango) structWrap alias moduleAlias override" 574 " noprefix nostruct nocode nosignal" 575 " code interfaceCode" 576 " srcout out inout array" 577 ; 578 if (outPack == "lib") {string tmp = pack; pack = outPack; outPack = tmp;} //undo Bind hack...oupPack now holds bind dir. 579 convParms.outPack = outPack; 580 convParms.bindDir = bindingsDir; 581 582 while ( std..string.indexOf(keys, key) > 0 ) 583 { 584 debug(wrapParameter)writefln("wrapFile [%s] = %s", key, defReader.getValue()); 585 switch ( key ) 586 { 587 case "copy": status = copyFile(apiRoot,std.path.buildPath(srcOut,outPack),defReader.getValue()); 588 buildTextLibs ~= "private import " ~outPack~ "." ~defReader.getValue()[0..$-2]~ ";\n"; 589 break; 590 case "srcout": srcOut = defReader.getValue(); break; 591 case "struct": convParms.strct = defReader.getValue(); break; 592 case "realStruct": convParms.realStrct = defReader.getValue(); break; 593 case "ctorStruct": convParms.ctorStrct = defReader.getValue(); break; 594 case "class": convParms.clss = defReader.getValue(); break; 595 case "extend": convParms.extend = defReader.getValue(); break; 596 case "implements": convParms.impl ~= defReader.getValue(); break; 597 case "template": convParms.templ ~= defReader.getValue(); break; 598 case "prefix": convParms.prefixes ~= defReader.getValue(); break; 599 case "strictPrefix": convParms.strictPrefix = defReader.getValueBit(); break; 600 case "noprefix": convParms.noPrefixes ~= defReader.getValue(); break; 601 case "nocode": convParms.noCode ~= defReader.getValue(); break; 602 case "nosignal": convParms.noSignals ~= defReader.getValue(); break; 603 case "nostruct": convParms.noStructs ~= defReader.getValue(); break; 604 case "import": convParms.imprts ~= defReader.getValue(); break; 605 case "import(tango)": /*ignore for now*/defReader.getValue(); break; 606 case "structWrap": loadAA(convParms.structWrap, defReader, errors); break; 607 case "alias": loadAA(convParms.aliases, defReader, errors); break; 608 case "moduleAlias": loadAA(convParms.mAliases, defReader, errors); break; 609 case "override": convParms.overrides ~= defReader.getValue(); break; 610 case "out": loadAA(convParms.outParms, defReader, errors); break; 611 case "inout": loadAA(convParms.inoutParms, defReader, errors); break; 612 case "array": loadAAA(convParms.array, defReader, errors); break; 613 case "text": 614 convParms.text ~= loadTextMultiLine("text"); 615 break; 616 case "code": 617 convParms.classCode ~= loadText("code"); 618 break; 619 case "interfaceCode": 620 convParms.interfaceCode ~= loadText("interfaceCode"); 621 break; 622 623 case "openFile": 624 gtkDClass = openFile(outPack, text, convParms); 625 text.length = 0; 626 break; 627 case "mergeFile": 628 gtkDClass.mergeGtkDClass(text, convParms); 629 text.length = 0; 630 break; 631 case "closeFile": 632 buildText ~= "\nprivate import " 633 ~convParms.outPack~"." 634 ~defReader.getValue()~";"; 635 closeFile(text, gtkDClass, convParms); 636 text.length = 0; 637 break; 638 case "interface": 639 convParms.interf = defReader.getValue(); 640 string saveClass = convParms.clss; 641 string[] saveTempl = convParms.templ; 642 convParms.templ.length = 0; 643 convParms.outFile = convParms.interf; 644 convParms.isInterface = true; 645 buildText ~= "\nprivate import " 646 ~convParms.outPack~"." 647 ~defReader.getValue()~";"; 648 outFile(outPack, text, convParms); 649 convParms.clss = saveClass; 650 convParms.templ = saveTempl; 651 // mark not interface (anymore) 652 convParms.isInterface = false; 653 // as outFile is always the last definition 654 // there is no need to restore it 655 break; 656 case "outFile": 657 buildText ~= "\nprivate import " 658 ~convParms.outPack~"." 659 ~defReader.getValue()~";"; 660 outFile(outPack, text, convParms); 661 break; 662 case "file": 663 convParms.inFile = std..string.strip(defReader.getValue()); 664 if ( convParms.inFile.length > 0 ) 665 { 666 if ( startsWith(convParms.inFile, "/") ) 667 { 668 debug(file)writefln("GtkWrapper.wrapFile convParms:\n%s", convParms.toString()); 669 debug(file)writefln("GtkWrapper.wrapFile convParms:\n%s", defReader.toString()); 670 debug(file)writefln("(2)GtkWrapper.wrapFile %s", convParms.inFile); 671 text = cast(string) std.file.read(convParms.inFile); 672 } 673 else 674 { 675 debug(file)writefln("(3)GtkWrapper.wrapFile %s", convParms.inFile); 676 text = cast(string) std.file.read(std.path.buildPath(std.path.buildPath(inputRoot,pack),convParms.inFile)); 677 } 678 } 679 else 680 { 681 text.length = 0; 682 } 683 break; 684 default: 685 status = ERR_FILE_DEFINITION; 686 errors ~= WError.create(defReader.fileName, defReader.getLineNumber(), status, "Invalid file definition"); 687 break; 688 } 689 key = defReader.next(); 690 } 691 692 return status; 693 } 694 695 /** 696 * Opens, reads and closes a file 697 * Params: 698 * outPack = 699 * text = 700 * convParms = 701 */ 702 private void outFile(string outPack, string text, ConvParms* convParms) 703 { 704 GtkDClass gtkDClass = openFile(outPack, text, convParms); 705 closeFile("", gtkDClass, convParms); 706 } 707 708 /** 709 * Opens and reads a file 710 * Params: 711 * outPack = 712 * text = 713 * convParms = 714 * Returns: 715 */ 716 private GtkDClass openFile(string outPack, string text, ConvParms* convParms) 717 { 718 convParms.outFile = defReader.getValue(); 719 debug(wrapFile)writefln("######### gtkDClass for %s.%s (%s) 720 bound at %s", outPack, convParms.clss, 721 convParms.outFile,convParms.bindDir); 722 GtkDClass gtkDClass = new GtkDClass(this); 723 convParms.bindDir = bindingsDir; 724 gtkDClass.openGtkDClass(text, convParms); 725 726 return gtkDClass; 727 } 728 729 private void closeFile(string text, GtkDClass gtkDClass, ConvParms* convParms) 730 { 731 debug(writeFile)writefln("GtkWrapper.closeFile %s", 732 gtkDClass.getOutFile(outputRoot, srcDir)); 733 string gtkDText = gtkDClass.closeGtkDClass(text, convParms); 734 string writeDir = std.path.buildPath(outputRoot, srcDir); 735 if ( gtkDClass.getError() == 0 ) 736 { 737 if (!std.file.exists(writeDir)) 738 { 739 std.file.mkdir(writeDir); 740 } 741 std.file.write(gtkDClass.getOutFile(outputRoot,srcDir),gtkDText); 742 } 743 writefln("gtk Wrapped %s", gtkDClass.getOutFile(outputRoot, srcDir)); 744 if ( !convParms.isInterface ) 745 { 746 convParms.clearAll(); 747 } 748 749 externalDeclarations ~= gtkDClass.getExternalDeclarations(); 750 collectedAliases ~= gtkDClass.getAliases(); 751 collectedEnums ~= gtkDClass.getEnums(); 752 collectedFuncts ~= gtkDClass.getFuncts(); 753 collectedStructs ~= gtkDClass.getStructs(); 754 collectedTypes ~= gtkDClass.getTypes(); 755 collectedUnions ~= gtkDClass.getUnions(); 756 collectedConstants ~= gtkDClass.getConstants(); 757 stockEnums ~= gtkDClass.getStockEnums(); 758 stockChars ~= gtkDClass.getStockChars(); 759 gTypes ~= gtkDClass.getGTypes(); 760 } 761 762 /** 763 * Assumes input and output packages contains no spaces and are separated by a space 764 * Params: 765 * outputRoot = 766 * pack = 767 * Returns: 768 */ 769 private int createPackage(string outputRoot, string packagevalue) 770 { 771 int status = ERR_NONE; 772 773 string[] packages = std..string.split(packagevalue, " "); 774 string packageDir; 775 776 if ( packages.length == 1 && "bind" == defReader.getKey() ) 777 { 778 packages ~="lib"; 779 packageDir = packages[0]; 780 } 781 else if ( packages.length == 2 && "package" == defReader.getKey() ) 782 { 783 packageDir = packages[1]; 784 // nothing here 785 } 786 else 787 { 788 status = ERR_CREATE_PACKAGE; 789 } 790 791 if ( status==ERR_NONE ) 792 { 793 debug(createPackage)writefln("adding (%s) %s %s", defReader.getKey(), packages[0], packages[1]); 794 this.packages[packages[0]] = packages[1]; 795 try 796 { 797 std.file.mkdir(joinRootDirFile(outputRoot,srcDir,packageDir)); 798 } 799 catch ( Exception e) 800 { 801 //status = 4; 802 //errors ~= WError.create(defReader.fileName, defReader.getLineNumber(), status, "Cannot create src package: "~pack); 803 } 804 try 805 { 806 std.file.mkdir(joinRootDirFile(outputRoot,"obj", 807 packageDir)); 808 } 809 catch ( Exception e) 810 { 811 //status = 5; 812 //errors ~= WError.create(defReader.fileName, defReader.getLineNumber(), status, "Cannot create obj package: "~pack); 813 } 814 } 815 816 if ( status != ERR_NONE ) 817 { 818 errors ~= WError.create(defReader.fileName, defReader.getLineNumber(), status, 819 "Invalid package/src definition (need in and out packages or lib name): "~packagevalue); 820 } 821 822 return status; 823 } 824 825 public void printErrors() 826 { 827 writefln("printing %s errors", errors.length); 828 foreach ( WError* error ; errors) 829 { 830 error.print(); 831 } 832 } 833 834 public string getLicense() 835 { 836 return license; 837 } 838 839 public string[string] getAliases() 840 { 841 return aliases; 842 } 843 844 public string[string] getEnumTypes() 845 { 846 return enumTypes; 847 } 848 849 public bool includeComments() 850 { 851 return currIncludeComments; 852 } 853 854 void buildLoaderTable(string loaderTableName, string[] declarations) 855 { 856 string externalText = license; 857 858 externalText ~= "\nmodule "~bindingsDir~"."~loaderTableName~";\n" 859 "\nversion(Tango)" 860 "\n private import tango.stdc.stdio;" 861 "\nelse" 862 "\n private import std.stdio;\n" 863 "\nprivate import "~bindingsDir~"." ~loaderTableName~"types;"; 864 865 if ( loaderTableName == "glib" ) 866 { 867 externalText ~= "\nprivate import "~bindingsDir~".gthreadtypes;"; 868 } 869 if ( loaderTableName == "gdk" || loaderTableName == "pango" ) 870 { 871 externalText ~= "\nprivate import "~bindingsDir~".cairotypes;"; 872 } 873 874 if ( loaderTableName != "gl" && 875 loaderTableName != "glu" && 876 loaderTableName != "glx" 877 ) 878 { 879 externalText ~= "\nprivate import gtkc.Loader;" 880 "\nprivate import gtkc.paths;\n" 881 "\nmixin( _shared ~ \"static this()" 882 "\n{"; 883 884 string library = "LIBRARY."~ toUpper(loaderTableName); 885 886 //Returns an array of libraries to try and link with. 887 string getLibrary(string funct) 888 { 889 if ( GtkDClass.startsWith(funct, "gdk") ) 890 return library ~ ", LIBRARY.GDKPIXBUF"; 891 else if ( GtkDClass.startsWith(funct, "pango_cairo") ) 892 return library ~ ", LIBRARY.PANGOCAIRO"; 893 else if ( GtkDClass.startsWith(funct, "g_module") ) 894 return library ~ ", LIBRARY.GMODULE"; 895 else 896 return library; 897 } 898 899 //Generate the static this, where the linking takes place 900 foreach ( string declaration; declarations ) 901 { 902 string dec = std..string.strip(declaration); 903 sizediff_t pos = std..string.lastIndexOf(dec,')'); 904 905 if (dec.length == 0) 906 continue; 907 908 if ( GtkDClass.startsWith(dec, "//") ) 909 externalText ~= "\n\t"~ dec ~"\n\n"; 910 911 if ( pos > 0 ) 912 { 913 externalText ~= '\t'; 914 915 if ( dec[0]=='#' ) 916 { 917 externalText ~= "// "; 918 } 919 else 920 { 921 string functName = std..string.strip(dec[pos+1..$]); 922 if ( functName.length > 0 ) 923 { 924 externalText ~= "Linker.link("~ functName ~", \\\""~ functName ~"\\\", "~ getLibrary(functName) ~");"; 925 } 926 } 927 externalText ~= '\n'; 928 } 929 } 930 931 externalText ~= "}\");\n\n" 932 "mixin( gshared ~\"extern(C)\n" 933 "{"; 934 935 //Generate the functions. 936 foreach(string declaration ; declarations) 937 { 938 string dec = std..string.strip(declaration); 939 940 if (dec.length == 0) 941 continue; 942 943 if ( GtkDClass.startsWith(dec, "//") ) 944 { 945 externalText ~= "\n\t"~ dec ~"\n\n"; 946 continue; 947 } 948 949 if ( loaderTableName == "glib" || loaderTableName == "pango" ) 950 dec = replace(dec, "FILE*", "void*"); //Phobos workaround. 951 952 sizediff_t pos = std..string.lastIndexOf(dec,')') + 1; 953 externalText ~= '\t'; 954 955 if ( dec[0]=='#' ) 956 externalText ~= "// "; 957 958 if ( !GtkDClass.startsWith(dec, "//") && dec[0]!='#' ) 959 externalText ~= dec[0..pos] ~" c_"~ dec[pos..$] ~';'; 960 else 961 externalText ~= dec; 962 963 externalText ~= '\n'; 964 } 965 966 externalText ~= "}\");\n"; 967 968 //Generate the aliases. 969 foreach ( string declaration; declarations ) 970 { 971 string dec = std..string.strip(declaration); 972 sizediff_t pos = std..string.lastIndexOf(dec,')'); 973 974 if (dec.length == 0) 975 continue; 976 977 if ( GtkDClass.startsWith(dec, "//") ) 978 externalText ~= '\n'~ dec ~"\n\n"; 979 980 if ( pos > 0 ) 981 { 982 if ( dec[0]=='#' ) 983 { 984 externalText ~= "// "; 985 } 986 else 987 { 988 string functName = std..string.strip(dec[pos+1..$]); 989 if ( functName.length > 0 ) 990 { 991 externalText ~= "alias c_"~ functName ~" "~ functName ~";"; 992 } 993 } 994 externalText ~= '\n'; 995 } 996 } 997 } 998 999 string pathname = joinRootDirFile(std.path.buildPath(outputRoot,srcDir),bindingsDir,loaderTableName~".d"); 1000 std.file.write(pathname,externalText); 1001 } 1002 1003 void buildTypedefs(string outPack) 1004 { 1005 1006 string def = license; 1007 def ~= "module "~bindingsDir~"."~outPack~"types;\n\n"; 1008 1009 auto indenter = new IndentedStringBuilder(); 1010 1011 def ~= indenter.format(lookupTypedefs); 1012 1013 if ( gTypes.length > 0 ) 1014 { 1015 def ~= "\n\n// G_TYPE_*"; 1016 def ~= "\nenum GType : size_t"; 1017 def ~= "\n{\n"; 1018 indenter.setIndent("\t"); 1019 def ~= indenter.format(gTypes); 1020 def ~= "\n}\n\n"; 1021 } 1022 indenter.setIndent(""); 1023 1024 def ~= indenter.format(lookupConstants); 1025 def ~= indenter.format(lookupAliases); 1026 def ~= indenter.format(collectedAliases); 1027 1028 indenter.setIndent(""); 1029 def ~= indenter.format(lookupEnums); 1030 def ~= indenter.format(collectedEnums); 1031 1032 indenter.setIndent(""); 1033 def ~= indenter.format(lookupStructs); 1034 def ~= indenter.format(collectedStructs); 1035 1036 indenter.setIndent(""); 1037 def ~= indenter.format(lookupTypes); 1038 def ~= indenter.format(collectedTypes); 1039 1040 indenter.setIndent(""); 1041 def ~= indenter.format(lookupFuncts); 1042 def ~= indenter.format(collectedFuncts); 1043 1044 indenter.setIndent(""); 1045 def ~= indenter.format(lookupUnions); 1046 def ~= indenter.format(collectedUnions); 1047 1048 if ( stockEnums.length > 0 ) 1049 { 1050 def ~= "\n\n// StockIDs"; 1051 def ~= "\nenum StockID"; 1052 def ~= "\n{\n"; 1053 indenter.setIndent("\t"); 1054 def ~= indenter.format(stockEnums); 1055 def ~= "\n}"; 1056 def ~= "\n\n// Stock strings"; 1057 def ~= "\nstring[] StockDesc = "; 1058 def ~= "\n["; 1059 indenter.setIndent("\t"); 1060 def ~= indenter.format(stockChars); 1061 def ~= "\n];"; 1062 } 1063 indenter.setIndent(""); 1064 def ~= indenter.format(collectedConstants); 1065 1066 string pathname = 1067 joinRootDirFile(std.path.buildPath(outputRoot,srcDir), bindingsDir, outPack~"types.d"); 1068 std.file.write(pathname,def); 1069 1070 lookupTypedefs.length = 0; 1071 lookupAliases.length = 0; 1072 lookupEnums.length = 0; 1073 lookupStructs.length = 0; 1074 lookupTypes.length = 0; 1075 lookupFuncts.length = 0; 1076 lookupUnions.length = 0; 1077 lookupConstants.length = 0; 1078 1079 collectedAliases.length = 0; 1080 collectedEnums.length = 0; 1081 collectedStructs.length = 0; 1082 collectedTypes.length = 0; 1083 collectedFuncts.length = 0; 1084 collectedUnions.length = 0; 1085 collectedConstants.length = 0; 1086 1087 stockEnums.length = 0; 1088 stockChars.length = 0; 1089 gTypes.length = 0; 1090 } 1091 } 1092 1093 int main() 1094 { 1095 GtkWrapper wrapper = new GtkWrapper("./"); //Run gtkwrapper from the project directory... Make this a config option later. 1096 int status = wrapper.process("APILookup.txt"); 1097 wrapper.printErrors(); 1098 if ( wrapper.errors.length == 0 ) 1099 { 1100 wrapper.writeBuildText(); 1101 } 1102 return status; 1103 }