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