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 1881 { 1882 collectedStructs ~= elem; 1883 } 1884 } 1885 } 1886 1887 /// hack... we don't have all types (do we?) 1888 bool isEnum(string type) 1889 { 1890 if ( type == "GdkEventType" ) 1891 { 1892 return true; 1893 } 1894 return false; 1895 } 1896 1897 bool primitiveType(string line) 1898 { 1899 int p=0; 1900 skipBlank(p, line); 1901 string type = untilBlank(p, line); 1902 if ( isEnum(type) ) 1903 { 1904 return true; 1905 } 1906 foreach(primitive; wrapper.getAliases()) 1907 { 1908 if(primitive == type) 1909 return true; 1910 } 1911 return (type in wrapper.getAliases()) !is null; 1912 } 1913 1914 public static void skipBlank(ref int p, string text) 1915 { 1916 while( p<text.length && text[p]<=' ' ) 1917 { 1918 ++p; 1919 } 1920 } 1921 1922 public static void skip(ref int p, string text, char s) 1923 { 1924 while( p<text.length && text[p]==s) 1925 { 1926 ++p; 1927 } 1928 } 1929 1930 public static string untilBlank(ref int p, string text) 1931 { 1932 int start=p; 1933 while ( p<text.length && text[p]>' ') 1934 { 1935 ++p; 1936 } 1937 return text[start..p]; 1938 } 1939 1940 public static string untilBlank(ref int p, string text, string s) 1941 { 1942 int start=p; 1943 while ( p<text.length && text[p]>' ' && std..string.indexOf(s,text[p])<0 ) 1944 { 1945 ++p; 1946 } 1947 return text[start..p]; 1948 } 1949 1950 public static string until(ref int p, string text, char s) 1951 { 1952 int start=p; 1953 while ( p<text.length && text[p]!=s) 1954 { 1955 ++p; 1956 } 1957 return text[start..p]; 1958 } 1959 1960 public static string until(ref int p, string text, string s) 1961 { 1962 int start=p; 1963 while ( p<text.length && std..string.indexOf(s,text[p])<0 ) 1964 { 1965 ++p; 1966 } 1967 return text[start..p]; 1968 } 1969 1970 private string getFunctionDeclaration(ref int line, string[] lines) 1971 { 1972 string funct; 1973 while ( line<lines.length 1974 && (!endsWith(lines[line], ");") 1975 && !startsWith(funct, "#define")) 1976 ) 1977 { 1978 funct ~= lines[line]~ " "; 1979 debug(endFunction)writefln("funct line = >>>%s<<< endWith(\");\") = ", 1980 lines[line], 1981 endsWith(lines[line], ");") 1982 ); 1983 ++line; 1984 } 1985 if ( line<lines.length && endsWith(lines[line], ");") ) 1986 { 1987 funct ~= lines[line++]; 1988 } 1989 1990 return funct; 1991 } 1992 1993 /** Builds the declaration of a new method for a class, according to 1994 * the information retrieved from the documentation. 1995 * Params: 1996 * lines = the lines containing the definition of the original GTK+ 1997 * function, extracted from the documentation. 1998 * prefixes = a list of prefixes to look for in 'lines' (gtk_xxx). 1999 */ 2000 private string[] getFunction(string[] lines, string[] prefixes) 2001 { 2002 string[] member; 2003 2004 int line = 1; 2005 2006 string funct = getFunctionDeclaration(line, lines); 2007 2008 Funct fun = Funct(funct, convParms, wrapper.getAliases()); 2009 2010 /** 2011 * Checks restrictions on the functions to include 2012 * Params: 2013 * lines = 2014 * prefix = 2015 * Returns: 2016 */ 2017 bool includeFunction(ConvParms* convParms) 2018 { 2019 bool inc = true; 2020 2021 int nPrefix = 0; 2022 while ( inc && nPrefix<convParms.noPrefixes.length ) 2023 { 2024 debug(noPrefixes)writefln("\ttest noPrefix %s ?= %s", fun.name, convParms.noPrefixes[nPrefix]); 2025 inc = !startsWith(fun.name, convParms.noPrefixes[nPrefix++]); 2026 } 2027 if ( inc ) 2028 { 2029 inc = false; 2030 2031 if ( convParms.containsPrefix(fun.name) ) 2032 { 2033 debug(noPrefixes)writefln("included by name"); 2034 inc = true; 2035 } 2036 else if ( convParms.strictPrefix && convParms.prefixes.length>0 ) 2037 { 2038 debug(noPrefixes) writefln("dropped by strictPrefix"); 2039 inc = false; 2040 } 2041 else 2042 { 2043 inc = true; 2044 debug(noPrefixes)if ( !inc) writefln("dropped by noPrefixes"); 2045 } 2046 } 2047 //debug(noPrefixes)writefln("%s : %s (%s)", (inc?"included":"dropped"),fun.name, convParms.prefix); 2048 return inc; 2049 } 2050 2051 if ( includeFunction(convParms) ) 2052 { 2053 if ( funct[0] == '#' ) 2054 { 2055 if ( !convParms.strictPrefix ) 2056 { 2057 collectedTypes ~= ""; 2058 debug(defines)writefln("it's define: %s",funct); 2059 // comment 2060 if ( wrapper.includeComments() ) 2061 { 2062 collectedTypes ~= "/*"; 2063 while ( line<lines.length ) 2064 { 2065 collectedTypes ~= " * "~lines[line++]; 2066 } 2067 collectedTypes ~= " */"; 2068 } 2069 collectedTypes ~= "// TODO"; 2070 // body 2071 collectedTypes ~= "// "~funct; 2072 } 2073 2074 } 2075 else 2076 { 2077 debug(functName) writefln("funct name = %s", fun.name); 2078 if ( fun.name.length==0 || fun.name[0] == '(' ) 2079 { 2080 if ( !convParms.isInterface ) 2081 { 2082 if ( !convParms.strictPrefix ) 2083 { 2084 collectedFuncts ~= ""; 2085 // comment 2086 if ( wrapper.includeComments() ) 2087 { 2088 collectedFuncts ~= "/*"; 2089 while ( line<lines.length ) 2090 { 2091 collectedFuncts ~= " * "~lines[line++]; 2092 } 2093 collectedFuncts ~= " */"; 2094 collectedFuncts ~= "// "~funct; 2095 } 2096 // body 2097 string decl = getFunction(funct, convParms); 2098 2099 if ( decl.length > 0 ) 2100 collectedFuncts ~= "public alias "~ decl; 2101 } 2102 } 2103 } 2104 else // the regular function 2105 { 2106 bool tooSoon = false; // reject for 2.10 2107 // comment 2108 void addComments() 2109 { 2110 string[] phraseParams(string[] comments) 2111 { 2112 string[] description; 2113 string[] params; 2114 string ret; 2115 2116 for(int i; i < comments.length; i++) 2117 { 2118 if(indexOf(comments[i], ":") == comments[i].length-1 && comments[i].chomp(":").strip() != "Returns" ) 2119 { 2120 //Get the GtkD name of the param 2121 string param = strip( idsToGtkD(comments[i][0 .. $-1], convParms, wrapper.getAliases()) ); 2122 2123 //If this param is not in the Gtkd Function Skip it. 2124 if(indexOf(fun.declaration(), param) == -1) 2125 { 2126 //Loop for multi line descriptons for this param. 2127 while(i+1 < comments.length && stilInParam(comments[i+1])) 2128 i++; 2129 continue; 2130 } 2131 2132 if(params.length == 0) 2133 params ~= "Params:"; 2134 2135 //Loop for multi line descriptons for this param. 2136 bool firstRun = true; 2137 while(i+1 < comments.length && stilInParam(comments[i+1])) 2138 { 2139 i++; 2140 if(firstRun) 2141 { 2142 params ~= param ~" = "~ stripLeft(comments[i]); 2143 firstRun = false; 2144 } 2145 else 2146 params ~= comments[i]; 2147 } 2148 } 2149 else if( comments[i].chomp(":").strip() == "Returns" ) 2150 { 2151 //Skip return for Constructors. 2152 if(indexOf(fun.declaration(), "this (") > -1) 2153 { 2154 //Loop for multi line descriptons for this return. 2155 while(i+1 < comments.length && stilInParam(comments[i+1])) 2156 i++; 2157 continue; 2158 } 2159 2160 ret ~= "Returns:"; 2161 2162 //Loop for multi line descriptons for this return. 2163 bool firstRun = true; 2164 while(i+1 < comments.length && stilInParam(comments[i+1])) 2165 { 2166 i++; 2167 ret ~= " " ~ comments[i].strip(); 2168 } 2169 } 2170 else if(indexOf(comments[i], "See Also") == 0 || indexOf(comments[i], "Property Details") == 0) 2171 { 2172 //These sections get included with the last function. 2173 break; 2174 } 2175 else 2176 { 2177 //Add the rest to the description. 2178 description ~= comments[i]; 2179 } 2180 } 2181 2182 if(params.length > 0) 2183 { 2184 foreach(string line; params) 2185 description ~= line; 2186 } 2187 2188 if(ret.length > 0) 2189 description ~= ret; 2190 2191 if ( indexOf(fun.getExternal(), "GError**") > -1 2192 && indexOf(fun.declaration(), "Error") == -1 ) 2193 { 2194 description ~= "Throws: GException on failure."; 2195 } 2196 2197 if ( indexOf(fun.declaration(), "this (") > -1 ) 2198 { 2199 description ~= "Throws: ConstructionException GTK+ fails to create the object."; 2200 } 2201 2202 return description; 2203 } 2204 2205 if ( wrapper.includeComments() ) 2206 { 2207 string[] comments; 2208 while ( line<lines.length ) 2209 { 2210 //if ( !tooSoon ) 2211 //{ 2212 // tooSoon = lines[line]=="Since 2.10"; 2213 //} 2214 comments ~= lines[line++]; 2215 } 2216 2217 member ~= "/**"; 2218 2219 comments = phraseParams(comments); 2220 foreach(string line; comments) 2221 member ~= " * "~ line; 2222 2223 member ~= " */"; 2224 } 2225 } 2226 2227 if ( tooSoon ) 2228 { 2229 addComments(); 2230 member ~= "// next release"; 2231 } 2232 else 2233 { 2234 if ( !convParms.isInterface ) 2235 { 2236 string externalDeclaration = fun.getExternal(); 2237 2238 /* Don't add repeated declarations. */ 2239 bool addme = true; 2240 2241 foreach(ref string declaration; externalDeclarations) 2242 { 2243 if(externalDeclaration == declaration){ addme = false; break; } 2244 } 2245 2246 if(addme) externalDeclarations ~= externalDeclaration; 2247 } 2248 // body 2249 if ( !convParms.omitCode(fun.name) && indexOf(fun.declaration(), "...") < 0 ) 2250 { 2251 string gtkDDeclaration = fun.declaration(); 2252 //string gtkDDeclaration = stringToGtkD(rawDeclaration,convParms,wrapper.getAliases()); 2253 debug(declaration) writefln("Declaration\n\t%s\n\t%s",rawDeclaration, gtkDDeclaration); 2254 addComments(); 2255 member ~= gtkDDeclaration~iFaceChar; 2256 if ( !convParms.isInterface ) 2257 { 2258 member ~= "{"; 2259 member ~= "// "~funct; 2260 member ~= fun.bod(); 2261 member ~= "}"; 2262 } 2263 /* Duplicated functions are omitted. */ 2264 if(checkIfDupFunction(fun)) member.length = 0; 2265 checkIfGtkStructs(fun); 2266 } 2267 } 2268 } 2269 } 2270 } 2271 2272 return member; 2273 } 2274 2275 private bool checkIfDupFunction(Funct fun) 2276 { 2277 string signature = fun.convName~'('~fun.getWrapParametersType()~')'; 2278 if ( signature in functionSignatures ) 2279 { 2280 writefln("######################## duplicated function %s", signature); 2281 return true; 2282 } 2283 else 2284 { 2285 functionSignatures[signature] = 1; 2286 return false; 2287 } 2288 } 2289 2290 /* 2291 * Checks if the current line is still part of the param description. 2292 * it does this by checking for things not normaly in the param description 2293 * Params: 2294 * comments = Line to check. 2295 * Returns: true if we are still in the description of the param. 2296 */ 2297 bool stilInParam(string comments) 2298 { 2299 return !(indexOf(comments, ":") == comments.length-1 || 2300 comments.chomp(":").strip() == "Returns" || 2301 ( indexOf(comments, "Since 2.") == 0 || indexOf(comments, "Since 1.") == 0) || 2302 indexOf(comments, "See Also") == 0 || 2303 indexOf(comments, "Property Details") == 0 || 2304 comments == "<hr>"); 2305 } 2306 2307 /** 2308 * Prints out the potential Gtk struct to be wrapped 2309 * so that the wrap parameter can be set on the APILookupXXX.txt 2310 * TODO assume all structs are to be wrapped an explicitly declare the ones not to be wrapped 2311 * Params: 2312 * fun = 2313 */ 2314 private void checkIfGtkStructs(Funct fun) 2315 { 2316 bool found = false; 2317 void check(string type) 2318 { 2319 if ( startsWith(type, 'G') 2320 && endsWith(type, '*') 2321 ) 2322 { 2323 if ( type in gtkStructs ) 2324 { 2325 // nothing 2326 } 2327 else 2328 { 2329 found = true; 2330 gtkStructs[type] = 1; 2331 //writefln("######################## Gtk struct found %s\t\t%s", 2332 // type, 2333 // fun.convName~"("~fun.getWrapParametersType()~")" 2334 // ); 2335 2336 string strct = type; 2337 string dName = ""; 2338 string pack = ""; 2339 if ( startsWith(strct, "Gtk") ) 2340 { 2341 pack = "gtk"; 2342 dName = strct[3..strct.length-1]; 2343 //dName[0] = std.ascii.toLower(dName[0]); 2344 } 2345 else if ( startsWith(strct, "Gdk") ) 2346 { 2347 pack = "gdk"; 2348 dName = strct[3..strct.length-1]; 2349 //dName[0] = std.ascii.toLower(dName[0]); 2350 if ( dName == "Pixbuf") pack = "gdkpixbuf"; 2351 } 2352 else if ( startsWith(strct, "Gst") ) 2353 { 2354 pack = "gstreamer"; 2355 dName = strct[3..strct.length-1]; 2356 //dName[0] = std.ascii.toLower(dName[0]); 2357 } 2358 else if ( startsWith(strct, "G") ) 2359 { 2360 dName = strct[1..strct.length-1]; 2361 switch ( dName ) 2362 { 2363 case "Object": 2364 2365 if ( pack == "g" ) 2366 { 2367 pack = "gobject"; dName = "ObjectG"; 2368 } 2369 else if ( pack == "gdk" ) 2370 { 2371 dName = "ObjectG"; 2372 } 2373 else if ( pack == "gtk" ) 2374 { 2375 dName = "ObjectGtk"; 2376 } 2377 else if ( pack == "gstreamer" ) 2378 { 2379 dName = "ObjectGst"; 2380 } 2381 else if ( pack == "atk" ) 2382 { 2383 dName = "ObjectAtk"; 2384 } 2385 break; 2386 case "Closure": pack = "gobject"; break; 2387 case "Type": pack = "gobject"; break; 2388 case "Value": pack = "gobject"; break; 2389 case "List": pack = "glib"; dName = "ListG"; break; 2390 case "SList": pack = "glib"; dName = "ListSG"; break; 2391 case "String": pack = "glib"; dName = "StringG"; break; 2392 case "IOChannel": pack = "glib"; break; 2393 case "Quark": pack = "glib"; break; 2394 case "ParmSpec": pack = "gobject"; break; 2395 case "TypeModule": pack = "gobject"; break; 2396 case "Flags": pack = "gobject"; break; 2397 case "Enums": pack = "gobject"; break; 2398 default: 2399 pack = "g"; 2400 break; 2401 } 2402 } 2403 debug(structs)writefln("import: %s.%s", pack, dName); 2404 debug(structs)writefln("structWrap: %s %s", strct, dName); 2405 } 2406 } 2407 } 2408 2409 if ( !fun.ctor 2410 && !endsWith(fun.convName, "Struct") 2411 ) 2412 { 2413 check(fun.typeWrap); 2414 } 2415 foreach ( count , param ; fun.params ) 2416 { 2417 if ( count > 0 || param.typeWrap != convParms.strct~'*' ) 2418 { 2419 check(param.typeWrap); 2420 } 2421 } 2422 } 2423 2424 /** 2425 * Params: 2426 * line = The API line of the function 2427 * convParms = the Conversion parameters 2428 * Returns: 2429 */ 2430 private string getFunction(string line, ConvParms* convParms) 2431 { 2432 debug(functionType) writefln("\ngetFunction line = %s", line); 2433 // void (*GChildWatchFunc) (GPid pid, gint status, gpointer data); 2434 // public typedef extern(C) void function(int, int, void*) GChildWatchFunc; 2435 2436 2437 2438 string f = "extern(C) "; 2439 int pos = 0; 2440 string type = until(pos, line, "("); 2441 until(pos, line, "*"); 2442 skip(pos, line, '*'); 2443 string name = until(pos, line, ")"); 2444 if (convParms.omitCode(name)) { 2445 return ""; 2446 } 2447 2448 f ~= stringToGtkD(type, convParms, wrapper.getAliases()).strip(); 2449 f ~= " function("; 2450 2451 until(pos, line, "("); 2452 skip(pos, line, '('); 2453 skipBlank(pos, line); 2454 2455 string sourceParms = std..string.strip(until(pos, line, ")")); 2456 string parms; 2457 2458 if ( sourceParms != "void" ) 2459 { 2460 int sPos = 0; 2461 int count = 0; 2462 debug(functionType) writefln("sourceParms = %s", sourceParms); 2463 while ( sPos < sourceParms.length ) 2464 { 2465 skipBlank(sPos, sourceParms); 2466 debug(functionType)writefln("parms sPos=%s [%s]",sPos, sourceParms[sPos..sourceParms.length]); 2467 if (count++ > 0 ) 2468 { 2469 parms ~= ", "; 2470 } 2471 string pType = untilBlank(sPos, sourceParms); 2472 fixType(pType, sPos, sourceParms); 2473 2474 string pName = until(sPos, sourceParms, ",)"); 2475 2476 debug(parmType)writefln("\tParameter type before = %s", pType); 2477 debug(parmName)writefln("\tParameter name before = %s", pName); 2478 adjustTypeName(pType, pName); 2479 debug(parmType)writefln("\tParameter type after = %s", pType); 2480 debug(parmName)writefln("\tParameter name after = %s", pName); 2481 2482 parms ~= tokenToGtkD(pType, convParms, wrapper.getAliases()) ~" "~ idsToGtkD(pName, convParms, wrapper.getAliases()); 2483 ++sPos; 2484 } 2485 } 2486 2487 if ( name == "ref" ) 2488 name = "doref"; 2489 2490 f ~= parms ~ ") " ~ name ~ ";"; 2491 2492 return f; 2493 } 2494 2495 /** 2496 * Wraps a set of lines in the block documentation comment 2497 * Returns: The comment formated for D block documentation comment 2498 */ 2499 private string[] getDescription() 2500 { 2501 string[] desc; 2502 desc ~= ""; 2503 desc ~= tabs ~ "/**"; 2504 string[] block = getBlock ("Description", "Details"); 2505 foreach ( string line; block ) 2506 { 2507 if( startsWith(line, "--") && endsWith(line, "--") ) 2508 line = std.array.replace(line, "-", "_"); 2509 2510 desc ~= " * " ~ line; 2511 } 2512 desc ~= tabs ~ " */"; 2513 2514 return desc; 2515 2516 } 2517 2518 /** 2519 * Finds a block of lines delimited by the marker lines from the start of the text 2520 * Params: 2521 * startLine = The Start marker line 2522 * endLine = The end marker line 2523 * Returns: The block os lines 2524 */ 2525 private string[] getBlock(string startLine, string endLine) 2526 { 2527 currLine = 0; 2528 2529 debug(getBlock) writefln("getBlock for ]%s,%s[", startLine, endLine); 2530 2531 // TODO use slicing instead of this array 2532 string[] block; 2533 2534 while ( currLine<inLines.length && inLines[currLine]!=startLine ) 2535 { 2536 debug(getBlock) writefln("-\t\t[%s]%s",currLine,inLines[currLine]); 2537 ++currLine; 2538 } 2539 2540 return getUntil(endLine); 2541 } 2542 2543 private int moveToBlockStart(string startLine, string[] inLines) 2544 { 2545 int startPos = 0; 2546 while ( startPos < inLines.length && inLines[startPos]!= startLine ) 2547 { 2548 ++startPos; 2549 } 2550 return startPos; 2551 } 2552 2553 /** 2554 * Gets all the non empty lines until a marker line 2555 * Params: 2556 * endLine = the marker line 2557 * Returns: 2558 */ 2559 private string[] getUntil(string endLine) 2560 { 2561 bool end = false; 2562 2563 string[] block; 2564 2565 while ( currLine < inLines.length && !end ) 2566 { 2567 if ( inLines[currLine] == endLine ) 2568 { 2569 end = true; 2570 debug(getUntil) writefln("getBlock end at line %s",currLine,"\n"); 2571 } 2572 else 2573 { 2574 if ( std..string.strip(inLines[currLine]).length > 0 ) 2575 { 2576 block ~= inLines[currLine]; 2577 } 2578 debug(getUntil) writefln("+[%s]%s",currLine,inLines[currLine]); 2579 } 2580 ++currLine; 2581 } 2582 return block; 2583 } 2584 2585 /** 2586 * Gets all the non empty lines until a marker line 2587 * Params: 2588 * endLine = the marker line 2589 * Returns: 2590 */ 2591 private string[] getUntil(string endLine, string[] lines) 2592 { 2593 bool end = false; 2594 int currLine; 2595 2596 string[] block; 2597 2598 while ( currLine < lines.length && !end ) 2599 { 2600 if ( lines[currLine] == endLine ) 2601 { 2602 end = true; 2603 debug(getUntil) writefln("getBlock end at line %s",currLine,"\n"); 2604 } 2605 else 2606 { 2607 if ( std..string.strip(lines[currLine]).length > 0 ) 2608 { 2609 block ~= lines[currLine]; 2610 } 2611 debug(getUntil) writefln("+[%s]%s",currLine,lines[currLine]); 2612 } 2613 ++currLine; 2614 } 2615 return block; 2616 } 2617 2618 /** 2619 * Converts a GTK strin to a GtkD string. 2620 * This removes the "_" and capitalises the next letter and converts the basic types 2621 * Params: 2622 * gString = 2623 * Returns: 2624 */ 2625 public static string stringToGtkD(string gString, ConvParms* convParms, string[string] aliases, bool caseConvert=true) 2626 { 2627 string converted; 2628 2629 int pos = 0 ; 2630 string seps = " \n\r\t\f\v()[]*,;"; 2631 2632 char c = ' '; 2633 char pc; 2634 int start = 0; 2635 int end = 0; 2636 while ( pos < gString.length ) 2637 { 2638 pc = c; 2639 c = gString[pos]; 2640 if ( std..string.indexOf(seps,c) >= 0 ) 2641 { 2642 end = pos; 2643 converted ~= tokenToGtkD(gString[start..end], convParms, aliases, caseConvert); 2644 if ( c=='*' ) 2645 { 2646 //if ( pc==' ' ) 2647 //{ 2648 // converted.length = converted.length-1; 2649 //} 2650 //converted ~= "[] "; 2651 converted ~= c; 2652 2653 } 2654 else if ( c<=' ' ) 2655 { 2656 if ( converted.length >0 && converted[converted.length-1] != ' ' ) 2657 { 2658 converted ~= ' '; 2659 } 2660 c = ' '; 2661 } 2662 else 2663 { 2664 converted ~= c; 2665 } 2666 start = pos+1; 2667 } 2668 ++pos; 2669 } 2670 if ( pos > start ) 2671 { 2672 converted ~= tokenToGtkD(gString[start..pos], convParms, aliases, caseConvert); 2673 } 2674 return converted; 2675 } 2676 2677 2678 public static string idsToGtkD(string gToken, ConvParms* convParms, string[string] aliases, bool caseConvert=true) 2679 { 2680 string converted = tokenToGtkD(gToken, convParms, aliases, caseConvert); 2681 switch ( converted ) 2682 { 2683 case "alias" : converted = "alia"; break; 2684 case "class" : converted = "clss"; break; 2685 case "interface" : converted = "intrface"; break; 2686 case "debug" : converted = "dbug"; break; 2687 case "version" : converted = "vrsion"; break; 2688 case "out" : converted = "f_out"; break; 2689 case "in" : converted = "f_in"; break; 2690 case "inout" : converted = "f_inout"; break; 2691 //case "ref" : converted = "doref"; break; // TODO why wasn't this converted from the alias on APILookup.txt 2692 default: 2693 // done 2694 break; 2695 } 2696 return converted; 2697 } 2698 2699 /** 2700 * Convert for normal GtkD conversion and after verifies if is necessary to use a enumType for references enum values 2701 * Params: 2702 * enumType = 2703 * gToken = 2704 * convParms = 2705 * aliases = 2706 * caseConvert = 2707 * Returns: 2708 */ 2709 public static string enumToGtkD(string enumType, string gToken, ConvParms* convParms, WrapperIF wrapper, bool caseConvert=true) 2710 { 2711 debug(enumToGtkD)writefln("enumLine (%s) BEFORE %s", enumType, gToken); 2712 string converted = stringToGtkD(gToken, convParms, wrapper.getAliases()); 2713 2714 sizediff_t pos = std..string.indexOf(converted, '='); 2715 debug(enumToGtkD)writefln("\t pos = %s", pos); 2716 if ( pos > 0 ) 2717 { 2718 string refValue = std..string.strip(converted[pos+1..converted.length]); 2719 converted = converted[0..pos+1]~ " "; 2720 2721 debug(enumToGtkD)writefln("\t refValue = %s", refValue); 2722 bool needComa = false; 2723 if ( endsWith(refValue, ',') ) 2724 { 2725 refValue = std..string.strip(refValue[0..refValue.length-1]); 2726 needComa = true; 2727 } 2728 2729 debug(enumToGtkD)writefln("\t refValue = %s", refValue); 2730 2731 debug(enumToGtkD) 2732 { 2733 foreach(string key ; wrapper.getEnumTypes().keys) 2734 { 2735 writefln("\t\t [%s] = %s", key, wrapper.getEnumTypes()[key]); 2736 } 2737 } 2738 2739 if ( std..string.indexOf(refValue, ' ') > 0 && std..string.indexOf(refValue, '<') > 0 ) 2740 { 2741 string[] parts = std..string.split(refValue); 2742 2743 foreach ( part; parts ) 2744 { 2745 if ( startsWith(part, "(") ) 2746 { 2747 converted ~= "("; 2748 part = part[1 .. $]; 2749 } 2750 2751 if ( part in wrapper.getEnumTypes() ) 2752 { 2753 part = wrapper.getEnumTypes()[part] ~" "; 2754 } 2755 else if ( std..string.indexOf(part, "<<") > 0 ) 2756 { 2757 string[] values = std..string.split(part, "<<"); 2758 2759 if ( values[0] in wrapper.getEnumTypes() ) 2760 values[0] = wrapper.getEnumTypes()[values[0]]; 2761 if ( values[1] in wrapper.getEnumTypes() ) 2762 values[1] = wrapper.getEnumTypes()[values[1]]; 2763 2764 part = values[0] ~" << "~ values[1] ~ " "; 2765 } 2766 2767 converted ~= part ~" "; 2768 } 2769 } 2770 else if ( refValue in wrapper.getEnumTypes() ) 2771 { 2772 converted ~= wrapper.getEnumTypes()[refValue]; 2773 } 2774 else 2775 { 2776 converted ~= refValue; 2777 } 2778 2779 converted = std..string.stripRight(converted); 2780 2781 if (needComa) 2782 converted ~= ","; 2783 } 2784 debug(enumToGtkD)writefln("enumLine (%s) AFTER %s", enumType, converted); 2785 2786 return converted; 2787 } 2788 2789 /** 2790 * Converts a GTK token to a Dui token 2791 * This removes the "_" and capitalises the next letter and converts the basic types. 2792 * Doesn't do it if it's cairo name 2793 * Params: 2794 * gToken = 2795 * Returns: 2796 */ 2797 public static string tokenToGtkD(string gToken, ConvParms* convParms, string[string] aliases, bool caseConvert=true) 2798 { 2799 string converted; 2800 2801 debug(tokenToGtkD) writefln("gToken=>>>%s<<<", gToken); 2802 2803 if ( (aliases !is null) && (gToken in aliases) ) 2804 { 2805 converted = aliases[gToken]; 2806 } 2807 else if ( (convParms.aliases !is null) && (gToken in convParms.aliases) ) 2808 { 2809 converted = convParms.aliases[gToken]; 2810 } 2811 else if ( endsWith(gToken, "_t") && startsWith(gToken,"cairo_") ) 2812 { 2813 converted = gToken; 2814 } 2815 else if ( endsWith(gToken, "_t*") && startsWith(gToken,"cairo_") ) 2816 { 2817 converted = gToken; 2818 } 2819 else if ( endsWith(gToken, "_t**") && startsWith(gToken,"cairo_") ) 2820 { 2821 converted = gToken; 2822 } 2823 else if ( startsWith(gToken,"f_") && (endsWith(gToken,"_out") || endsWith(gToken,"_in") || endsWith(gToken,"_inout") ) ) 2824 { 2825 converted = gToken; 2826 } 2827 else if ( caseConvert ) 2828 { 2829 converted = gToken.removePrefix(convParms).removeUnderscore(); 2830 // do it again after the gToken is converted 2831 if ( (aliases !is null) && (converted in aliases) ) 2832 { 2833 converted = aliases[converted]; 2834 } 2835 } 2836 else 2837 { 2838 converted = gToken; 2839 } 2840 2841 debug(tokenToGtkD) writefln("converted=>>>%s<<<\n", converted); 2842 2843 return converted; 2844 } 2845 2846 2847 2848 /** 2849 * Moves '*' and 'const' and trailing '[]' from the name to the type token 2850 * Params: 2851 * type = 2852 * name = 2853 */ 2854 public static void adjustTypeName(ref string type, ref string name) 2855 { 2856 debug(type)writefln("type before %s", type); 2857 debug(name)writefln("name before %s", name); 2858 name = std..string.strip(name); 2859 while ( name.length > 0 2860 && (GtkDClass.startsWith(name,"const") || name[0] == '*' 2861 || GtkDClass.startsWith(name,"G_GNUC_MAY_ALIAS") ) 2862 ) 2863 { 2864 if ( name[0] == '*' ) 2865 { 2866 type = type ~ '*'; 2867 name = std..string.strip(name[1..name.length]); 2868 } 2869 else if (GtkDClass.startsWith(name,"const")) 2870 { 2871 name = std..string.strip(name[5..name.length]); 2872 } 2873 else 2874 { 2875 name = std..string.strip(name[16..name.length]); 2876 } 2877 name = std..string.strip(name); 2878 } 2879 while ( GtkDClass.endsWith(name, "[]") ) 2880 { 2881 type ~= "*"; 2882 name = std..string.strip(name[0..name.length-2]); 2883 } 2884 debug(type)writefln("type after %s", type); 2885 debug(name)writefln("name after %s", name); 2886 } 2887 2888 /** 2889 * Consumes "const" and "unsigned" adding "u" to the type when "unsigned" is found 2890 * (? uchar will become just char) 2891 * Params: 2892 * type = 2893 * p = 2894 * text = 2895 */ 2896 public static void fixType(ref string type, ref int p, ref string text) 2897 { 2898 if ( type == "const" || type == "struct" ) 2899 { 2900 GtkDClass.skipBlank(p, text); 2901 type = untilBlank(p, text); 2902 } 2903 if ( type == "unsigned" ) 2904 { 2905 GtkDClass.skipBlank(p, text); 2906 type = "u" ~ untilBlank(p, text); 2907 } 2908 if ( startsWith(type, "_") ) 2909 { 2910 type = type[1..$]; 2911 } 2912 // if ( type == "uchar" ) 2913 // { 2914 // type = "char"; 2915 // } 2916 } 2917 2918 2919 2920 2921 public static bool startsWith(string str, string prefix) 2922 { 2923 return str.length >= prefix.length 2924 && str[0..prefix.length] == prefix; 2925 } 2926 2927 public static bool startsWith(string str, char prefix) 2928 { 2929 return str.length > 0 2930 && str[0] == prefix; 2931 } 2932 2933 public static bool endsWith(string str, string suffix) 2934 { 2935 return str.length >= suffix.length 2936 && str[str.length-suffix.length..str.length] == suffix; 2937 } 2938 2939 public static bool endsWith(string str, char suffix) 2940 { 2941 return str.length >= 1 2942 && str[str.length-1] == suffix; 2943 } 2944 2945 } 2946 2947 string removePrefix(string gToken, string prefix) 2948 { 2949 if ( startsWith(gToken, prefix) ) 2950 { 2951 return gToken[prefix.length..gToken.length]; 2952 } 2953 return gToken; 2954 } 2955 2956 string removePrefix(string gToken, ConvParms* convParms) 2957 { 2958 //debug(tokenToGtkD) writefln("gToken.length > prefix.length %s",gToken.length > convParms.prefix.length); 2959 string prefix = convParms.getPrefix(gToken); 2960 if ( prefix.length > 0 ) 2961 { 2962 return gToken[prefix.length..gToken.length]; 2963 } 2964 2965 return gToken; 2966 2967 } 2968 2969 string removeUnderscore(string gToken) 2970 { 2971 string converted; 2972 2973 char c = ' '; 2974 char pc = ' '; 2975 char ppc = ' '; 2976 int pos = 0; 2977 while ( pos < gToken.length ) 2978 { 2979 c = gToken[pos]; 2980 if ( pc == '_' ) 2981 { 2982 c = to!char(std.ascii.toUpper(c)); 2983 } 2984 else if ( c == '_' && std.ascii.isLower(pc) ) 2985 { 2986 pc = c; 2987 c = '\0'; 2988 } 2989 2990 if ( c > '\0' ) 2991 { 2992 if ( ppc == '_' 2993 && pc == 'g' 2994 && c == 'l' 2995 && gToken.length-1 > pos 2996 && gToken[pos+1] == '_' 2997 ) 2998 { 2999 c = 'L'; 3000 } 3001 ppc = pc; 3002 pc = gToken[pos]; 3003 converted ~= c; 3004 } 3005 ++pos; 3006 } 3007 return converted; 3008 } 3009