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