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