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.GtkDClass; 21 22 //debug = getBlock; 23 //debug = getUntil; 24 //debug = Funct; 25 //debug = stringToGtkD; 26 //debug = tokenToGtkD; 27 //debug = endFunction; 28 //debug = defines; 29 //debug = functName; 30 //debug = noPrefixes; 31 //debug = functionType; 32 //debug = declaration; 33 //debug = structs; 34 //debug = enums; 35 //debug = enumPrefix; 36 //debug = unions; 37 //debug = parmType; 38 //debug = parmName; 39 //debug = enumToGtkD; 40 //debug = getParent; 41 //debug = getSignal; 42 //debug = signalFunction; 43 //debug = stockItems; 44 //debug = gTypes; 45 //debug = implements; 46 //debug = getMember; 47 48 //version = noGtkBody; 49 50 /** 51 * Creates a GtkD class 52 */ 53 54 //Moved here because of dsss: 55 private import utils.HtmlStrip; 56 private import utils.WrapperIF; 57 private import utils.IndentedStringBuilder; 58 private import utils.convparms; 59 private import utils.funct; 60 61 private import std.ascii: isLower; 62 private import std.path; 63 private import std.stdio; 64 private import std.array; 65 private import std.string; 66 private import std.conv; 67 68 public class GtkDClass 69 { 70 private WrapperIF wrapper; 71 private string inAPI; 72 private string[] inLines; 73 int currLine; 74 75 private int status = 0; 76 private int countBlock = 0; 77 78 ConvParms* convParms; 79 80 string iFaceChar = ""; 81 82 private string parentName; /// gtk parent struct 83 private string gtkDParentName; /// gtkD parent name 84 private string gtkDParentNamePrefix; /// gtkD parent name package 85 86 private string[] externalDeclarations; /// the external definition to pass to the wrapper 87 88 private string[] collectedAliases; /// public, module level type aliases 89 private string[] collectedEnums; /// public, module level definitions of enums 90 private string[] stockEnums; /// special enums for the SotckID 91 private string[] gTypes; /// special enums for G_TYPE_* 92 private string[] stockChars; /// the string value for the stockIDs 93 private string[] collectedStructs; /// public, module level definitions of structs 94 private string[] collectedTypes; /// public, module level definitions of other types 95 private string[] collectedFuncts; /// public, module level definitions of functions 96 private string[] collectedUnions; /// public, module level definitions of unions 97 private string[] collectedConstants;/// public, module level constants 98 99 100 private string gtkDText; 101 102 private string[] properties; 103 private string[] styleProperties; 104 private string[] signals; 105 private string[] description; 106 private IndentedStringBuilder indenter; 107 108 string[] members; 109 110 int[string] functionSignatures; 111 int[string] gtkStructs; 112 113 114 private bool needSignalImports; 115 116 private string tabs; /// used for simple indentation 117 118 public this (WrapperIF wrapper ) 119 { 120 this.wrapper = wrapper; 121 indenter = new IndentedStringBuilder(); 122 } 123 124 public string[] getExternalDeclarations() 125 { 126 return externalDeclarations; 127 } 128 129 public string[] getAliases() 130 { 131 return collectedAliases; 132 } 133 134 public string[] getConstants() 135 { 136 return collectedConstants; 137 } 138 139 public string[] getEnums() 140 { 141 return collectedEnums; 142 } 143 public string[] getStockEnums() 144 { 145 return stockEnums; 146 } 147 public string[] getStockChars() 148 { 149 return stockChars; 150 } 151 152 public string[] getGTypes() 153 { 154 return gTypes; 155 } 156 157 public string[] getStructs() 158 { 159 return collectedStructs; 160 } 161 162 public string[] getTypes() 163 { 164 return collectedTypes; 165 } 166 167 public string[] getFuncts() 168 { 169 return collectedFuncts; 170 } 171 172 public string[] getUnions() 173 { 174 return collectedUnions; 175 } 176 177 public int getError() 178 { 179 return status; 180 } 181 182 private int[string] getCleanSigns() 183 { 184 int[string] cleanSignature; 185 return cleanSignature; 186 } 187 188 /** Construct the wrapped class according to all the collected 189 * information. 190 */ 191 public void openGtkDClass(string inAPI, ConvParms* convParms) 192 { 193 //writefln("collectStructs %s", std.string.strip(inLines[currLine])); 194 this.inAPI = inAPI; 195 if ( convParms.isInterface ) iFaceChar = ";"; 196 else iFaceChar = ""; 197 HtmlStrip stripper = new HtmlStrip(); 198 inLines = std..string.splitLines(stripper.strip(inAPI)); 199 //writefln("new API\n%s",inAPI); 200 201 functionSignatures = getCleanSigns(); 202 gtkStructs = getCleanSigns(); 203 204 this.convParms = convParms; 205 206 collectedAliases.length = 0; 207 collectedEnums.length = 0; 208 stockEnums.length = 0; 209 stockChars.length = 0; 210 gTypes.length = 0; 211 collectedStructs.length = 0; 212 collectedUnions.length = 0; 213 collectedTypes.length = 0; 214 collectedFuncts.length = 0; 215 collectedConstants.length = 0; 216 217 needSignalImports = true; 218 219 string privPub = ( convParms.templ.length > 0 ) ? "public" : "private"; 220 221 externalDeclarations ~= ""; 222 externalDeclarations ~= "// " ~ convParms.outPack ~ '.' ~ convParms.clss; 223 externalDeclarations ~= ""; 224 225 gtkDText = wrapper.getLicense(); 226 227 gtkDText ~= convParms.toString(); 228 229 gtkDText ~= "module "~convParms.outPack~"."; 230 if ( convParms.clss.length > 0 ) 231 { 232 gtkDText ~= convParms.outFile; 233 } 234 else if ( convParms.outFile.length > 0 ) 235 { 236 gtkDText ~= convParms.outFile; 237 } 238 gtkDText ~= ";\n\n"; 239 240 /* Type information should be publicly imported by all modules. */ 241 gtkDText ~= "public import " ~convParms.bindDir~ "." ~convParms.outPack~ "types;\n\n"; 242 gtkDText ~= privPub ~" import " ~convParms.bindDir~ "." ~convParms.outPack ~ ";\n"; 243 gtkDText ~= privPub ~" import glib.ConstructionException;\n"; 244 245 if ( convParms.outPack != "cairo" && convParms.outPack != "glib" && convParms.outPack != "gthread" ) 246 gtkDText ~= privPub ~" import gobject.ObjectG;\n"; 247 248 gtkDText ~= "\n"; 249 250 // move signal imports out of classes - JJR 251 if (needSignalImports) 252 { 253 int i = moveToBlockStart("Signal Details", inLines); 254 // if "Signal Details" exists in API Lines 255 // than we know that we need signal imports. 256 if (i < inLines.length) 257 { 258 gtkDText ~= privPub ~" import gobject.Signals;\n"; 259 gtkDText ~= "public import gtkc.gdktypes;\n"; 260 } 261 } 262 263 // the use of phobs is limited, maybe we can get by with this... 264 265 string[][string] tangoImportConvs; 266 tangoImportConvs["std.stdio"] = ["tango.io.Stdout"]; 267 tangoImportConvs["std.thread"] = ["tango.core.Thread"]; 268 tangoImportConvs["std.string"] = ["tango.text.Util", "tango.text.Unicode"]; 269 tangoImportConvs["std.c.string"] = ["tango.stdc.string"]; 270 tangoImportConvs["std.c.stdio"] = ["tango.stdc.stdio"]; 271 tangoImportConvs["std.gc"] = ["tango.core.Memory"]; 272 tangoImportConvs["std.stdarg"] = ["tango.core.Vararg"]; 273 tangoImportConvs["std.conv"] = ["tango.text.convert.Integer"]; 274 275 string[][string] druntimeImportConvs; 276 druntimeImportConvs["std.thread"] = ["core.thread"]; 277 druntimeImportConvs["std.c.string"] = ["core.stdc.string"]; 278 druntimeImportConvs["std.gc"] = ["core.memory"]; 279 druntimeImportConvs["std.stdarg"] = ["core.vararg"]; 280 281 string[][string] phobos2ImportConvs; 282 phobos2ImportConvs["std.stdio"] = ["std.stdio"]; 283 phobos2ImportConvs["std.c.stdio"] = ["core.stdc.stdio"]; 284 phobos2ImportConvs["std.string"] = ["std.string"]; 285 phobos2ImportConvs["std.conv"] = ["std.conv"]; 286 287 string importTango = "\nversion(Tango) {\n"; 288 string importDruntime = "} else version(D_Version2) {\n"; 289 string importElse = "} else {\n"; 290 string importCommon = "\n"; 291 292 int countTango; 293 int countDruntime; 294 295 foreach( string imprt ; convParms.imprts ) 296 { 297 if ( imprt in druntimeImportConvs ) 298 { 299 ++countDruntime; 300 foreach ( string d2Imp ; druntimeImportConvs[imprt] ) 301 { 302 importDruntime ~= "\t"~ privPub ~" import "~d2Imp~";\n"; 303 } 304 } 305 if ( imprt in phobos2ImportConvs ) 306 { 307 foreach ( string phobos2Imp ; phobos2ImportConvs[imprt] ) 308 { 309 importDruntime ~= "\t"~ privPub ~" import "~phobos2Imp~";\n"; 310 } 311 } 312 313 if ( imprt in tangoImportConvs ) 314 { 315 ++countTango; 316 foreach ( string tangoImp ; tangoImportConvs[imprt] ) 317 { 318 importTango ~= "\t"~ privPub ~" import "~tangoImp~";\n"; 319 } 320 importElse ~= "\t"~ privPub ~" import "~imprt~";\n"; 321 } 322 else 323 { 324 importCommon ~= privPub ~" import "~imprt~";\n"; 325 } 326 } 327 328 gtkDText ~= importCommon~"\n"; 329 if ( countTango > 0 ) 330 { 331 gtkDText ~= importTango; 332 333 if ( countDruntime > 0 ) 334 { 335 gtkDText ~= "\n\tversion = druntime;\n"; 336 gtkDText ~= importDruntime; 337 gtkDText ~= "\n\tversion = druntime;\n"; 338 } 339 340 gtkDText ~= importElse~"}\n"; 341 } 342 343 properties.length = 0; 344 styleProperties.length = 0; 345 signals.length = 0; 346 347 readGtkDClass(convParms); 348 349 gtkDText ~= "\n"; 350 351 foreach ( string key ; convParms.mAliases.keys.sort ) 352 { 353 gtkDText ~= "public alias "~key~" "~convParms.mAliases[key]~";"; 354 } 355 gtkDText ~= "\n"; 356 357 // reset the parent name 358 parentName = null; 359 gtkDParentName = ""; 360 361 string[] classHead = openClass(convParms); 362 gtkDText ~= indenter.format(classHead); 363 } 364 365 private void readGtkDClass(ConvParms* convParms) 366 { 367 description = getDescription(); 368 properties ~= getProperties(); 369 styleProperties ~= getStyleProperties(); 370 signals ~= getSignals(); 371 372 members ~= getMembers(convParms); 373 374 } 375 376 public void mergeGtkDClass(string inAPI, ConvParms* convParms) 377 { 378 this.inAPI = inAPI; 379 HtmlStrip stripper = new HtmlStrip(); 380 inLines = std..string.splitLines(stripper.strip(inAPI)); 381 //writefln("new API\n%s",inAPI); 382 383 this.convParms = convParms; 384 385 readGtkDClass(convParms); 386 387 if ( wrapper.includeComments() ) 388 { 389 gtkDText ~= indenter.format(description); 390 } 391 392 } 393 394 public string closeGtkDClass(string inAPI, ConvParms* convParms) 395 { 396 mergeGtkDClass(inAPI, convParms); 397 398 gtkDText ~= indenter.format(properties); 399 gtkDText ~= indenter.format(styleProperties); 400 gtkDText ~= indenter.format(signals); 401 gtkDText ~= indenter.format(members); 402 gtkDText ~= closeClass(convParms); 403 404 return gtkDText; 405 } 406 407 /** 408 * Gets the name to the output file 409 * Params: 410 * outputRoot = 411 * Returns: 412 */ 413 public string getOutFile(string outputRoot, string srcOut) 414 { 415 string outF = std.path.buildPath(outputRoot, srcOut); 416 outF = std.path.buildPath(outF, convParms.outPack); 417 outF = std.path.buildPath(outF, (convParms.clss.length>0 ? convParms.outFile : convParms.outFile)); 418 return outF~".d"; 419 } 420 421 422 /** 423 * Checks if we are a template and if the parent name 424 * Params: 425 * parentName = 426 * Returns: 427 */ 428 private string getClassHeader(ConvParms* convParms, string parentName) 429 { 430 string h; 431 if ( convParms.isInterface ) 432 { 433 h = "public interface "~convParms.interf; 434 } 435 else if ( convParms.templ.length == 0 ) 436 { 437 h = "public class "~convParms.clss; 438 } 439 else 440 { 441 h = "public template "~convParms.clss~"("; 442 443 foreach ( int count, string tp ; convParms.templ ) 444 { 445 if ( count > 0 ) 446 { 447 h ~= ", "; 448 } 449 h ~= tp; 450 } 451 h ~= ")"; 452 } 453 if ( parentName.length > 0 ) 454 { 455 h ~= " : " ~ parentName; 456 } 457 return h; 458 } 459 460 /** 461 * Create the class header. 462 * If the class name is empty this is not a class so no header is created 463 * Params: 464 * clss = The class Name 465 * Returns: 466 */ 467 private string[] openClass(ConvParms* convParms) 468 { 469 string[] text; 470 471 if ( convParms.clss.length > 0 ) 472 { 473 getParent(); 474 if ( gtkDParentName.length > 0 475 && gtkDParentNamePrefix.length > 0 476 ) 477 { 478 text ~= "private import "~gtkDParentNamePrefix~"."~gtkDParentName~";"; 479 } 480 481 if ( wrapper.includeComments() ) 482 { 483 foreach(string line; description) 484 text ~= line; 485 } 486 487 text ~= getClassHeader(convParms, gtkDParentName) 488 ~ getImplements(convParms, gtkDParentName); 489 // string implements = getImplements(convParms, gtkDParentName); 490 // if ( implements.length > 0 ) 491 // { 492 // text ~= implements; 493 // } 494 text ~= "{"; 495 } 496 497 // moved from module level 498 //text ~= "private import "~convParms.outPack ~ "."~convParms.outPack~"types;\n\n"; 499 //text ~= "private import lib."~convParms.outPack ~ ";\n\n"; 500 501 // moved to module level - AND BACK AGAIN 502 //foreach( string imprt ; convParms.imprts ) 503 //{ 504 // text ~= "private import "~imprt~";"; 505 //} 506 507 string flipG(string inStr) 508 { 509 if ( inStr[0] == 'G' ) 510 { 511 return (inStr[1 .. $] ~ 'G'); 512 } 513 514 return inStr; 515 } 516 517 if ( convParms.strct.length > 0 ) 518 { 519 string gtkStruct = convParms.realStrct.length > 0 520 ? convParms.realStrct 521 : convParms.strct; 522 string var = toVar(gtkStruct); 523 text ~= ""; 524 if ( !convParms.isInterface ) 525 { 526 text ~= "/** the main Gtk struct */"; 527 text ~= "protected "~gtkStruct~"* "~var~";"; 528 text ~= ""; 529 } 530 531 if ( convParms.clss.length > 0 ) 532 { 533 text ~= ""; 534 535 if ( convParms.templ.length > 0 ) 536 { 537 text ~= "public "~gtkStruct~"* get"~convParms.clss~"Struct()"~iFaceChar; 538 if ( !convParms.isInterface ) 539 { 540 text ~= "{"; 541 text ~= "return cast("~gtkStruct~"*)getStruct();"; 542 text ~= "}"; 543 } 544 text ~= ""; 545 } 546 else 547 { 548 if ( gtkDParentName == "GioMountOperation" || gtkDParentName == "GioApplication" ) 549 text ~= "public "~gtkStruct~"* getGtk"~convParms.clss~"Struct()"~iFaceChar; 550 else if ( gtkDParentName == "GioAppLaunchContext" ) 551 text ~= "public "~gtkStruct~"* getGdk"~convParms.clss~"Struct()"~iFaceChar; 552 else 553 text ~= "public "~gtkStruct~"* get"~convParms.clss~"Struct()"~iFaceChar; 554 if ( !convParms.isInterface ) 555 { 556 text ~= "{"; 557 text ~= "return " ~ var ~ ';'; 558 text ~= "}"; 559 text ~= ""; 560 } 561 text ~= ""; 562 text ~= "/** the main Gtk struct as a void* */"; 563 if ( gtkDParentName.length > 0 && gtkDParentName != "Boxed" ) 564 text ~= "protected override void* getStruct()"~iFaceChar; 565 else 566 text ~= "protected void* getStruct()"~iFaceChar; 567 if ( !convParms.isInterface ) 568 { 569 text ~= "{"; 570 text ~= "return cast(void*)" ~ var ~ ';'; 571 text ~= "}"; 572 } 573 text ~= ""; 574 if ( "GObject" != convParms.strct ) 575 { 576 // GObject has a specific constructor for the struct 577 if ( !convParms.isInterface ) 578 { 579 text ~= "/**"; 580 text ~= " * Sets our main struct and passes it to the parent class"; 581 text ~= " */"; 582 text ~= "public this ("~gtkStruct~"* "~var~")"~iFaceChar; 583 text ~= "{"; 584 585 if ( parentName.length > 0 && gtkDParentName != "Boxed" ) 586 { 587 text ~= "super("~castToParent(var)~");"; 588 } 589 text ~= "this."~var~" = "~var~";"; 590 text ~= "}"; 591 592 if ( parentName.length > 0 && convParms.outPack != "cairo" && gtkDParentName != "Boxed" ) 593 { 594 text ~= ""; 595 text ~= "protected override void setStruct(GObject* obj)"; 596 text ~= "{"; 597 text ~= " super.setStruct(obj);"; 598 text ~= " "~var~" = cast("~gtkStruct~"*)obj;"; 599 text ~= "}"; 600 } 601 } 602 } 603 } 604 } 605 } 606 607 addStaticClassCode(convParms, text); 608 609 return text; 610 611 } 612 613 /* Deprecated */ /* 614 string[] assertStructNotNull = [ 615 ]; 616 617 private string[] getAssertStructNotNull(string var) 618 { 619 string[] lines = [ 620 "version(noAssert)", 621 "{", 622 " if ( "~var~" is null )", 623 " {", 624 " int zero = 0;", 625 " version(Tango)", 626 " {", 627 " Stdout(\"struct "~var~" is null on constructor\").newline;", 628 " }", 629 " else", 630 " {", 631 " printf(\"struct "~var~" is null on constructor\");", 632 " }", 633 " zero = zero / zero;", 634 " }", 635 "}", 636 "else", 637 "{", 638 " assert("~var~" !is null, \"struct "~var~" is null on constructor\");", 639 "}" 640 ] 641 ; 642 return lines; 643 } 644 */ 645 646 647 /** 648 * Adds the class code from the conversion parameters. 649 * If current output is a interface the body functions 650 * will be removed (at least we'll try to remove it) 651 * Params: 652 * convParms = 653 */ 654 private void addStaticClassCode(ConvParms* convParms, ref string[] text) 655 { 656 string code; 657 658 if ( convParms.isInterface ) code = convParms.interfaceCode; 659 else code = convParms.classCode; 660 661 if ( code.length > 0 ) 662 { 663 text ~= ""; 664 foreach ( string line ; std..string.splitLines(code)) 665 { 666 text ~= std..string.strip(line); 667 } 668 } 669 } 670 671 private string castToParent(string var) 672 { 673 return "cast("~parentName~"*)"~var; 674 } 675 676 /** 677 * Converts a type to a var. 678 * lower case the first letter 679 * Params: 680 * type = 681 * Returns: 682 */ 683 public static string toVar(string type) 684 { 685 if (type.length == 0) 686 return ""; 687 688 string p = to!string(toLower(type[0])); 689 if ( type.endsWith("_t") ) 690 { 691 return p ~ type[1 .. $ - 2]; 692 } else { 693 return p ~ type[1 .. $]; 694 } 695 } 696 697 /** 698 * Close the class by adding the final brace 699 * If the class name is empty this is not a class so no closing is necessary 700 * Params: 701 * clss = The class name 702 * Returns: 703 */ 704 private string closeClass(ConvParms* convParms) 705 { 706 if ( tabs.length > 0 ) 707 { 708 tabs.length = tabs.length -1; 709 } 710 return convParms.clss.length>0 ? "}\n" : "\n"; 711 } 712 713 /** 714 * Read the parent class under "Object Hierarchy" section 715 * or get from the extend on the convParms 716 * Params: 717 * clss = 718 * Returns: 719 */ 720 private string getParent() 721 { 722 debug(getParent) writefln("getParent for %s ", convParms.outFile); 723 724 if ( parentName is null ) 725 { 726 if ( convParms.extend.length > 0 ) 727 { 728 parentName = convParms.extend; 729 gtkDParentName = convertClassName(convParms.extend); 730 } 731 else 732 { 733 int i = moveToBlockStart("Object Hierarchy", inLines); 734 i += 2; 735 while ( i < inLines.length && !startsWith(std..string.strip(inLines[i]), "+----") ) 736 { 737 debug(getParent)writefln("\t skip line %s", inLines[i]); 738 ++i; 739 } 740 debug(getParent) 741 { 742 writefln("getParent 1 "); 743 for ( int j=i-3 ;j<inLines.length && j<i+5 ; j++) 744 { 745 writefln("\t getParent line = %s", inLines[j]); 746 } 747 if ( i<inLines.length ) writefln("\t getParent first line = %s", inLines[i]); 748 } 749 string parent; 750 string current; 751 string next; 752 753 if ( i < inLines.length ) 754 { 755 next = std..string.strip(inLines[i-1]); // many times "GObject" 756 if ( next != "GInterface" ) 757 { 758 current = next; 759 } 760 } 761 string gtkStruct = convParms.strct; 762 if ( convParms.realStrct.length > 0 ) 763 { 764 gtkStruct = convParms.realStrct; 765 } 766 while ( i < inLines.length 767 && startsWith(std..string.strip(inLines[i]), "+----") 768 && current != gtkStruct 769 ) 770 { 771 parent = current; 772 next = inLines[i][6..inLines[i].length]; 773 if ( "GInitiallyUnowned" != next ) 774 { 775 current = next; 776 debug(getParent) writefln("\t current = %s", current); 777 } 778 ++i; 779 } 780 if ( gtkStruct == current && parent.length>0 ) 781 { 782 parentName = parent; 783 gtkDParentName = convertClassName(parentName); 784 } 785 } 786 } 787 return parentName; 788 } 789 790 private string convertClassName(string gName) 791 { 792 string conv; 793 string prefix; 794 795 if ( startsWith(gName, "GtkSource") ) prefix = "Gsv"; 796 else if ( startsWith(gName, "Gtk") ) prefix = "Gtk"; 797 else if ( startsWith(gName, "Gio") ) prefix = ""; 798 else if ( startsWith(gName, "Gdk") ) prefix = "Gdk"; 799 else if ( startsWith(gName, "Gst") ) prefix = "Gst"; 800 else if ( startsWith(gName, "Gda") ) prefix = "Gda"; 801 else if ( startsWith(gName, "Atk") ) prefix = "Atk"; 802 else if ( startsWith(gName, "G") ) prefix = "G"; 803 else if ( startsWith(gName, "Pango") ) prefix = "Pg"; 804 else if ( startsWith(gName, "cairo") ) prefix = "cairo"; 805 806 conv = gName[prefix.length..gName.length]; 807 808 if ( conv == "Object" ) conv ~= prefix; 809 if ( prefix == "Pg" ) conv = "Pg" ~ gName[5..gName.length]; 810 if ( prefix == "cairo") conv = std..string.toUpper(gName[6..7]) ~ gName[7..gName.length - 2]; 811 812 debug(getParent)writefln("convertClassName %s >>> %s", gName, conv); 813 prefix = std..string.toLower(prefix); 814 815 //TODO: better way to covert Gio names. 816 if( prefix == "g" && convParms.outPack == "gio" && conv != "ObjectG" && conv != "TypeModule" && conv != "Boxed" ) 817 prefix = "gio"; 818 819 if( prefix == "gst") prefix = "gstreamer"; 820 if( prefix == "g") prefix = "gobject"; 821 if( prefix == "pg" ) prefix = "pango"; 822 if ( startsWith(gName, "Gio") ) parentName = "G"~ gName[3 .. $]; 823 824 gtkDParentNamePrefix = prefix; 825 return conv; 826 } 827 828 /** 829 * Under "Implemented Interfaces" section 830 * Params: 831 * clss = 832 * Returns: 833 */ 834 private string getImplements(ConvParms* convParms, string parentName) 835 { 836 string impls; 837 foreach ( int count, string impl ; convParms.impl ) 838 { 839 if ( count > 0 || parentName.length > 0) 840 { 841 impls ~= ", "; 842 } 843 else if ( count == 0 || parentName.length == 0) 844 { 845 impls ~= " : "; 846 } 847 impls ~= impl; 848 } 849 return impls; 850 } 851 852 /* TODO */ 853 private string[] getProperties() 854 { 855 string[] text; 856 857 return text; 858 } 859 860 /* TODO */ 861 private string[] getStyleProperties() 862 { 863 string[] text; 864 865 return text; 866 } 867 868 869 /** 870 * All the signals 871 * Returns: 872 */ 873 private string[] getSignals() 874 { 875 string[] text; 876 debug(getSignal) writefln("\tgetSignals"); 877 878 int i = moveToBlockStart("Signal Details", inLines); 879 880 i += 2; 881 882 debug(getSignal)if(i<inLines.length)writefln("\t %s", inLines[i]); 883 884 while ( i<inLines.length && startsWith(inLines[i], "The \"") ) 885 { 886 text ~= getSignal(i, inLines); 887 while ( i<inLines.length && !startsWith(inLines[i], "The \"") ) 888 { 889 debug(getSignal) writefln("\tgoto next\t%s", inLines[i]); 890 ++i; 891 } 892 } 893 894 return text; 895 } 896 897 private string[] getSignal(ref int i, string[] lines) 898 { 899 debug(getSignal) writefln("\tgetSignal %s", lines[i]); 900 string[] text; 901 sizediff_t endPos = std..string.lastIndexOf(lines[i], '"'); 902 if ( endPos > 5 ) 903 { 904 string signalName = lines[i][5..endPos]; 905 906 ++i; 907 string funct = getSignalFunctionDeclaration(i, lines); 908 909 if(!convParms.omitSignal(signalName)) 910 { 911 string[] comments; 912 if ( wrapper.includeComments ) 913 { 914 comments ~= "/**"; 915 while ( i<lines.length && lines[i] != "<hr>" ) 916 { 917 debug(getSignal) writefln("\t\t%s", lines[i]); 918 919 if(lines[i].length == 0) 920 { 921 //Skip empty lines. 922 ++i; 923 } 924 else if(indexOf(lines[i], ":") == lines[i].length-1) 925 { 926 //Skip the parameters. 927 ++i; 928 929 while(i<lines.length && stilInParam(lines[i])) 930 ++i; 931 } 932 else 933 { 934 comments ~= " * "~lines[i]; 935 ++i; 936 } 937 } 938 comments ~= "*/"; 939 } 940 941 Funct fun = Funct(funct, convParms, wrapper.getAliases()); 942 943 string gtkDSignal = signalNameToGtkD(signalName); 944 string delegateDeclaration = fun.getDelegateDeclaration(1); 945 946 // Removed function "addSignalImports" and replaced it 947 // with simple "if" block to make sure class local imports 948 // don't get added - JJR 949 950 if ( needSignalImports ) 951 { 952 if ( !convParms.isInterface ) 953 { 954 text ~= "int[string] connectedSignals;"; 955 } 956 text ~= ""; 957 958 needSignalImports = false; 959 } 960 961 if(convParms.isInterface) 962 { 963 text ~= delegateDeclaration ~ "[] on" ~ gtkDSignal~"Listeners();" ; 964 text ~= comments; 965 } 966 else if(!convParms.isInterface && convParms.templ.length > 0) 967 { 968 text ~= delegateDeclaration ~ "[] _on" ~ gtkDSignal~"Listeners;"; 969 text ~= delegateDeclaration ~ "[] on" ~ gtkDSignal~"Listeners()"; 970 text ~= "{"; 971 text ~= " return _on" ~ gtkDSignal~"Listeners;"; 972 text ~= "}"; 973 text ~= comments; 974 } 975 else 976 { 977 text ~= delegateDeclaration ~ "[] on" ~ gtkDSignal~"Listeners;" ; 978 text ~= comments; 979 } 980 981 addAddListener(text, signalName, gtkDSignal, delegateDeclaration); 982 addExternCallback(text, fun, gtkDSignal, delegateDeclaration); 983 } 984 } 985 return text; 986 } 987 988 /* 989 * Params: 990 * text = the string[] to append the function to. 991 * funct = the signal function 992 * gtkDSignal = the GtkD name for the signal 993 * dlg = the delegale for this signal 994 */ 995 void addExternCallback(ref string[] text, Funct fun, string gtkDSignal, string dlg) 996 { 997 if ( !convParms.isInterface ) 998 { 999 if ( startsWith(dlg, "bool") ) 1000 { 1001 text ~= "extern(C) static gboolean callBack"~gtkDSignal~"(" 1002 ~fun.getCallbackParameters() 1003 ~")"; 1004 } 1005 else 1006 { 1007 text ~= "extern(C) static void callBack"~gtkDSignal~"(" 1008 ~ std.array.replace(fun.getCallbackParameters(), "string", "str") 1009 ~")"; 1010 } 1011 text ~= "{"; 1012 text ~= " foreach ( "~dlg~" dlg ; _"~idsToGtkD(getClassVar(convParms), convParms, wrapper.getAliases())~".on"~gtkDSignal~"Listeners )"; 1013 text ~= " {"; 1014 if ( startsWith(dlg, "bool") ) 1015 { 1016 text ~= " if ( dlg("~fun.getCallbackVars()~") )"; 1017 text ~= " {"; 1018 text ~= " return 1;"; 1019 text ~= " }"; 1020 text ~= " }"; 1021 text ~= " "; 1022 text ~= " return 0;"; 1023 } 1024 else 1025 { 1026 text ~= " dlg("~ std.array.replace(fun.getCallbackVars(), "string", "str")~");"; 1027 text ~= " }"; 1028 } 1029 text ~= "}"; 1030 text ~= ""; 1031 } 1032 } 1033 1034 void addAddListener(ref string[] text, string signalName, string gtkDSignalName, string dlg) 1035 { 1036 text ~= "void addOn"~gtkDSignalName~"("~dlg~" dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)"~iFaceChar; 1037 if ( !convParms.isInterface ) 1038 { 1039 text ~= "{"; 1040 text ~= "if ( !(\""~signalName~"\" in connectedSignals) )"; 1041 text ~= "{"; 1042 1043 // TODO move this to the config files or read it from the Gtk docs (how?) 1044 if ( convParms.clss != "StatusIcon") 1045 { 1046 switch ( signalName ) 1047 { 1048 case "button-press-event": text ~= "addEvents(EventMask.BUTTON_PRESS_MASK);"; break; 1049 case "button-release-event": 1050 text ~= "addEvents(EventMask.BUTTON_PRESS_MASK);"; 1051 text ~= "addEvents(EventMask.BUTTON_RELEASE_MASK);"; 1052 break; 1053 case "motion-notify-event": text ~= "addEvents(EventMask.POINTER_MOTION_MASK);"; break; 1054 default: 1055 break; 1056 } 1057 } 1058 1059 text ~= " Signals.connectData("; 1060 text ~= " getStruct(), "; 1061 text ~= " \""~signalName~"\", "; 1062 text ~= " cast(GCallback)&callBack"~gtkDSignalName~", "; 1063 1064 if(convParms.templ.length > 0) 1065 text ~= " cast(void*)cast("~ convParms.interf ~")this, "; 1066 else 1067 text ~= " cast(void*)this, "; 1068 1069 text ~= " null, "; 1070 text ~= " connectFlags);"; 1071 text ~= " connectedSignals[\""~signalName~"\"] = 1;"; 1072 text ~= "}"; 1073 1074 if(convParms.templ.length > 0) 1075 text ~= "_on"~gtkDSignalName~"Listeners ~= dlg;"; 1076 else 1077 text ~= "on"~gtkDSignalName~"Listeners ~= dlg;"; 1078 1079 text ~= "}"; 1080 } 1081 } 1082 1083 public static string getClassVar(ConvParms* convParms) 1084 { 1085 string cv; 1086 if ( convParms.interf.length > 0) 1087 { 1088 cv = convParms.interf; 1089 } 1090 else if ( convParms.clss.length > 0 ) 1091 { 1092 cv = convParms.clss; 1093 } 1094 1095 return (cv is null) ? null : (toLower(cv[0 .. 1]) ~ cv[1 .. $]); 1096 } 1097 1098 private string signalNameToGtkD(string signalName) 1099 { 1100 string signalGtkD; 1101 1102 char pc = ' '; 1103 foreach ( int count, char c ; signalName ) 1104 { 1105 if ( count == 0 ) 1106 { 1107 signalGtkD ~= toUpper(c); 1108 } 1109 else 1110 { 1111 if ( c!='-' && c!='_' ) 1112 { 1113 if ( pc=='-' || pc=='_' ) 1114 { 1115 signalGtkD ~= toUpper(c); 1116 } 1117 else 1118 { 1119 signalGtkD ~= c; 1120 } 1121 } 1122 } 1123 pc = c; 1124 } 1125 1126 //writefln("signalGtkD = %s", signalGtkD); 1127 1128 if ( "MapEvent" != signalGtkD 1129 && "UnmapEvent" != signalGtkD 1130 && "DestroyEvent" != signalGtkD 1131 && endsWith(signalGtkD, "Event") ) 1132 { 1133 signalGtkD = signalGtkD[0..signalGtkD.length-5]; 1134 } 1135 1136 return signalGtkD; 1137 } 1138 1139 1140 private string getSignalFunctionDeclaration(ref int line, string[] lines) 1141 { 1142 debug(signalFunction)writefln("getSignalFunctionDeclaration"); 1143 string funct; 1144 while ( line<lines.length 1145 && std..string.indexOf(lines[line], ")")<0 1146 ) 1147 { 1148 funct ~= lines[line]~ " "; 1149 debug(endFunction)writefln("funct line = >>>%s<<< endWith(\");\") = ", 1150 lines[line], 1151 endsWith(lines[line], ");") 1152 ); 1153 ++line; 1154 } 1155 if ( line<lines.length && std..string.indexOf(lines[line], ")")>0 ) 1156 { 1157 funct ~= lines[line++]; 1158 } 1159 return funct; 1160 } 1161 1162 1163 1164 private string[] getMembers(ConvParms* convParms) 1165 { 1166 currLine = 0; 1167 getUntil("Details"); 1168 1169 string[] text; 1170 1171 while ( currLine < inLines.length ) 1172 { 1173 string[] member = getMember(convParms.prefixes); 1174 1175 //Don't add empty members. 1176 if(member.length > 1) 1177 text ~= member; 1178 } 1179 1180 return text; 1181 } 1182 1183 /** Searches for new members in the documentation. Starts from 1184 * the last kown position. 1185 * Params: 1186 * prefixes = a list of valid prefixes for new members 1187 * (gtk_xxx_). 1188 */ 1189 private string[] getMember(string[] prefixes) 1190 { 1191 string[] lines; 1192 string[] member; 1193 1194 if ( convParms.text.length > 0 ) 1195 { 1196 lines = getUntil("<hr>", convParms.text); 1197 1198 if ( lines.length != convParms.text.length ) 1199 convParms.text = convParms.text[lines.length+1 .. $]; 1200 else 1201 convParms.text.length = 0; 1202 } 1203 else 1204 { 1205 lines ~= getUntil("<hr>"); 1206 } 1207 1208 //debug(structs){ 1209 // writefln("lines[1] = %s", lines[1]); 1210 //}else debug(enums){ 1211 // writefln("lines[1] = %s", lines[1]); 1212 //} 1213 1214 1215 debug(getMember) 1216 { 1217 writefln("getMember:"); 1218 foreach (string line ; lines ) 1219 { 1220 writefln("\t%s", line); 1221 } 1222 } 1223 if ( lines.length < 2 ) 1224 { 1225 return member; 1226 } 1227 1228 1229 member ~= ""; 1230 if ( endsWith(lines[0],"()") ) 1231 { 1232 member ~= getFunction(lines, prefixes); 1233 } 1234 else if ( startsWith(lines[1], "typedef enum") ) 1235 { 1236 if ( !convParms.strictPrefix 1237 && !convParms.isInterface 1238 ) 1239 { 1240 collectEnums(lines, convParms); 1241 } 1242 } 1243 else if ( startsWith(lines[1], "typedef struct") 1244 || startsWith(lines[1], "struct") 1245 ) 1246 { 1247 if ( !convParms.strictPrefix 1248 && !convParms.isInterface 1249 ) 1250 { 1251 collectStructs(lines, convParms); 1252 } 1253 } 1254 else if ( startsWith(lines[0], "union") ) 1255 { 1256 if ( !convParms.strictPrefix 1257 && !convParms.isInterface 1258 ) 1259 { 1260 collectUnions(lines, convParms); 1261 } 1262 } 1263 else if ( startsWith(lines[1], "typedef") ) 1264 { 1265 if ( !convParms.strictPrefix 1266 && !convParms.isInterface 1267 ) 1268 { 1269 collectAliases(lines, convParms); 1270 } 1271 } 1272 else if ( startsWith(lines[0], "GTK_STOCK_") ) 1273 { 1274 if ( !convParms.isInterface ) 1275 { 1276 collectStockItems(lines, convParms); 1277 } 1278 } 1279 else if ( startsWith(lines[0], "G_TYPE_") 1280 && convParms.outFile == "Type" 1281 ) 1282 { 1283 if ( !convParms.isInterface ) 1284 { 1285 collectGTypes(lines, convParms); 1286 } 1287 } 1288 1289 return member; 1290 } 1291 1292 1293 private void collectGTypes(string[] lines, ConvParms* convParms) 1294 { 1295 debug(gTypes)writefln("gype lines\n\t%s\n\t%s\n\t%s",lines[0],lines[1],lines[2]); 1296 int defLine = 1; 1297 if ( lines.length > 0 1298 && std..string.indexOf(lines[defLine],"G_TYPE_MAKE_FUNDAMENTAL")>=0 1299 && endsWith(lines[defLine],")") 1300 && std..string.indexOf(lines[defLine],"<<") < 0 1301 ) 1302 { 1303 sizediff_t pos = std..string.indexOf(lines[defLine], "("); 1304 if ( pos > 0 ) 1305 { 1306 sizediff_t posf = std..string.indexOf(lines[defLine], ")"); 1307 if ( posf>pos ) 1308 { 1309 gTypes ~= lines[0][7..lines[0].length] 1310 ~ " = "~lines[defLine][pos+1..posf]~"<<2" 1311 ~ ","; 1312 } 1313 } 1314 } 1315 } 1316 1317 // we expect all stock constants to be defined in one file 1318 int stockCurrEnum; 1319 1320 1321 private void collectStockItems(string[] lines, ConvParms* convParms) 1322 { 1323 debug(stockItems)writefln("stock items lines\n\t%s\n\t%s\n\t%s",lines[0],lines[1],lines[2]); 1324 int defLine = 1; 1325 if ( lines.length > 0 && startsWith(lines[defLine],"#define GTK_") ) 1326 { 1327 string line = lines[defLine]; 1328 string stockID; 1329 string stockValue; 1330 1331 sizediff_t pos = std..string.indexOf(line[12..line.length],' ')+12; 1332 debug(stockItems)writefln("pos=%s", pos); 1333 if ( pos > 12 ) 1334 { 1335 stockID = line[12..pos]; 1336 if ( startsWith(stockID, "STOCK_") ) 1337 { 1338 stockID = stockID[6..stockID.length]; 1339 } 1340 debug(stockItems)writefln("\t\tstockID = %s", stockID); 1341 if ( stockID.length>0 ) 1342 { 1343 stockValue = std..string.strip(line[pos+1..line.length]); 1344 debug(stockItems)writefln("\t\tstockValue = %s", stockValue); 1345 if ( stockValue.length>2 1346 && stockValue[0] == '"' 1347 && endsWith(stockValue, '"') 1348 ) 1349 { 1350 int ln = defLine+1; 1351 stockEnums ~= ""; 1352 stockEnums ~= "/**"; 1353 while ( ln < lines.length && lines[ln][0] > ' ' ) 1354 { 1355 stockEnums ~= " * "~lines[ln++]; 1356 } 1357 stockEnums ~= " */"; 1358 stockEnums ~= stockID~","; 1359 stockChars ~= "\""~stockValue[1..stockValue.length-1]~"\","; 1360 //collectedConstants ~= 1361 // "const StockID "~stockID 1362 // ~" = cast(StockID)\""~stockValue[1..stockValue.length-1]~"\";"; 1363 } 1364 } 1365 } 1366 1367 } 1368 1369 } 1370 1371 private void collectAliases(string[] lines, ConvParms* convParms) 1372 { 1373 int pos = 0; 1374 string[] tokens = std..string.split(until(pos, lines[1], ';')); 1375 1376 if ( convParms.omitCode(tokens[2]) ) 1377 return; 1378 1379 string alis = "public alias " ~ tokens[1] ~ ' ' ~ tokens[2] ~ ';'; 1380 1381 collectedAliases ~= ""; 1382 collectedAliases ~= "/**"; 1383 int ln = 1; 1384 while ( ln < lines.length && lines[ln][0] > ' ' ) 1385 { 1386 collectedAliases ~= " * "~lines[ln++]; 1387 } 1388 collectedAliases ~= " */"; 1389 collectedAliases ~= stringToGtkD(alis, convParms, wrapper.getAliases()); 1390 1391 } 1392 1393 private string getEnumPrefix(string enumName, string enumEntry) 1394 { 1395 debug(enumPrefix)writefln("%s.%s", enumName, enumEntry); 1396 string prefix; 1397 string upper = std..string.toUpper(enumName); 1398 int n = 0; 1399 int e = 0; 1400 1401 bool endOfStrings() 1402 { 1403 bool v = (n>=upper.length) || (e>=enumEntry.length); 1404 debug(enumPrefix) if (v) writefln("\t ended by endfStrings"); 1405 return v; 1406 } 1407 1408 bool isUnderscore() 1409 { 1410 bool v = enumEntry[e] == '_'; 1411 return v; 1412 } 1413 1414 bool sameChar() 1415 { 1416 bool v = upper[n] == enumEntry[e]; 1417 debug(enumPrefix) if (!v) writefln("\t ended by sameChar"); 1418 return v; 1419 } 1420 1421 bool isSuffix() 1422 { 1423 bool v = upper.length-n == 4 1424 && ( upper[n..n+4]=="TYPE" 1425 || upper[n..n+4]=="FLAG" 1426 || upper[n..n+4]=="MODE" 1427 ); 1428 debug(enumPrefix) if (v) writefln("\t ended by isSuffix"); 1429 return v; 1430 } 1431 1432 while ( !endOfStrings() 1433 && ( isUnderscore() 1434 || 1435 ( sameChar() && !isSuffix() ) 1436 ) 1437 ) 1438 { 1439 if ( upper[n] == enumEntry[e] ) 1440 { 1441 ++n; 1442 ++e; 1443 } 1444 else 1445 { 1446 ++e; 1447 } 1448 1449 } 1450 1451 if ( e < enumEntry.length ) 1452 { 1453 while ( e >0 && enumEntry[e]!= '_' ) 1454 { 1455 --e; 1456 } 1457 } 1458 1459 1460 if ( e<enumEntry.length && enumEntry[e] == '_' ) 1461 { 1462 ++e; 1463 } 1464 1465 prefix = enumEntry[0..e]; 1466 debug(enumPrefix) writefln("\t%s", prefix); 1467 return prefix; 1468 } 1469 1470 private void collectEnums(string[] lines, ConvParms* convParms) 1471 { 1472 string enumName = lines[0][5..lines[0].length]; 1473 string gtkDEnumName; 1474 1475 bool isGdkPrefix(string name) 1476 { 1477 return 1478 startsWith(enumName, "Gdk") 1479 ; 1480 } 1481 1482 //TODO: add an option for this to the APILookup files 1483 if ( enumName == "GstEventType" || enumName == "GstEventTypeFlags" ) 1484 return; 1485 1486 if ( startsWith(enumName, "Gtk") 1487 || isGdkPrefix(enumName) 1488 ) 1489 { 1490 gtkDEnumName = enumName[3..enumName.length]; 1491 if ( gtkDEnumName == "Function" ) gtkDEnumName = "Funct"; 1492 } 1493 else if ( startsWith(enumName, "Gst") ) 1494 { 1495 gtkDEnumName = enumName[3..enumName.length]; 1496 if ( gtkDEnumName == "Function" ) gtkDEnumName = "Funct"; 1497 } 1498 else if ( startsWith(enumName, "G") ) 1499 { 1500 gtkDEnumName = enumName[1..enumName.length]; 1501 } 1502 else if ( startsWith(enumName, "cairo") ) 1503 { 1504 gtkDEnumName = "C" ~ removeUnderscore(enumName[1 .. $-2]); 1505 } 1506 //string enumName = removeUnderscore(lines[0][5..lines[0].length]); 1507 debug(enums)writefln("enum %s", enumName); 1508 string[] values; 1509 // skipp until the start of the enumerations 1510 int pos = 1; 1511 while ( pos<lines.length 1512 && !endsWith(std..string.strip(lines[pos]),'{') 1513 && !startsWith(std..string.strip(lines[pos]),'{') 1514 && !startsWith(lines[pos], "typedef enum {") 1515 ) 1516 { 1517 debug(enums)writefln("\tskipp line: %s", lines[pos]); 1518 ++pos; 1519 } 1520 ++pos; 1521 bool invalidDEnum = false; 1522 if ( pos<lines.length && lines[pos][0] != '}' ) 1523 { 1524 while ( lines[pos].strip.startsWith("/+") || lines[pos].strip.startsWith("*") || lines[pos].strip.startsWith("+/") ) 1525 { 1526 values ~= lines[pos]; 1527 pos++; 1528 } 1529 1530 string enumPrefix = getEnumPrefix(enumName, std..string.strip(lines[pos])); 1531 while ( pos<lines.length && lines[pos][0] != '}' ) 1532 { 1533 debug(enums)writefln("\tenum line %s", lines[pos]); 1534 1535 string value = lines[pos++].strip().chomp("\\"); 1536 debug(enums)writefln("\traw %s", value); 1537 value = enumToGtkD(enumName, value, convParms, wrapper); 1538 debug(enums)writefln("\tprocessed %s", value); 1539 1540 //if ( std.string.indexOf(value, ":") >= 0 ) 1541 //{ 1542 // invalidDEnum = true; 1543 // debug(structs)writefln("- INVALID >>>%s<<<", value); 1544 //} 1545 //else 1546 if ( startsWith(value, '#') ) 1547 { 1548 // ignore 1549 debug(enums)writefln("= IGNORED >>>%s<<<", value); 1550 } 1551 else 1552 { 1553 debug(enumPrefix)writefln("\t\t%s", value); 1554 string v = std.array.replace(value, enumPrefix, ""); 1555 v = std.array.replace(v, "(int)", "cast(int)"); 1556 if ( enumName == "cairo_ps_level_t" ) 1557 { 1558 v = "LEVEL_"~v; 1559 } 1560 else if ( v.length > 2 ) 1561 { 1562 switch (v[0..3]) 1563 { 1564 case "2BI": v = "TOO_"~v[1..v.length]; break; 1565 case "2BU": v = "DOUBLE_"~v[1..v.length]; break; 1566 case "3BU": v = "TRIPLE_"~v[1..v.length]; break; 1567 case "1_1": v = "VERSION_"~v; break; 1568 case "1_2": v = "VERSION_"~v; break; 1569 case "1_4": v = "VERSION_"~v; break; 1570 case "1_5": v = "VERSION_"~v; break; 1571 default: 1572 // nothing 1573 break; 1574 } 1575 } 1576 1577 values ~= v; 1578 1579 debug(enums)writefln("+ ADDED >>>%s<<<", v); 1580 } 1581 } 1582 } 1583 ++pos; 1584 if ( pos < lines.length ) 1585 { 1586 collectedEnums ~= "/**"; 1587 while ( pos < lines.length && lines[pos] != "<hr>" ) 1588 { 1589 collectedEnums ~= " * "~lines[pos++]; 1590 } 1591 collectedEnums ~= " */"; 1592 } 1593 if ( invalidDEnum ) 1594 { 1595 collectedEnums ~= "// TODO "; 1596 collectedEnums ~= "// public enum "~enumName; 1597 } 1598 else 1599 { 1600 collectedEnums ~= "public enum "~enumName; 1601 collectedEnums ~= "{"; 1602 1603 foreach ( string value ; values ) 1604 { 1605 debug(enums)writefln("\t\t%s", value); 1606 collectedEnums ~= stringToGtkD(value, convParms, wrapper.getAliases()); 1607 } 1608 1609 collectedEnums ~= "}"; 1610 if ( gtkDEnumName.length > 0 1611 && !startsWith(gtkDEnumName, "Gdk") 1612 ) 1613 { 1614 collectedEnums ~= "alias "~enumName~" "~gtkDEnumName ~ ";"; 1615 collectedEnums ~= ""; 1616 } 1617 1618 } 1619 } 1620 1621 private void collectUnions(string[] lines, ConvParms* convParms) 1622 { 1623 string unionName = lines[0][6..lines[0].length]; 1624 1625 foreach ( name; convParms.noStructs ) 1626 { 1627 if(name == unionName) 1628 return; 1629 } 1630 1631 if ( unionName == "cairo_path_data_t" ) 1632 { 1633 collectedUnions ~= ""; 1634 collectedUnions ~= "// skipped union "~unionName; 1635 collectedUnions ~= ""; 1636 return; 1637 } 1638 debug(unions)writefln("union %s", unionName); 1639 string[] values; 1640 int pos = 3; 1641 while ( pos<lines.length && lines[pos][0] != '}' ) 1642 { 1643 debug(unions)writefln("\tunion line %s", lines[pos]); 1644 string value = std..string.strip(lines[pos++]); 1645 debug(unions)writefln("\traw %s", value); 1646 value = stringToGtkD(value, convParms, wrapper.getAliases()); 1647 debug(unions)writefln("\tprocessed %s", value); 1648 values ~= value; 1649 } 1650 ++pos; 1651 if ( pos < lines.length ) 1652 { 1653 collectedUnions ~= "/**"; 1654 while ( pos < lines.length && lines[pos][0] > ' ' ) 1655 { 1656 collectedUnions ~= " * "~lines[pos++]; 1657 } 1658 collectedUnions ~= " */"; 1659 } 1660 collectedUnions ~= "public struct "~unionName; 1661 collectedUnions ~= "{"; 1662 collectedUnions ~= "union"; 1663 collectedUnions ~= "{"; 1664 foreach ( string value ; values ) 1665 { 1666 debug(unions)writefln("\t\t%s", value); 1667 collectedUnions ~= value; 1668 } 1669 collectedUnions ~= "}"; 1670 collectedUnions ~= "}"; 1671 } 1672 1673 private void collectStructs(string[] lines, ConvParms* convParms) 1674 { 1675 string structName = lines[0]; 1676 if ( startsWith(structName, "struct ") ) 1677 { 1678 structName = structName[7..structName.length]; 1679 } 1680 1681 debug(structs)writefln("found typdef struct = %s", structName); 1682 1683 bool includeStruct = true; 1684 int nStructs = 0; 1685 while ( includeStruct && nStructs < convParms.noStructs.length ) 1686 { 1687 includeStruct = ! (structName == convParms.noStructs[nStructs++]); 1688 } 1689 1690 if ( includeStruct ) 1691 { 1692 string[] structDef; /// all elements of the struct 1693 int pos = 1; 1694 if ( lines[1][lines[1].length-1] == '{' ) 1695 { 1696 ++pos; 1697 debug(structs)writefln("collectStructs %s",std..string.strip(lines[pos])); 1698 while ( pos < lines.length && lines[pos][0] != '}' ) 1699 { 1700 structDef ~= lines[pos]; 1701 ++pos; 1702 } 1703 } 1704 if ( pos < lines.length ) 1705 { 1706 collectedStructs ~= ""; 1707 string line = lines[pos]; 1708 ++pos; 1709 string gtkStruct = convParms.realStrct.length > 0 1710 ? convParms.realStrct 1711 : convParms.strct; 1712 1713 if ( pos < lines.length && lines[pos][0] > ' ' ) 1714 { 1715 collectedStructs ~= "/**"; 1716 if ( structName == gtkStruct ) 1717 { 1718 collectedStructs ~= " * Main Gtk struct."; 1719 } 1720 while ( pos < lines.length && lines[pos][0] > ' ' ) 1721 { 1722 collectedStructs ~= " * "~lines[pos++]; 1723 } 1724 collectedStructs ~= " */"; 1725 } 1726 else if ( structName == gtkStruct ) 1727 { 1728 collectedStructs ~= "/**"; 1729 collectedStructs ~= " * Main Gtk struct."; 1730 collectedStructs ~= " */"; 1731 } 1732 } 1733 1734 if ( structDef.length > 0 ) 1735 { 1736 collectedStructs ~= "public struct "~structName~"\n{"; 1737 getStructInternals(structDef, convParms); 1738 collectedStructs ~= "\n}"; 1739 } 1740 else 1741 { 1742 collectedStructs ~= "public struct "~structName~"{}"; 1743 } 1744 collectedStructs ~= ""; 1745 } 1746 } 1747 1748 void getStructInternals(string[] structDef, ConvParms* convParms) 1749 { 1750 string getFunctionPointer(string def, inout int i) 1751 { 1752 1753 string funct = std..string.split(def, ";")[0]; 1754 string comment = std..string.split(def, ";")[1]; 1755 1756 return getFunction(funct, convParms) ~ comment; 1757 } 1758 1759 bool bitField = false; // if we are in a bit field 1760 int bitFieldNr; // Number apended to bit field 1761 int bits; // Bits used in the curent bit field 1762 1763 for ( int i; i < structDef.length; i++ ) 1764 { 1765 // Remove GSEAL macro 1766 if ( std..string.indexOf(structDef[i], "GSEAL (") > -1 ) 1767 { 1768 structDef[i] = std.array.replace(structDef[i], "GSEAL (", ""); 1769 structDef[i] = std.array.replace(structDef[i], ")", ""); 1770 } 1771 1772 string elem = stringToGtkD(structDef[i], convParms, wrapper.getAliases()); 1773 1774 if ( startsWith(elem, "*") && std..string.indexOf(elem, "+/") < elem.length - 2) 1775 elem = std.array.replace(elem, "/", "\\"); //Some comments are broken 1776 1777 if ( std..string.indexOf(elem, "unsigned long") == 0) 1778 elem = "ulong"~ elem[13..$]; //TODO: posibly use fixtype 1779 1780 if ( std..string.indexOf(structDef[i], ":") >= 0 && (std..string.indexOf(structDef[i], ":") < std..string.indexOf(structDef[i], "/+*") || std..string.indexOf(structDef[i], "/+*") == -1) ) 1781 //Bit fields. 1782 { 1783 if ( !bitField ) 1784 { 1785 bitField = true; 1786 collectedStructs ~= "\tuint bitfield" ~ to!string(bitFieldNr) ~";"; 1787 } 1788 if (std..string.indexOf(elem, "/+*") > 0 && std..string.indexOf(elem, "+/") < 0) 1789 { 1790 string[] parts = std..string.split(elem, "/+*"); 1791 collectedStructs ~= "//" ~ parts[0]; 1792 collectedStructs ~= "/+*" ~ parts[1]; 1793 } 1794 else 1795 { 1796 collectedStructs ~= "//" ~ elem; 1797 } 1798 1799 auto b = split(elem, ":")[1]; 1800 b = b[0 .. b.indexOf(";")].strip; 1801 bits += to!int(b); 1802 if ( bits >= 32) 1803 { 1804 bitField = false; 1805 bitFieldNr++; 1806 bits = 0; 1807 } 1808 } 1809 else if ( std..string.indexOf(elem, "#") > -1 && std..string.indexOf(elem, "#") < 2 ) 1810 //Versions. 1811 { 1812 if ( std..string.indexOf(elem, "#if defined (G_OS_WIN32) GLIB_SIZEOF_VOID_P == 8") > -1 ) 1813 { 1814 //GLIB_SIZEOF_VOID_P == 8 means 64 bit. assuming WIN32 is an bad name for just windows. 1815 collectedStructs ~= "version(Win64)"; 1816 collectedStructs ~= "{"; 1817 } 1818 if ( std..string.indexOf(elem, "#if __SIZEOF_INT__ == __SIZEOF_POINTER__") > -1 || 1819 std..string.indexOf(elem, "#if (defined(__SIZEOF_INT__) defined(__SIZEOF_POINTER__)) (__SIZEOF_INT__ == __SIZEOF_POINTER__)") > -1 ) 1820 { 1821 collectedStructs ~= "static if (int.sizeof == ptrdiff_t.sizeof)"; 1822 collectedStructs ~= "{"; 1823 } 1824 if ( std..string.indexOf(elem, "#ifndef") == 0 ) 1825 { 1826 collectedStructs ~= "version("~ elem[8..$] ~")"; 1827 collectedStructs ~= "{"; 1828 } 1829 else if ( std..string.indexOf(elem, "#else") == 0 ) 1830 { 1831 collectedStructs ~= "}"; 1832 collectedStructs ~= "else"; 1833 collectedStructs ~= "{"; 1834 } 1835 else if ( std..string.indexOf(elem, "#endif") == 0 ) 1836 { 1837 collectedStructs ~= "}"; 1838 } 1839 } 1840 else if ( std..string.indexOf(elem, "(") > 0 && !startsWith(elem, "* ") && !startsWith(elem, "/+*") ) 1841 //Function Pointers. 1842 { 1843 string funct; 1844 for ( ; i < structDef.length; i++ ) 1845 { 1846 funct ~= stringToGtkD(structDef[i], convParms, wrapper.getAliases()); 1847 1848 if ( std..string.indexOf(structDef[i], ");") > 0 ) 1849 break; 1850 } 1851 1852 collectedStructs ~= getFunctionPointer(funct, i); 1853 } 1854 else if( std..string.indexOf(elem, "{") > 0 ) 1855 //Nested Structs and unions. 1856 { 1857 string structUnion = std..string.split(structDef[i])[0]; 1858 int parentCount; 1859 string[] def; 1860 1861 for ( i++; i < structDef.length; i++ ) 1862 { 1863 if ( std..string.indexOf(structDef[i], "{") > -1 ) 1864 parentCount++; 1865 1866 if ( std..string.indexOf(structDef[i], "}") > -1 && parentCount-- == 0) 1867 break; 1868 1869 def ~= stringToGtkD(structDef[i], convParms, wrapper.getAliases()); 1870 } 1871 1872 string varName = stringToGtkD(std..string.split(structDef[i])[1][0..$-1], convParms, wrapper.getAliases()); 1873 string structName = std..string.toUpper(varName)[0..1] ~ varName[1..$]; 1874 1875 collectedStructs ~= structUnion ~" "~ structName; 1876 collectedStructs ~= "{"; 1877 getStructInternals(def, convParms); 1878 collectedStructs ~= "}"; 1879 collectedStructs ~= structName ~" "~ varName ~";"; 1880 } 1881 else if ( std..string.indexOf(elem, "[") > 0 ) 1882 { 1883 string member; 1884 size_t space = std..string.indexOf(elem, " "); 1885 size_t startBracket = std..string.indexOf(elem, "["); 1886 size_t endBracket = std..string.indexOf(elem, "]"); 1887 1888 member = elem[0..space]; 1889 1890 if ( elem[space+1] == '*' ) 1891 member ~= "*"; 1892 1893 member ~= elem[startBracket..endBracket+1] ~ " "; 1894 1895 if ( elem[space+1] == '*' ) 1896 member ~= elem[space+2..startBracket]; 1897 else 1898 member ~= elem[space+1..startBracket]; 1899 1900 collectedStructs ~= member ~ elem[endBracket+1..$]; 1901 } 1902 else 1903 { 1904 collectedStructs ~= elem; 1905 } 1906 } 1907 } 1908 1909 /// hack... we don't have all types (do we?) 1910 bool isEnum(string type) 1911 { 1912 if ( type == "GdkEventType" ) 1913 { 1914 return true; 1915 } 1916 return false; 1917 } 1918 1919 bool primitiveType(string line) 1920 { 1921 int p=0; 1922 skipBlank(p, line); 1923 string type = untilBlank(p, line); 1924 if ( isEnum(type) ) 1925 { 1926 return true; 1927 } 1928 foreach(primitive; wrapper.getAliases()) 1929 { 1930 if(primitive == type) 1931 return true; 1932 } 1933 return (type in wrapper.getAliases()) !is null; 1934 } 1935 1936 public static void skipBlank(ref int p, string text) 1937 { 1938 while( p<text.length && text[p]<=' ' ) 1939 { 1940 ++p; 1941 } 1942 } 1943 1944 public static void skip(ref int p, string text, char s) 1945 { 1946 while( p<text.length && text[p]==s) 1947 { 1948 ++p; 1949 } 1950 } 1951 1952 public static string untilBlank(ref int p, string text) 1953 { 1954 int start=p; 1955 while ( p<text.length && text[p]>' ') 1956 { 1957 ++p; 1958 } 1959 return text[start..p]; 1960 } 1961 1962 public static string untilBlank(ref int p, string text, string s) 1963 { 1964 int start=p; 1965 while ( p<text.length && text[p]>' ' && std..string.indexOf(s,text[p])<0 ) 1966 { 1967 ++p; 1968 } 1969 return text[start..p]; 1970 } 1971 1972 public static string until(ref int p, string text, char s) 1973 { 1974 int start=p; 1975 while ( p<text.length && text[p]!=s) 1976 { 1977 ++p; 1978 } 1979 return text[start..p]; 1980 } 1981 1982 public static string until(ref int p, string text, string s) 1983 { 1984 int start=p; 1985 while ( p<text.length && std..string.indexOf(s,text[p])<0 ) 1986 { 1987 ++p; 1988 } 1989 return text[start..p]; 1990 } 1991 1992 private string getFunctionDeclaration(ref int line, string[] lines) 1993 { 1994 string funct; 1995 while ( line<lines.length 1996 && (!endsWith(lines[line], ");") 1997 && !startsWith(funct, "#define")) 1998 ) 1999 { 2000 funct ~= lines[line]~ " "; 2001 debug(endFunction)writefln("funct line = >>>%s<<< endWith(\");\") = ", 2002 lines[line], 2003 endsWith(lines[line], ");") 2004 ); 2005 ++line; 2006 } 2007 if ( line<lines.length && endsWith(lines[line], ");") ) 2008 { 2009 funct ~= lines[line++]; 2010 } 2011 2012 return funct; 2013 } 2014 2015 /** Builds the declaration of a new method for a class, according to 2016 * the information retrieved from the documentation. 2017 * Params: 2018 * lines = the lines containing the definition of the original GTK+ 2019 * function, extracted from the documentation. 2020 * prefixes = a list of prefixes to look for in 'lines' (gtk_xxx). 2021 */ 2022 private string[] getFunction(string[] lines, string[] prefixes) 2023 { 2024 string[] member; 2025 2026 int line = 1; 2027 2028 string funct = getFunctionDeclaration(line, lines); 2029 2030 Funct fun = Funct(funct, convParms, wrapper.getAliases()); 2031 2032 /** 2033 * Checks restrictions on the functions to include 2034 * Params: 2035 * lines = 2036 * prefix = 2037 * Returns: 2038 */ 2039 bool includeFunction(ConvParms* convParms) 2040 { 2041 bool inc = true; 2042 2043 int nPrefix = 0; 2044 while ( inc && nPrefix<convParms.noPrefixes.length ) 2045 { 2046 debug(noPrefixes)writefln("\ttest noPrefix %s ?= %s", fun.name, convParms.noPrefixes[nPrefix]); 2047 inc = !startsWith(fun.name, convParms.noPrefixes[nPrefix++]); 2048 } 2049 if ( inc ) 2050 { 2051 inc = false; 2052 2053 if ( convParms.containsPrefix(fun.name) ) 2054 { 2055 debug(noPrefixes)writefln("included by name"); 2056 inc = true; 2057 } 2058 else if ( convParms.strictPrefix && convParms.prefixes.length>0 ) 2059 { 2060 debug(noPrefixes) writefln("dropped by strictPrefix"); 2061 inc = false; 2062 } 2063 else 2064 { 2065 inc = true; 2066 debug(noPrefixes)if ( !inc) writefln("dropped by noPrefixes"); 2067 } 2068 } 2069 //debug(noPrefixes)writefln("%s : %s (%s)", (inc?"included":"dropped"),fun.name, convParms.prefix); 2070 return inc; 2071 } 2072 2073 if ( includeFunction(convParms) ) 2074 { 2075 if ( funct[0] == '#' ) 2076 { 2077 if ( !convParms.strictPrefix ) 2078 { 2079 collectedTypes ~= ""; 2080 debug(defines)writefln("it's define: %s",funct); 2081 // comment 2082 if ( wrapper.includeComments() ) 2083 { 2084 collectedTypes ~= "/*"; 2085 while ( line<lines.length ) 2086 { 2087 collectedTypes ~= " * "~lines[line++]; 2088 } 2089 collectedTypes ~= " */"; 2090 } 2091 collectedTypes ~= "// TODO"; 2092 // body 2093 collectedTypes ~= "// "~funct; 2094 } 2095 2096 } 2097 else 2098 { 2099 debug(functName) writefln("funct name = %s", fun.name); 2100 if ( fun.name.length==0 || fun.name[0] == '(' ) 2101 { 2102 if ( !convParms.isInterface ) 2103 { 2104 if ( !convParms.strictPrefix ) 2105 { 2106 collectedFuncts ~= ""; 2107 // comment 2108 if ( wrapper.includeComments() ) 2109 { 2110 collectedFuncts ~= "/*"; 2111 while ( line<lines.length ) 2112 { 2113 collectedFuncts ~= " * "~lines[line++]; 2114 } 2115 collectedFuncts ~= " */"; 2116 collectedFuncts ~= "// "~funct; 2117 } 2118 // body 2119 string decl = getFunction(funct, convParms); 2120 2121 if ( decl.length > 0 ) 2122 collectedFuncts ~= "public alias "~ decl; 2123 } 2124 } 2125 } 2126 else // the regular function 2127 { 2128 bool tooSoon = false; // reject for 2.10 2129 // comment 2130 void addComments() 2131 { 2132 string[] phraseParams(string[] comments) 2133 { 2134 string[] description; 2135 string[] params; 2136 string ret; 2137 2138 for(int i; i < comments.length; i++) 2139 { 2140 if(indexOf(comments[i], ":") == comments[i].length-1 && comments[i].chomp(":").strip() != "Returns" ) 2141 { 2142 //Get the GtkD name of the param 2143 string param = strip( idsToGtkD(comments[i][0 .. $-1], convParms, wrapper.getAliases()) ); 2144 2145 //If this param is not in the Gtkd Function Skip it. 2146 if(indexOf(fun.declaration(), param) == -1) 2147 { 2148 //Loop for multi line descriptons for this param. 2149 while(i+1 < comments.length && stilInParam(comments[i+1])) 2150 i++; 2151 continue; 2152 } 2153 2154 if(params.length == 0) 2155 params ~= "Params:"; 2156 2157 //Loop for multi line descriptons for this param. 2158 bool firstRun = true; 2159 while(i+1 < comments.length && stilInParam(comments[i+1])) 2160 { 2161 i++; 2162 if(firstRun) 2163 { 2164 params ~= param ~" = "~ stripLeft(comments[i]); 2165 firstRun = false; 2166 } 2167 else 2168 params ~= comments[i]; 2169 } 2170 } 2171 else if( comments[i].chomp(":").strip() == "Returns" ) 2172 { 2173 //Skip return for Constructors. 2174 if(indexOf(fun.declaration(), "this (") > -1) 2175 { 2176 //Loop for multi line descriptons for this return. 2177 while(i+1 < comments.length && stilInParam(comments[i+1])) 2178 i++; 2179 continue; 2180 } 2181 2182 ret ~= "Returns:"; 2183 2184 //Loop for multi line descriptons for this return. 2185 bool firstRun = true; 2186 while(i+1 < comments.length && stilInParam(comments[i+1])) 2187 { 2188 i++; 2189 ret ~= " " ~ comments[i].strip(); 2190 } 2191 } 2192 else if(indexOf(comments[i], "See Also") == 0 || indexOf(comments[i], "Property Details") == 0) 2193 { 2194 //These sections get included with the last function. 2195 break; 2196 } 2197 else 2198 { 2199 //Add the rest to the description. 2200 description ~= comments[i]; 2201 } 2202 } 2203 2204 if(params.length > 0) 2205 { 2206 foreach(string line; params) 2207 description ~= line; 2208 } 2209 2210 if(ret.length > 0) 2211 description ~= ret; 2212 2213 if ( indexOf(fun.getExternal(), "GError**") > -1 2214 && indexOf(fun.declaration(), "Error") == -1 ) 2215 { 2216 description ~= "Throws: GException on failure."; 2217 } 2218 2219 if ( indexOf(fun.declaration(), "this (") > -1 ) 2220 { 2221 description ~= "Throws: ConstructionException GTK+ fails to create the object."; 2222 } 2223 2224 return description; 2225 } 2226 2227 if ( wrapper.includeComments() ) 2228 { 2229 string[] comments; 2230 while ( line<lines.length ) 2231 { 2232 //if ( !tooSoon ) 2233 //{ 2234 // tooSoon = lines[line]=="Since 2.10"; 2235 //} 2236 comments ~= lines[line++]; 2237 } 2238 2239 member ~= "/**"; 2240 2241 comments = phraseParams(comments); 2242 foreach(string line; comments) 2243 member ~= " * "~ line; 2244 2245 member ~= " */"; 2246 } 2247 } 2248 2249 if ( tooSoon ) 2250 { 2251 addComments(); 2252 member ~= "// next release"; 2253 } 2254 else 2255 { 2256 if ( !convParms.isInterface ) 2257 { 2258 string externalDeclaration = fun.getExternal(); 2259 2260 /* Don't add repeated declarations. */ 2261 bool addme = true; 2262 2263 foreach(ref string declaration; externalDeclarations) 2264 { 2265 if(externalDeclaration == declaration){ addme = false; break; } 2266 } 2267 2268 if(addme) externalDeclarations ~= externalDeclaration; 2269 } 2270 // body 2271 if ( !convParms.omitCode(fun.name) && indexOf(fun.declaration(), "...") < 0 ) 2272 { 2273 string gtkDDeclaration = fun.declaration(); 2274 //string gtkDDeclaration = stringToGtkD(rawDeclaration,convParms,wrapper.getAliases()); 2275 debug(declaration) writefln("Declaration\n\t%s\n\t%s",rawDeclaration, gtkDDeclaration); 2276 addComments(); 2277 member ~= gtkDDeclaration~iFaceChar; 2278 if ( !convParms.isInterface ) 2279 { 2280 member ~= "{"; 2281 member ~= "// "~funct; 2282 member ~= fun.bod(); 2283 member ~= "}"; 2284 } 2285 /* Duplicated functions are omitted. */ 2286 if(checkIfDupFunction(fun)) member.length = 0; 2287 checkIfGtkStructs(fun); 2288 } 2289 } 2290 } 2291 } 2292 } 2293 2294 return member; 2295 } 2296 2297 private bool checkIfDupFunction(Funct fun) 2298 { 2299 string signature = fun.convName~'('~fun.getWrapParametersType()~')'; 2300 if ( signature in functionSignatures ) 2301 { 2302 writefln("######################## duplicated function %s", signature); 2303 return true; 2304 } 2305 else 2306 { 2307 functionSignatures[signature] = 1; 2308 return false; 2309 } 2310 } 2311 2312 /* 2313 * Checks if the current line is still part of the param description. 2314 * it does this by checking for things not normaly in the param description 2315 * Params: 2316 * comments = Line to check. 2317 * Returns: true if we are still in the description of the param. 2318 */ 2319 bool stilInParam(string comments) 2320 { 2321 return !(indexOf(comments, ":") == comments.length-1 || 2322 comments.chomp(":").strip() == "Returns" || 2323 ( indexOf(comments, "Since 2.") == 0 || indexOf(comments, "Since 1.") == 0) || 2324 indexOf(comments, "See Also") == 0 || 2325 indexOf(comments, "Property Details") == 0 || 2326 comments == "<hr>"); 2327 } 2328 2329 /** 2330 * Prints out the potential Gtk struct to be wrapped 2331 * so that the wrap parameter can be set on the APILookupXXX.txt 2332 * TODO assume all structs are to be wrapped an explicitly declare the ones not to be wrapped 2333 * Params: 2334 * fun = 2335 */ 2336 private void checkIfGtkStructs(Funct fun) 2337 { 2338 bool found = false; 2339 void check(string type) 2340 { 2341 if ( startsWith(type, 'G') 2342 && endsWith(type, '*') 2343 ) 2344 { 2345 if ( type in gtkStructs ) 2346 { 2347 // nothing 2348 } 2349 else 2350 { 2351 found = true; 2352 gtkStructs[type] = 1; 2353 //writefln("######################## Gtk struct found %s\t\t%s", 2354 // type, 2355 // fun.convName~"("~fun.getWrapParametersType()~")" 2356 // ); 2357 2358 string strct = type; 2359 string dName = ""; 2360 string pack = ""; 2361 if ( startsWith(strct, "Gtk") ) 2362 { 2363 pack = "gtk"; 2364 dName = strct[3..strct.length-1]; 2365 //dName[0] = std.ascii.toLower(dName[0]); 2366 } 2367 else if ( startsWith(strct, "Gdk") ) 2368 { 2369 pack = "gdk"; 2370 dName = strct[3..strct.length-1]; 2371 //dName[0] = std.ascii.toLower(dName[0]); 2372 if ( dName == "Pixbuf") pack = "gdkpixbuf"; 2373 } 2374 else if ( startsWith(strct, "Gst") ) 2375 { 2376 pack = "gstreamer"; 2377 dName = strct[3..strct.length-1]; 2378 //dName[0] = std.ascii.toLower(dName[0]); 2379 } 2380 else if ( startsWith(strct, "G") ) 2381 { 2382 dName = strct[1..strct.length-1]; 2383 switch ( dName ) 2384 { 2385 case "Object": 2386 2387 if ( pack == "g" ) 2388 { 2389 pack = "gobject"; dName = "ObjectG"; 2390 } 2391 else if ( pack == "gdk" ) 2392 { 2393 dName = "ObjectG"; 2394 } 2395 else if ( pack == "gtk" ) 2396 { 2397 dName = "ObjectGtk"; 2398 } 2399 else if ( pack == "gstreamer" ) 2400 { 2401 dName = "ObjectGst"; 2402 } 2403 else if ( pack == "atk" ) 2404 { 2405 dName = "ObjectAtk"; 2406 } 2407 break; 2408 case "Closure": pack = "gobject"; break; 2409 case "Type": pack = "gobject"; break; 2410 case "Value": pack = "gobject"; break; 2411 case "List": pack = "glib"; dName = "ListG"; break; 2412 case "SList": pack = "glib"; dName = "ListSG"; break; 2413 case "String": pack = "glib"; dName = "StringG"; break; 2414 case "IOChannel": pack = "glib"; break; 2415 case "Quark": pack = "glib"; break; 2416 case "ParmSpec": pack = "gobject"; break; 2417 case "TypeModule": pack = "gobject"; break; 2418 case "Flags": pack = "gobject"; break; 2419 case "Enums": pack = "gobject"; break; 2420 default: 2421 pack = "g"; 2422 break; 2423 } 2424 } 2425 debug(structs)writefln("import: %s.%s", pack, dName); 2426 debug(structs)writefln("structWrap: %s %s", strct, dName); 2427 } 2428 } 2429 } 2430 2431 if ( !fun.ctor 2432 && !endsWith(fun.convName, "Struct") 2433 ) 2434 { 2435 check(fun.typeWrap); 2436 } 2437 foreach ( count , param ; fun.params ) 2438 { 2439 if ( count > 0 || param.typeWrap != convParms.strct~'*' ) 2440 { 2441 check(param.typeWrap); 2442 } 2443 } 2444 } 2445 2446 /** 2447 * Params: 2448 * line = The API line of the function 2449 * convParms = the Conversion parameters 2450 * Returns: 2451 */ 2452 private string getFunction(string line, ConvParms* convParms) 2453 { 2454 debug(functionType) writefln("\ngetFunction line = %s", line); 2455 // void (*GChildWatchFunc) (GPid pid, gint status, gpointer data); 2456 // public typedef extern(C) void function(int, int, void*) GChildWatchFunc; 2457 2458 2459 2460 string f = "extern(C) "; 2461 int pos = 0; 2462 string type = until(pos, line, "("); 2463 until(pos, line, "*"); 2464 skip(pos, line, '*'); 2465 string name = until(pos, line, ")"); 2466 if (convParms.omitCode(name)) { 2467 return ""; 2468 } 2469 2470 f ~= stringToGtkD(type, convParms, wrapper.getAliases()).strip(); 2471 f ~= " function("; 2472 2473 until(pos, line, "("); 2474 skip(pos, line, '('); 2475 skipBlank(pos, line); 2476 2477 string sourceParms = std..string.strip(until(pos, line, ")")); 2478 string parms; 2479 2480 if ( sourceParms != "void" ) 2481 { 2482 int sPos = 0; 2483 int count = 0; 2484 debug(functionType) writefln("sourceParms = %s", sourceParms); 2485 while ( sPos < sourceParms.length ) 2486 { 2487 skipBlank(sPos, sourceParms); 2488 debug(functionType)writefln("parms sPos=%s [%s]",sPos, sourceParms[sPos..sourceParms.length]); 2489 if (count++ > 0 ) 2490 { 2491 parms ~= ", "; 2492 } 2493 string pType = untilBlank(sPos, sourceParms); 2494 fixType(pType, sPos, sourceParms); 2495 2496 string pName = until(sPos, sourceParms, ",)"); 2497 2498 debug(parmType)writefln("\tParameter type before = %s", pType); 2499 debug(parmName)writefln("\tParameter name before = %s", pName); 2500 adjustTypeName(pType, pName); 2501 debug(parmType)writefln("\tParameter type after = %s", pType); 2502 debug(parmName)writefln("\tParameter name after = %s", pName); 2503 2504 parms ~= tokenToGtkD(pType, convParms, wrapper.getAliases()) ~" "~ idsToGtkD(pName, convParms, wrapper.getAliases()); 2505 ++sPos; 2506 } 2507 } 2508 2509 if ( name == "ref" ) 2510 name = "doref"; 2511 2512 f ~= parms ~ ") " ~ name ~ ";"; 2513 2514 return f; 2515 } 2516 2517 /** 2518 * Wraps a set of lines in the block documentation comment 2519 * Returns: The comment formated for D block documentation comment 2520 */ 2521 private string[] getDescription() 2522 { 2523 string[] desc; 2524 desc ~= ""; 2525 desc ~= tabs ~ "/**"; 2526 string[] block = getBlock ("Description", "Details"); 2527 foreach ( string line; block ) 2528 { 2529 if( startsWith(line, "--") && endsWith(line, "--") ) 2530 line = std.array.replace(line, "-", "_"); 2531 2532 desc ~= " * " ~ line; 2533 } 2534 desc ~= tabs ~ " */"; 2535 2536 return desc; 2537 2538 } 2539 2540 /** 2541 * Finds a block of lines delimited by the marker lines from the start of the text 2542 * Params: 2543 * startLine = The Start marker line 2544 * endLine = The end marker line 2545 * Returns: The block os lines 2546 */ 2547 private string[] getBlock(string startLine, string endLine) 2548 { 2549 currLine = 0; 2550 2551 debug(getBlock) writefln("getBlock for ]%s,%s[", startLine, endLine); 2552 2553 // TODO use slicing instead of this array 2554 string[] block; 2555 2556 while ( currLine<inLines.length && inLines[currLine]!=startLine ) 2557 { 2558 debug(getBlock) writefln("-\t\t[%s]%s",currLine,inLines[currLine]); 2559 ++currLine; 2560 } 2561 2562 return getUntil(endLine); 2563 } 2564 2565 private int moveToBlockStart(string startLine, string[] inLines) 2566 { 2567 int startPos = 0; 2568 while ( startPos < inLines.length && inLines[startPos]!= startLine ) 2569 { 2570 ++startPos; 2571 } 2572 return startPos; 2573 } 2574 2575 /** 2576 * Gets all the non empty lines until a marker line 2577 * Params: 2578 * endLine = the marker line 2579 * Returns: 2580 */ 2581 private string[] getUntil(string endLine) 2582 { 2583 bool end = false; 2584 2585 string[] block; 2586 2587 while ( currLine < inLines.length && !end ) 2588 { 2589 if ( inLines[currLine] == endLine ) 2590 { 2591 end = true; 2592 debug(getUntil) writefln("getBlock end at line %s",currLine,"\n"); 2593 } 2594 else 2595 { 2596 if ( std..string.strip(inLines[currLine]).length > 0 ) 2597 { 2598 block ~= inLines[currLine]; 2599 } 2600 debug(getUntil) writefln("+[%s]%s",currLine,inLines[currLine]); 2601 } 2602 ++currLine; 2603 } 2604 return block; 2605 } 2606 2607 /** 2608 * Gets all the non empty lines until a marker line 2609 * Params: 2610 * endLine = the marker line 2611 * Returns: 2612 */ 2613 private string[] getUntil(string endLine, string[] lines) 2614 { 2615 bool end = false; 2616 int currLine; 2617 2618 string[] block; 2619 2620 while ( currLine < lines.length && !end ) 2621 { 2622 if ( lines[currLine] == endLine ) 2623 { 2624 end = true; 2625 debug(getUntil) writefln("getBlock end at line %s",currLine,"\n"); 2626 } 2627 else 2628 { 2629 if ( std..string.strip(lines[currLine]).length > 0 ) 2630 { 2631 block ~= lines[currLine]; 2632 } 2633 debug(getUntil) writefln("+[%s]%s",currLine,lines[currLine]); 2634 } 2635 ++currLine; 2636 } 2637 return block; 2638 } 2639 2640 /** 2641 * Converts a GTK strin to a GtkD string. 2642 * This removes the "_" and capitalises the next letter and converts the basic types 2643 * Params: 2644 * gString = 2645 * Returns: 2646 */ 2647 public static string stringToGtkD(string gString, ConvParms* convParms, string[string] aliases, bool caseConvert=true) 2648 { 2649 string converted; 2650 2651 int pos = 0 ; 2652 string seps = " \n\r\t\f\v()[]*,;"; 2653 2654 char c = ' '; 2655 char pc; 2656 int start = 0; 2657 int end = 0; 2658 while ( pos < gString.length ) 2659 { 2660 pc = c; 2661 c = gString[pos]; 2662 if ( std..string.indexOf(seps,c) >= 0 ) 2663 { 2664 end = pos; 2665 converted ~= tokenToGtkD(gString[start..end], convParms, aliases, caseConvert); 2666 if ( c=='*' ) 2667 { 2668 //if ( pc==' ' ) 2669 //{ 2670 // converted.length = converted.length-1; 2671 //} 2672 //converted ~= "[] "; 2673 converted ~= c; 2674 2675 } 2676 else if ( c<=' ' ) 2677 { 2678 if ( converted.length >0 && converted[converted.length-1] != ' ' ) 2679 { 2680 converted ~= ' '; 2681 } 2682 c = ' '; 2683 } 2684 else 2685 { 2686 converted ~= c; 2687 } 2688 start = pos+1; 2689 } 2690 ++pos; 2691 } 2692 if ( pos > start ) 2693 { 2694 converted ~= tokenToGtkD(gString[start..pos], convParms, aliases, caseConvert); 2695 } 2696 return converted; 2697 } 2698 2699 2700 public static string idsToGtkD(string gToken, ConvParms* convParms, string[string] aliases, bool caseConvert=true) 2701 { 2702 string converted = tokenToGtkD(gToken, convParms, aliases, caseConvert); 2703 switch ( converted ) 2704 { 2705 case "alias" : converted = "alia"; break; 2706 case "class" : converted = "clss"; break; 2707 case "interface" : converted = "intrface"; break; 2708 case "debug" : converted = "dbug"; break; 2709 case "version" : converted = "vrsion"; break; 2710 case "out" : converted = "f_out"; break; 2711 case "in" : converted = "f_in"; break; 2712 case "inout" : converted = "f_inout"; break; 2713 //case "ref" : converted = "doref"; break; // TODO why wasn't this converted from the alias on APILookup.txt 2714 default: 2715 // done 2716 break; 2717 } 2718 return converted; 2719 } 2720 2721 /** 2722 * Convert for normal GtkD conversion and after verifies if is necessary to use a enumType for references enum values 2723 * Params: 2724 * enumType = 2725 * gToken = 2726 * convParms = 2727 * aliases = 2728 * caseConvert = 2729 * Returns: 2730 */ 2731 public static string enumToGtkD(string enumType, string gToken, ConvParms* convParms, WrapperIF wrapper, bool caseConvert=true) 2732 { 2733 debug(enumToGtkD)writefln("enumLine (%s) BEFORE %s", enumType, gToken); 2734 string converted = stringToGtkD(gToken, convParms, wrapper.getAliases()); 2735 2736 sizediff_t pos = std..string.indexOf(converted, '='); 2737 debug(enumToGtkD)writefln("\t pos = %s", pos); 2738 if ( pos > 0 ) 2739 { 2740 string refValue = std..string.strip(converted[pos+1..converted.length]); 2741 converted = converted[0..pos+1]~ " "; 2742 2743 debug(enumToGtkD)writefln("\t refValue = %s", refValue); 2744 bool needComa = false; 2745 if ( endsWith(refValue, ',') ) 2746 { 2747 refValue = std..string.strip(refValue[0..refValue.length-1]); 2748 needComa = true; 2749 } 2750 2751 debug(enumToGtkD)writefln("\t refValue = %s", refValue); 2752 2753 debug(enumToGtkD) 2754 { 2755 foreach(string key ; wrapper.getEnumTypes().keys) 2756 { 2757 writefln("\t\t [%s] = %s", key, wrapper.getEnumTypes()[key]); 2758 } 2759 } 2760 2761 if ( std..string.indexOf(refValue, ' ') > 0 && std..string.indexOf(refValue, '<') > 0 ) 2762 { 2763 string[] parts = std..string.split(refValue); 2764 2765 foreach ( part; parts ) 2766 { 2767 if ( startsWith(part, "(") ) 2768 { 2769 converted ~= "("; 2770 part = part[1 .. $]; 2771 } 2772 2773 if ( part in wrapper.getEnumTypes() ) 2774 { 2775 part = wrapper.getEnumTypes()[part] ~" "; 2776 } 2777 else if ( std..string.indexOf(part, "<<") > 0 ) 2778 { 2779 string[] values = std..string.split(part, "<<"); 2780 2781 if ( values[0] in wrapper.getEnumTypes() ) 2782 values[0] = wrapper.getEnumTypes()[values[0]]; 2783 if ( values[1] in wrapper.getEnumTypes() ) 2784 values[1] = wrapper.getEnumTypes()[values[1]]; 2785 2786 part = values[0] ~" << "~ values[1] ~ " "; 2787 } 2788 2789 converted ~= part ~" "; 2790 } 2791 } 2792 else if ( refValue in wrapper.getEnumTypes() ) 2793 { 2794 converted ~= wrapper.getEnumTypes()[refValue]; 2795 } 2796 else 2797 { 2798 converted ~= refValue; 2799 } 2800 2801 converted = std..string.stripRight(converted); 2802 2803 if (needComa) 2804 converted ~= ","; 2805 } 2806 debug(enumToGtkD)writefln("enumLine (%s) AFTER %s", enumType, converted); 2807 2808 return converted; 2809 } 2810 2811 /** 2812 * Converts a GTK token to a Dui token 2813 * This removes the "_" and capitalises the next letter and converts the basic types. 2814 * Doesn't do it if it's cairo name 2815 * Params: 2816 * gToken = 2817 * Returns: 2818 */ 2819 public static string tokenToGtkD(string gToken, ConvParms* convParms, string[string] aliases, bool caseConvert=true) 2820 { 2821 string converted; 2822 2823 debug(tokenToGtkD) writefln("gToken=>>>%s<<<", gToken); 2824 2825 if ( (aliases !is null) && (gToken in aliases) ) 2826 { 2827 converted = aliases[gToken]; 2828 } 2829 else if ( (convParms.aliases !is null) && (gToken in convParms.aliases) ) 2830 { 2831 converted = convParms.aliases[gToken]; 2832 } 2833 else if ( endsWith(gToken, "_t") && startsWith(gToken,"cairo_") ) 2834 { 2835 converted = gToken; 2836 } 2837 else if ( endsWith(gToken, "_t*") && startsWith(gToken,"cairo_") ) 2838 { 2839 converted = gToken; 2840 } 2841 else if ( endsWith(gToken, "_t**") && startsWith(gToken,"cairo_") ) 2842 { 2843 converted = gToken; 2844 } 2845 else if ( startsWith(gToken,"f_") && (endsWith(gToken,"_out") || endsWith(gToken,"_in") || endsWith(gToken,"_inout") ) ) 2846 { 2847 converted = gToken; 2848 } 2849 else if ( caseConvert ) 2850 { 2851 converted = gToken.removePrefix(convParms).removeUnderscore(); 2852 // do it again after the gToken is converted 2853 if ( (aliases !is null) && (converted in aliases) ) 2854 { 2855 converted = aliases[converted]; 2856 } 2857 } 2858 else 2859 { 2860 converted = gToken; 2861 } 2862 2863 debug(tokenToGtkD) writefln("converted=>>>%s<<<\n", converted); 2864 2865 return converted; 2866 } 2867 2868 2869 2870 /** 2871 * Moves '*' and 'const' and trailing '[]' from the name to the type token 2872 * Params: 2873 * type = 2874 * name = 2875 */ 2876 public static void adjustTypeName(ref string type, ref string name) 2877 { 2878 debug(type)writefln("type before %s", type); 2879 debug(name)writefln("name before %s", name); 2880 name = std..string.strip(name); 2881 while ( name.length > 0 2882 && (GtkDClass.startsWith(name,"const") || name[0] == '*' 2883 || GtkDClass.startsWith(name,"G_GNUC_MAY_ALIAS") ) 2884 ) 2885 { 2886 if ( name[0] == '*' ) 2887 { 2888 type = type ~ '*'; 2889 name = std..string.strip(name[1..name.length]); 2890 } 2891 else if (GtkDClass.startsWith(name,"const")) 2892 { 2893 name = std..string.strip(name[5..name.length]); 2894 } 2895 else 2896 { 2897 name = std..string.strip(name[16..name.length]); 2898 } 2899 name = std..string.strip(name); 2900 } 2901 while ( GtkDClass.endsWith(name, "[]") ) 2902 { 2903 type ~= "*"; 2904 name = std..string.strip(name[0..name.length-2]); 2905 } 2906 debug(type)writefln("type after %s", type); 2907 debug(name)writefln("name after %s", name); 2908 } 2909 2910 /** 2911 * Consumes "const" and "unsigned" adding "u" to the type when "unsigned" is found 2912 * (? uchar will become just char) 2913 * Params: 2914 * type = 2915 * p = 2916 * text = 2917 */ 2918 public static void fixType(ref string type, ref int p, ref string text) 2919 { 2920 if ( type == "const" || type == "struct" ) 2921 { 2922 GtkDClass.skipBlank(p, text); 2923 type = untilBlank(p, text); 2924 } 2925 if ( type == "unsigned" ) 2926 { 2927 GtkDClass.skipBlank(p, text); 2928 type = "u" ~ untilBlank(p, text); 2929 } 2930 if ( startsWith(type, "_") ) 2931 { 2932 type = type[1..$]; 2933 } 2934 // if ( type == "uchar" ) 2935 // { 2936 // type = "char"; 2937 // } 2938 } 2939 2940 2941 2942 2943 public static bool startsWith(string str, string prefix) 2944 { 2945 return str.length >= prefix.length 2946 && str[0..prefix.length] == prefix; 2947 } 2948 2949 public static bool startsWith(string str, char prefix) 2950 { 2951 return str.length > 0 2952 && str[0] == prefix; 2953 } 2954 2955 public static bool endsWith(string str, string suffix) 2956 { 2957 return str.length >= suffix.length 2958 && str[str.length-suffix.length..str.length] == suffix; 2959 } 2960 2961 public static bool endsWith(string str, char suffix) 2962 { 2963 return str.length >= 1 2964 && str[str.length-1] == suffix; 2965 } 2966 2967 } 2968 2969 string removePrefix(string gToken, string prefix) 2970 { 2971 if ( startsWith(gToken, prefix) ) 2972 { 2973 return gToken[prefix.length..gToken.length]; 2974 } 2975 return gToken; 2976 } 2977 2978 string removePrefix(string gToken, ConvParms* convParms) 2979 { 2980 //debug(tokenToGtkD) writefln("gToken.length > prefix.length %s",gToken.length > convParms.prefix.length); 2981 string prefix = convParms.getPrefix(gToken); 2982 if ( prefix.length > 0 ) 2983 { 2984 return gToken[prefix.length..gToken.length]; 2985 } 2986 2987 return gToken; 2988 2989 } 2990 2991 string removeUnderscore(string gToken) 2992 { 2993 string converted; 2994 2995 char c = ' '; 2996 char pc = ' '; 2997 char ppc = ' '; 2998 int pos = 0; 2999 while ( pos < gToken.length ) 3000 { 3001 c = gToken[pos]; 3002 if ( pc == '_' ) 3003 { 3004 c = to!char(toUpper(c)); 3005 } 3006 else if ( c == '_' && isLower(pc) ) 3007 { 3008 pc = c; 3009 c = '\0'; 3010 } 3011 3012 if ( c > '\0' ) 3013 { 3014 if ( ppc == '_' 3015 && pc == 'g' 3016 && c == 'l' 3017 && gToken.length-1 > pos 3018 && gToken[pos+1] == '_' 3019 ) 3020 { 3021 c = 'L'; 3022 } 3023 ppc = pc; 3024 pc = gToken[pos]; 3025 converted ~= c; 3026 } 3027 ++pos; 3028 } 3029 return converted; 3030 } 3031