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 }