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.funct; 21 22 //debug = Funct; 23 //debug = wrapType; 24 //debug = unwrapType; 25 //debug = mainStrct; 26 //debug = declaration; 27 //debug = ctor; 28 //debug = type; 29 //debug = name; 30 //debug = parm; 31 //debug = externalDec 32 //debug = callback; 33 34 private import std.string; 35 private import std.stdio; 36 37 private import utils.convparms; 38 private import utils.GtkDClass; 39 40 bool contains(string[] src, string elem) 41 { 42 foreach( str; src) 43 if ( str == elem ) 44 return true; 45 46 return false; 47 } 48 49 bool contains(Param[] params, string elem) 50 { 51 foreach( param; params) 52 if ( param.name == elem ) 53 return true; 54 55 return false; 56 } 57 58 string contains(string[string] src, string elem) 59 { 60 foreach( key, str; src) 61 if ( str == elem ) 62 return key; 63 64 return null; 65 } 66 67 struct Param 68 { 69 string type; 70 string typeWrap; 71 string name; 72 string convName; 73 74 bool constParam; 75 bool outParam; 76 bool refParam; 77 bool arrayParam; 78 79 string lengthParamName; 80 } 81 82 public struct Funct 83 { 84 bool ctor; /// when true this method was found to be a constructor 85 string type; 86 string typeWrap; 87 string name; 88 string convName; /// name after convertion 89 90 Param[] params; 91 92 string strctVar; 93 string strctPointer; 94 95 ConvParms* convParms; 96 string[string] aliases; 97 98 @disable this(); 99 100 /** 101 * Gets the type, name and parameters of the function 102 * Params: 103 * text = The Gtk API description of the function call 104 */ 105 this(string text, ConvParms* convParms, string[string] aliases) 106 { 107 this.convParms = convParms; 108 this.aliases = aliases; 109 110 strctVar = getStrctVar(); 111 strctPointer = convParms.strct ~ "*"; 112 113 debug(Funct) writefln("init text=%s", text); 114 115 int p = 0; 116 GtkDClass.skipBlank(p,text); 117 type = GtkDClass.untilBlank(p, text); 118 119 debug(type)writef("type = %s", type); 120 121 GtkDClass.fixType(type, p, text); 122 123 debug(type)writefln(" -> %s", type); 124 125 GtkDClass.skipBlank(p, text); 126 name = GtkDClass.until(p, text, '('); 127 128 GtkDClass.adjustTypeName(type, name); 129 130 if ( type == "gchar**" || type == "char**" ) 131 { 132 typeWrap = "string[]"; 133 } 134 else if ( name in convParms.array && "Return" in convParms.array[name] ) 135 { 136 if ( type == "gpointer" || type == "gconstpointer" ) 137 type = "void*"; 138 139 typeWrap = getWrappedType(type[0 .. $-1]) ~ "[]"; 140 141 if ( typeWrap == "char[]" || typeWrap == "gchar[]" ) 142 typeWrap = "string"; 143 } 144 else 145 { 146 typeWrap = getWrappedType(type); 147 } 148 149 GtkDClass.skip(p, text,'('); 150 int countBrace = 0; 151 while ( countBrace==0 && p<text.length && text[p]!=')' ) 152 { 153 Param param; 154 155 GtkDClass.skipBlank(p, text); 156 param.type = GtkDClass.untilBlank(p, text, ",)"); 157 158 debug(parm)writef("currParmType = %s", currParmType); 159 160 if ( param.type == "const") 161 { 162 param.constParam = true; 163 164 GtkDClass.skipBlank(p, text); 165 param.type = GtkDClass.untilBlank(p, text, ",)"); 166 } 167 else if ( std..string.indexOf(" volatile G_CONST_RETURN ", param.type) > 0 ) 168 { 169 GtkDClass.skipBlank(p, text); 170 param.type = GtkDClass.untilBlank(p, text, ",)"); 171 } 172 173 if ( param.type == "struct" ) 174 { 175 GtkDClass.skipBlank(p, text); 176 GtkDClass.untilBlank(p, text, ",)"); 177 param.type = "void"; 178 } 179 else if ( param.type == "gpointer" ) 180 { 181 param.type = "void*"; 182 } 183 else if ( param.type == "gconstpointer" ) 184 { 185 param.type = "void*"; 186 param.constParam = true; 187 } 188 else 189 { 190 GtkDClass.fixType(param.type, p, text); 191 } 192 193 debug(parm)writefln(" -> %s", currParmType); 194 195 GtkDClass.skipBlank(p, text); 196 if ( param.type != "..." ) 197 { 198 param.name = GtkDClass.until(p, text, "),"); 199 200 if ( param.name == "*ref" ) 201 param.name = "*doref"; 202 } 203 else 204 { 205 param.name = ""; 206 } 207 208 GtkDClass.adjustTypeName(param.type, param.name); 209 param.convName = GtkDClass.idsToGtkD(param.name, convParms, aliases); 210 211 param.outParam = isOutParam(param.name); 212 param.refParam = isRefParam(param.name); 213 param.arrayParam = isArrayParam(param.name); 214 215 if ( param.arrayParam ) 216 param.lengthParamName = convParms.array[name][param.name]; 217 218 param.typeWrap = getWrappedType(param); 219 220 if ( param.typeWrap == "string" ) 221 param.arrayParam = false; 222 223 params ~= param; 224 225 if ( p<text.length && text[p]==',') ++p; 226 } 227 228 GtkDClass.skip(p, text, ';'); 229 } 230 231 private bool isOutParam(string currParam) 232 { 233 if ( name in convParms.outParms && convParms.outParms[name].contains(currParam) ) 234 return true; 235 236 return false; 237 } 238 239 private bool isRefParam(string currParam) 240 { 241 if ( name in convParms.inoutParms && convParms.inoutParms[name].contains(currParam) ) 242 return true; 243 244 return false; 245 } 246 247 private bool isArrayParam(string currParam) 248 { 249 if ( name in convParms.array && currParam in convParms.array[name] ) 250 return true; 251 252 return false; 253 } 254 255 private bool isLengthParam(string currParam) 256 { 257 if ( name in convParms.array && convParms.array[name].contains(currParam) ) 258 return true; 259 260 return false; 261 } 262 263 string getStrctVar() 264 { 265 if ( strctVar.length == 0 ) 266 return strctVar; 267 268 if ( convParms.strct.length > 0 ) 269 return GtkDClass.toVar(convParms.strct); 270 271 return ""; 272 } 273 274 /** 275 * Checks the type against the strcutWrap table 276 * Returns: 277 */ 278 string getWrappedType(string currType) 279 { 280 string wType; 281 if ( currType == "gchar*" || currType == "char*" ) 282 { 283 wType = "string"; 284 } 285 else if ( convParms.structWrap.length == 0 ) 286 { 287 // this should be the common case 288 wType = currType; 289 } 290 else if ( currType in convParms.structWrap ) 291 { 292 wType = convParms.structWrap[currType]; 293 debug(wrapType) writefln("WrappedType %s -> %s", currType, wType); 294 } 295 else 296 { 297 wType = currType; 298 } 299 300 debug(wrapType)writefln("\t wrapType: %s -> %s", currType, wType); 301 return wType; 302 } 303 304 /** 305 * Ditto, but for parameters, also checks for out, ref, array and const. 306 */ 307 string getWrappedType(Param param) 308 { 309 string wType; 310 311 if ( param.arrayParam ) 312 { 313 if ( param.outParam ) 314 wType ~= "out "~ getWrappedType(param.type[0 .. $-2]) ~"[]"; 315 else if ( param.refParam ) 316 wType ~= "ref "~ getWrappedType(param.type[0 .. $-2]) ~"[]"; 317 else 318 wType ~= getWrappedType(param.type[0 .. $-1]) ~"[]"; 319 } 320 else if ( param.outParam ) 321 { 322 wType ~= "out "~ getWrappedType(param.type[0 .. $-1]); 323 } 324 else if ( param.refParam ) 325 { 326 wType ~= "ref "~ getWrappedType(param.type[0 .. $-1]); 327 } 328 else 329 { 330 wType ~= getWrappedType(param.type); 331 } 332 333 if ( (wType == "char[]" || wType == "gchar[]") && param.constParam ) 334 wType = "string"; 335 336 return wType; 337 } 338 339 /** 340 * Gets the gtk from the GtkD class to be used on the Gtk function call 341 * Params: 342 * currType = 343 * convParms = 344 * Returns: 345 */ 346 string getUnwrappedType(string currType) 347 { 348 // TODO 349 return currType; 350 } 351 352 /** 353 * Gets the external declaration 354 * Params: 355 * = 356 * aliases = 357 * Returns: 358 */ 359 string getExternal() 360 { 361 362 string ext = (( type == "Window" ) ? "gulong" : type) ~ " function(" 363 ~ getParameters() 364 ~ ")" 365 ~ name 366 ; 367 368 return ext; 369 } 370 371 string getParameters() 372 { 373 string parameters; 374 375 foreach( i, param; params ) 376 { 377 if ( i>0 ) parameters ~= ", "; 378 379 if ( param.type != "void" || param.name.length > 0 ) 380 { 381 //Workaround for GtkPlug/GtkSocket. 382 if ( param.type == "Window" ) 383 parameters ~= "gulong "~ param.convName; 384 else 385 parameters ~= param.type ~" "~ param.convName; 386 } 387 } 388 389 return parameters; 390 } 391 392 /** 393 * Gets the parameters for the call back functions. 394 * These are all but the first parameter and the last parameter will be the class. 395 * I'm not sure ths is valid for all callbacks. 396 * Params: 397 * firstParameter = ? 398 * Returns: 399 */ 400 string getCallbackParameters(int firstParameter = 0) 401 { 402 string parameters; 403 404 debug(callback)writefln("getCallbackParameters "~convParms.clss); 405 debug(callback)writefln("\t %s", getExternal()); 406 407 foreach ( i, param; params[firstParameter .. $-1] ) 408 { 409 if ( i == 0 && GtkDClass.endsWith(param.type, '*') ) 410 parameters ~= param.type ~" "~ param.convName ~"Struct"; 411 else 412 parameters ~= param.type ~" "~ param.convName; 413 414 parameters ~= ", "; 415 } 416 417 if(convParms.templ.length > 0) 418 parameters ~= convParms.interf~" _"~GtkDClass.idsToGtkD(GtkDClass.getClassVar(convParms), convParms, aliases); 419 else 420 parameters ~= convParms.clss~" _"~GtkDClass.idsToGtkD(GtkDClass.getClassVar(convParms), convParms, aliases); 421 422 return parameters.tr("-", "_"); 423 } 424 425 /** 426 * Gets the actual parameters for the call back functions. 427 * These are all but the first parameter and the last parameter will be the class. 428 * I'm not sure ths is valid for all callbacks. 429 */ 430 string getCallbackVars() 431 { 432 string parameters; 433 434 debug(callback)writefln("getCallbackVars "~convParms.clss); 435 debug(callback)writefln("\t %s", getExternal(convParms, aliases)); 436 437 foreach ( i, param; params[1 .. $-1] ) 438 { 439 parameters ~= parameterToGtkD(param) ~", "; 440 } 441 442 parameters ~= "_"~GtkDClass.idsToGtkD(GtkDClass.getClassVar(convParms), convParms, aliases); 443 444 return parameters.tr("-", "_"); 445 } 446 447 string getDelegateDeclaration(int firstParameter = 0) 448 { 449 if ( GtkDClass.endsWith(typeWrap,"user_function") ) 450 typeWrap = typeWrap[0..typeWrap.length-13]; 451 452 if ( typeWrap == "gboolean" ) 453 typeWrap = "bool"; 454 455 string decl = typeWrap ~ " delegate("; 456 457 foreach ( param; params[firstParameter .. $-1] ) 458 { 459 decl ~= param.typeWrap ~", "; 460 } 461 462 //If we are generating an interface or template 463 //use the interface name in the delegate. 464 if(convParms.isInterface || convParms.templ.length > 0) 465 decl ~= convParms.interf; 466 else 467 decl ~= convParms.clss; 468 469 decl ~= ")"; 470 return decl; 471 } 472 473 474 /** 475 * Gets the method header. 476 * If the type is a pointer to the main strcut and the name starts with "new" 477 * then the method is a constructor 478 * Returns: 479 */ 480 string declaration() 481 { 482 string dec; 483 string returnType; 484 485 if ( indexOf(typeWrap, "string") > -1 ) 486 returnType = typeWrap; 487 else 488 returnType = GtkDClass.stringToGtkD(typeWrap, convParms, aliases); 489 490 debug(ctor)writefln("declaration ctor strct = %s",convParms.strct); 491 debug(ctor)writefln("declaration ctor realStrct = %s",convParms.realStrct); 492 debug(ctor)writefln("declaration ctor type = %s",type); 493 debug(ctor)writefln("declaration ctor name = %s",name); 494 495 convName = GtkDClass.idsToGtkD(name, convParms, aliases); 496 497 if( convName == "ref" ) 498 convName = "doref"; 499 500 convName = GtkDClass.stringToGtkD(convName, convParms, aliases); 501 502 debug(declaration)writefln("name=%s convName=%s", name, convName); 503 504 if ( convParms.strct.length>0 505 && GtkDClass.startsWith(convName, "new") 506 && ( (type == strctPointer 507 || type == convParms.ctorStrct~"*") 508 || /* special GObject case */ 509 (type == "gpointer" && convParms.strct == "GObject") 510 || /* special Gtk... that return a GtkWidget pointer */ 511 (type == "GtkWidget*") 512 || /* special Gtk... that return a GtkWidget pointer */ 513 (type == "GtkObject*" && convParms.strct == "GtkAdjustment") 514 ) 515 ) 516 { 517 dec = "public this ("; 518 ctor = true; 519 convName = "this"; 520 } 521 else 522 { 523 if ( convName == "new" ) 524 convName ~= convParms.outFile; 525 526 string overr; 527 if (convParms.needsOverride(convName) && !convParms.isInterface ) 528 overr = "override "; 529 530 if ( convParms.strct.length>0 531 && params.length > 0 532 && params[0].type == strctPointer 533 && !params[0].arrayParam 534 ) 535 { 536 dec = "public "~overr~returnType~" "~convName~"("; 537 } 538 else 539 { 540 dec = "public static "~overr~returnType~" "~convName~"("; 541 } 542 ctor = false; 543 } 544 545 foreach ( i, param; params ) 546 { 547 if ( i == 0 ) 548 { 549 debug(mainStrct)writefln("1st Parm %s ?= %s",parmsType[i], convParms.strct); 550 551 if ( !ctor && param.type == strctPointer && !param.arrayParam ) 552 { 553 debug(mainStrct)writefln("\tSAME <<<<<<------"); 554 continue; 555 } 556 } 557 558 if ( GtkDClass.startsWith(param.typeWrap, "GError**") && convParms.strct != "GError" ) 559 continue; 560 561 if ( isLengthParam(param.name) ) 562 continue; 563 564 if ( dec[$-1] != '(' ) 565 dec ~= ", "; 566 567 if ( param.type != "void" || param.name.length > 0) 568 { 569 if ( indexOf(param.typeWrap, "string") > -1 ) 570 dec ~= param.typeWrap; 571 else 572 dec ~= GtkDClass.stringToGtkD(param.typeWrap, convParms, aliases); 573 574 dec ~= " "~ param.convName; 575 } 576 } 577 dec ~= ')'; 578 579 debug(declaration)writefln("declaration=%s", dec); 580 581 return dec; 582 } 583 584 /** 585 * Wraps the parameters if necessary 586 * Params: 587 * i = 588 * Returns: 589 */ 590 string parameterToGtk(Param param) 591 { 592 string parmToGtk; 593 594 if ( param.type != param.typeWrap ) 595 { 596 if ( param.typeWrap == "string" ) 597 { 598 if ( param.lengthParamName != "" && param.constParam ) 599 { 600 parmToGtk = "cast(char*)"~ param.convName ~".ptr"; 601 } 602 else 603 { 604 parmToGtk = "Str.toStringz("~ param.convName ~")"; 605 } 606 } 607 else if ( param.typeWrap == "string[]" ) 608 { 609 parmToGtk = "Str.toStringzArray("~ param.convName ~")"; 610 } 611 else if ( param.outParam || param.refParam ) 612 { 613 //Is this a plian old data type. 614 if ( param.type[0 .. $-1] == split(param.typeWrap)[1] ) 615 parmToGtk = "&" ~ param.convName; 616 else 617 parmToGtk = "&out" ~ param.convName; 618 } 619 else if ( param.arrayParam ) 620 { 621 parmToGtk = param.convName ~".ptr"; 622 } 623 else 624 { 625 if(GtkDClass.endsWith(param.typeWrap, "IF")) 626 parmToGtk = "("~param.convName~" is null) ? null : "~param.convName~ ".get"~ param.typeWrap[0..$-2] ~ "T" ~"Struct()"; 627 else if ( param.typeWrap == "Application" && param.type == "GtkApplication*" ) 628 parmToGtk = "("~param.convName~" is null) ? null : "~param.convName~ ".getGtk"~ param.typeWrap ~"Struct()"; 629 else 630 parmToGtk = "("~param.convName~" is null) ? null : "~param.convName~ ".get"~ param.typeWrap ~"Struct()"; 631 } 632 } 633 else 634 { 635 if ( name in convParms.array && convParms.array[name].contains(param.name) ) 636 { 637 if ( name in convParms.outParms && convParms.outParms[name].contains(convParms.array[name].contains(param.name)) ) 638 { 639 if ( GtkDClass.endsWith(param.type, "*") ) 640 parmToGtk = "&"~ param.convName; 641 else 642 parmToGtk ~= param.convName; 643 } 644 else if ( name in convParms.inoutParms && convParms.inoutParms[name].contains(convParms.array[name].contains(param.name)) ) 645 { 646 if ( GtkDClass.endsWith(param.type, "*") ) 647 parmToGtk = "&"~ param.convName; 648 else 649 parmToGtk ~= param.convName; 650 } 651 else 652 { 653 string id = GtkDClass.idsToGtkD(convParms.array[name].contains(param.name), convParms, aliases); 654 parmToGtk = "cast(int) "~ id ~".length"; 655 } 656 } 657 else 658 { 659 parmToGtk = param.convName; 660 } 661 } 662 return parmToGtk; 663 } 664 665 string parameterToGtkD(Param param) 666 { 667 string parmToGtkD; 668 669 if ( param.type != param.typeWrap ) 670 { 671 if ( param.typeWrap == "string" ) 672 { 673 parmToGtkD = "Str.toString("~ param.convName ~")"; 674 } 675 else if (GtkDClass.endsWith(param.typeWrap, "IF")) 676 { 677 parmToGtkD = "ObjectG.getDObject!("~param.typeWrap[0..$-2]~", "~param.typeWrap~")("~ param.convName ~")"; 678 } 679 else 680 { 681 parmToGtkD = "ObjectG.getDObject!("~param.typeWrap~")("~ param.convName ~")"; 682 } 683 } 684 else 685 { 686 parmToGtkD = param.convName; 687 } 688 689 return parmToGtkD; 690 } 691 692 string getWrapParametersType() 693 { 694 string pw; 695 foreach ( param; params ) 696 { 697 if ( pw !is null ) 698 pw ~= ","; 699 700 pw ~= param.typeWrap; 701 } 702 return pw; 703 } 704 705 /** 706 * Gets the body of the GtkD method. 707 * This include the call to the Gtk function. 708 * If the first parameter is a pointer to the struct make it implicit and use the internal struct 709 * Returns: The text of the body of the function NOT including the braces 710 */ 711 string[] bod() 712 { 713 string[] bd; /* Return variable. */ 714 string gtkCall; 715 string[] end; //Code to be added to the end of the function to wrap ref/out parameters. 716 bool wrapError = false; 717 718 void checkError() 719 { 720 if ( wrapError ) 721 { 722 bd ~= ""; 723 bd ~= "if (err !is null)"; 724 bd ~= "{"; 725 bd ~= "\tthrow new GException( new ErrorG(err) );"; 726 bd ~= "}"; 727 if ( end.length == 0 ) 728 bd ~= ""; 729 } 730 } 731 732 string construct(string type) 733 { 734 if ( convParms.outPack == "cairo" || convParms.outPack == "glib" || convParms.outPack == "gthread" ) 735 return "new "~ type; 736 else if( GtkDClass.endsWith(type, "IF") ) 737 return "ObjectG.getDObject!("~ type[0..$-2] ~", "~ type ~")"; 738 else 739 return "ObjectG.getDObject!("~ type ~")"; 740 } 741 742 /* 1st: construct the actual GTK+ call. */ 743 gtkCall ~= name ~ "("; //gtk_function( 744 745 foreach( i, param; params ) 746 { 747 debug(parm) writefln("\t(%s -> %s) %s",param.type, param.typeWrap, param.name); 748 749 if ( i > 0 ) 750 gtkCall ~= ", "; 751 752 if ( !ctor && i == 0 && params[0].type == strctPointer && !(name in convParms.array && params[0].name in convParms.array[name]) ) 753 { 754 755 if ( convParms.templ.length == 0 ) 756 { 757 gtkCall ~= GtkDClass.toVar(convParms.strct); 758 } 759 else 760 { 761 gtkCall ~= "get"~convParms.clss~"Struct()"; 762 } 763 } 764 else if ( param.typeWrap == "GError**" && convParms.strct != "GError") 765 { 766 bd ~= "GError* err = null;"; 767 768 gtkCall ~= "&err"; 769 770 wrapError = true; 771 } 772 else if ( param.typeWrap == "out string" || param.typeWrap == "ref string" ) 773 { 774 string id = param.convName; 775 776 if ( param.typeWrap == "out string" ) 777 bd ~= "char* out"~ id ~" = null;"; 778 else 779 bd ~= "char* out"~ id ~" = Str.toStringz("~ id ~");"; 780 781 gtkCall ~= "&out"~ id; 782 end ~= id ~" = Str.toString(out"~ id ~");"; 783 } 784 else if ( param.typeWrap == "out string[]" || param.typeWrap == "ref string[]" ) 785 { 786 string id = param.convName; 787 string lenid = GtkDClass.idsToGtkD(convParms.array[name][param.name], convParms, aliases); 788 789 if ( param.typeWrap == "out string[]" ) 790 bd ~= "char** out"~ id ~" = null;"; 791 else 792 bd ~= "char** out"~ id ~" = Str.toStringzArray("~ id ~");"; 793 794 if ( convParms.array[name][param.name] != "" ) 795 if ( param.typeWrap == "out string[]" ) 796 bd ~= "int "~ GtkDClass.idsToGtkD(convParms.array[name][param.name], convParms, aliases) ~";"; 797 else 798 bd ~= "int "~ GtkDClass.idsToGtkD(convParms.array[name][param.name], convParms, aliases) ~" = cast(int) "~ id ~".length;"; 799 800 gtkCall ~= "&out"~ id; 801 802 if ( lenid.length > 0 ) 803 { 804 end ~= id ~" = null;"; 805 end ~= "foreach ( cstr; out"~ id ~"[0 .. "~ lenid ~"] )"; 806 end ~= "{"; 807 end ~= " "~ id ~" ~= Str.toString(cstr);"; 808 end ~= "}"; 809 } 810 else 811 { 812 end ~= id ~" = Str.toStringArray(out"~ id ~");"; 813 } 814 } 815 else if ( (param.outParam || param.refParam) && param.arrayParam ) 816 { 817 string id = param.convName; 818 string lenid = GtkDClass.idsToGtkD(convParms.array[name][param.name], convParms, aliases); 819 820 if ( param.type[0 .. $-2] == split(param.typeWrap)[1][0 .. $-2] ) 821 { 822 if ( param.outParam ) 823 bd ~= split(param.typeWrap)[1][0 .. $-2] ~"* out"~ id ~ " = null;"; 824 else 825 bd ~= split(param.typeWrap)[1][0 .. $-2] ~"* out"~ id ~ " = "~ id ~".ptr;"; 826 827 gtkCall ~= "&out" ~ id; 828 829 bool areMultipleArrays() 830 { 831 foreach ( parm; params[i+1 .. $] ) 832 { 833 if ( parm.name in convParms.array[name] && convParms.array[name][param.name] == convParms.array[name][parm.name] ) 834 return true; 835 } 836 return false; 837 } 838 839 if ( !areMultipleArrays && params.contains(convParms.array[name][param.name]) ) 840 { 841 if (GtkDClass.startsWith(param.typeWrap, "out") ) 842 bd ~= "int "~ lenid ~";"; 843 else 844 bd ~= "int "~ lenid ~" = cast(int) "~ id ~".length;"; 845 } 846 847 if ( convParms.array[name][param.name] == "Return" ) 848 lenid = "p"; 849 850 end ~= id ~" = out"~ id ~"[0 .. " ~ lenid ~"];"; 851 } 852 else 853 { 854 if ( param.outParam ) 855 { 856 bd ~= param.type.removechars("*") ~"** out"~ id ~ " = null;"; 857 } 858 else 859 { 860 bd ~= ""; 861 bd ~= param.type.removechars("*") ~ "*[] inout"~ id ~" = new "~ param.type.removechars("*") ~"*["~ id ~".length];"; 862 bd ~= "for ( int i = 0; i < "~ id ~".length ; i++ )"; 863 bd ~= "{"; 864 bd ~= "\tinout"~ id ~"[i] = "~ id~ "[i].get"~ split(param.typeWrap)[1][0 .. $-2] ~"Struct();"; 865 bd ~= "}"; 866 bd ~= ""; 867 bd ~= param.type.removechars("*") ~ "** out"~ id ~" = inout"~ id ~".ptr;"; 868 } 869 870 gtkCall ~= "&out" ~ id; 871 872 if ( params.contains(convParms.array[name][param.name]) ) 873 { 874 if ( param.outParam ) 875 bd ~= "int "~ lenid ~";"; 876 else 877 bd ~= "int "~ lenid ~" = cast(int) "~ id ~".length;"; 878 } 879 880 if ( convParms.array[name][param.name] == "Return" ) 881 lenid = "p"; 882 883 end ~= ""; 884 end ~= id ~" = new "~ split(param.typeWrap)[1][0 .. $-2] ~"["~ lenid ~"];"; 885 end ~= "for(int i = 0; i < "~ lenid ~"; i++)"; 886 end ~= "{"; 887 end ~= "\t"~ id ~"[i] = " ~ construct(split(param.typeWrap)[1][0 .. $-2]) ~ "(cast(" ~ param.type.removechars("*") ~ "*) out"~ id ~"[i]);"; 888 end ~= "}"; 889 } 890 } 891 else if ( (param.outParam || param.refParam) && 892 param.type[0 .. $-1] != split(param.typeWrap)[1] ) 893 { 894 string id = param.convName; 895 896 if ( param.outParam ) 897 { 898 bd ~= param.type.removechars("*") ~"* out"~ id ~ " = null;"; 899 } 900 else 901 { 902 bd ~= param.type.removechars("*") ~"* out"~ id ~ " = ("~id~" is null) ? null : "~id~ ".get"~ split(param.typeWrap)[1] ~"Struct();"; 903 } 904 905 gtkCall ~= "&out" ~ id; 906 907 end ~= id ~" = "~ construct(split(param.typeWrap)[1]) ~"(out"~ id ~");"; 908 } 909 else if ( param.arrayParam && param.type[0 .. $-1] != param.typeWrap[0 .. $-2] && 910 !GtkDClass.endsWith(param.type, "[]") && param.typeWrap != "string[]" ) 911 { 912 string id = param.convName; 913 914 bd ~= ""; 915 bd ~= param.type.removechars("*") ~ "*[] "~ id ~"Array = new "~ param.type.removechars("*") ~"*["~ id ~".length];"; 916 bd ~= "for ( int i = 0; i < "~ id ~".length ; i++ )"; 917 bd ~= "{"; 918 bd ~= "\t"~ id ~"Array[i] = "~ id~ "[i].get"~ param.typeWrap[0 .. $-2] ~"Struct();"; 919 bd ~= "}"; 920 bd ~= ""; 921 922 gtkCall ~= id ~"Array.ptr"; 923 } 924 else if ( name in convParms.array && "Return" == convParms.array[name].contains(param.name) ) 925 { 926 string id = param.convName; 927 928 bd ~= GtkDClass.tokenToGtkD(param.type.chomp("*"), convParms, aliases) ~" "~ id ~";"; 929 gtkCall ~= "&"~ id; 930 } 931 else if ( param.typeWrap == "FILE*" ) //Phobos Workaround 932 { 933 gtkCall ~= "cast(void*)"~ GtkDClass.idsToGtkD(param.name, convParms, aliases); 934 } 935 else 936 { 937 if ( param.name.length > 0 ) 938 { 939 gtkCall ~= parameterToGtk(param); 940 } 941 } 942 } 943 944 gtkCall ~= ")"; //gtk_function(arg1...argN) 945 946 if ( end.length > 0 || wrapError ) 947 { 948 bd ~= ""; 949 if ( end.length > 0 ) 950 end = [""] ~ end; 951 } 952 953 /* 2nd: construct the rest of the body according to the type 954 * of the function. */ 955 if (type == "void") 956 { 957 /* If it's a void, we just need to make the call and be done 958 * with it. */ 959 gtkCall ~= ";"; 960 bd ~= gtkCall; 961 checkError(); 962 963 if ( end.length > 0 ) 964 bd ~= end; 965 966 return bd; 967 } 968 else if (type == "FILE*") //Phobos Workaround. 969 { 970 return bd ~= "return cast(FILE*)" ~ gtkCall ~ ";"; 971 } 972 else 973 { 974 /* If the call constructs an object, call the GTK+ constructor 975 * and pass the object to the wrapper's constructor. */ 976 if(ctor) 977 { 978 /*string prepend = "this(cast("; 979 if(convParms.realStrct.length > 0) 980 prepend ~= convParms.realStrct ~ "*)"; 981 else 982 prepend ~= convParms.strct ~ "*)"; 983 gtkCall = prepend ~ gtkCall*/ 984 string strct = (convParms.realStrct.length > 0) ? convParms.realStrct : convParms.strct; 985 /* Do we need a cast? */ 986 bd ~= "auto p = " ~ gtkCall ~ ";"; //GtkStruct* p = gtk_function(arg1...argN); 987 988 checkError(); 989 990 string[] check = [ "if(p is null)", 991 "{", 992 " throw new ConstructionException(\"null returned by " ~ gtkCall ~ "\");", 993 "}" ]; 994 bd ~= check; 995 996 if ( end.length > 0 ) 997 bd ~= end; 998 999 /* What's with all the casting? */ 1000 /* A; Casting is needed because some GTK+ 1001 * functions can return void pointers. */ 1002 bd ~= "this(cast(" ~ strct ~ "*) p);"; 1003 //bd ~= "this(p);"; 1004 1005 /* The body is constructed, return. */ 1006 return bd; 1007 } 1008 else 1009 { 1010 /* Non-void call. */ 1011 if(type == typeWrap ) 1012 { 1013 /* We return an object of the same type as the GTK+ function. */ 1014 //return gtk_function(arg1...argN); 1015 if ( !wrapError && end.length == 0) 1016 bd ~= "return " ~ gtkCall ~ ";"; 1017 else 1018 { 1019 bd ~= "auto p = " ~ gtkCall ~ ";"; 1020 checkError(); 1021 1022 if ( end.length > 0 ) 1023 bd ~= end; 1024 1025 if ( !(name in convParms.array && "Return" in convParms.array[name]) ) 1026 bd ~= "return p;"; 1027 } 1028 1029 return bd; 1030 } 1031 else 1032 { 1033 /* We return an object of a different type, we need to wrap it 1034 * accordingly. */ 1035 if(typeWrap == "string") 1036 { 1037 /* Returned strings get special care. */ 1038 //return Str.toString(gtk_function(arg1...argN)).dup; 1039 if ( !wrapError && !(name in convParms.array && "Return" in convParms.array[name]) ) 1040 bd ~= "return Str.toString(" ~ gtkCall ~ ");"; 1041 else 1042 { 1043 bd ~= "auto p = " ~ gtkCall ~ ";"; 1044 checkError(); 1045 1046 if ( end.length > 0 ) 1047 bd ~= end; 1048 1049 if (name in convParms.array && "Return" in convParms.array[name]) 1050 { 1051 string lenid = GtkDClass.idsToGtkD(convParms.array[name]["Return"], convParms, aliases); 1052 1053 bd ~= "return Str.toString(p, "~ lenid ~");"; 1054 } 1055 else 1056 bd ~= "return Str.toString(p);"; 1057 } 1058 1059 return bd; 1060 } 1061 else if(typeWrap == "string[]") 1062 { 1063 /* Returned strings get special care. */ 1064 //return Str.toString(gtk_function(arg1...argN)).dup; 1065 if ( !wrapError && !(name in convParms.array && "Return" in convParms.array[name]) ) 1066 bd ~= "return Str.toStringArray(" ~ gtkCall ~ ");"; 1067 else 1068 { 1069 bd ~= "\nauto p = " ~ gtkCall ~ ";"; 1070 checkError(); 1071 1072 if ( end.length > 0 ) 1073 bd ~= end; 1074 1075 if (name in convParms.array && "Return" in convParms.array[name]) 1076 { 1077 string lenid = GtkDClass.idsToGtkD(convParms.array[name]["Return"], convParms, aliases); 1078 1079 bd ~= ""; 1080 bd ~= "string[] strArray = null;"; 1081 bd ~= "foreach ( cstr; p[0 .. "~ lenid ~"] )"; 1082 bd ~= "{"; 1083 bd ~= " strArray ~= Str.toString(cstr);"; 1084 bd ~= "}"; 1085 bd ~= ""; 1086 bd ~= "return strArray;"; 1087 } 1088 else 1089 bd ~= "return Str.toStringArray(p);"; 1090 } 1091 1092 return bd; 1093 } 1094 else 1095 { 1096 /* All other objects are wrapped in their container. */ 1097 /* Why do we need a cast? */ 1098 //GtkType p = gtk_function(arg1...argN); 1099 bd ~= "auto p = " ~ gtkCall ~ ";"; 1100 1101 checkError(); 1102 1103 if ( end.length > 0 ) 1104 bd ~= end; 1105 1106 bd ~= [ "", 1107 "if(p is null)", 1108 "{", 1109 " return null;", 1110 "}", 1111 "" ]; 1112 1113 //Workaround, to support an destrutor which unrefs the Pixbuf, 1114 //These functions need to add an reference. 1115 import std.algorithm : among; 1116 if ( typeWrap == "Pixbuf" && 1117 name.among("gdk_pixbuf_animation_get_static_image", 1118 "gdk_pixbuf_animation_iter_get_pixbuf", 1119 "gdk_pixbuf_loader_get_pixbuf", 1120 "gtk_about_dialog_get_logo", 1121 "gtk_assistant_get_page_header_image", 1122 "gtk_assistant_get_page_side_image", 1123 "gtk_entry_get_icon_pixbuf", 1124 "gtk_icon_info_get_builtin_pixbuf", 1125 "gtk_image_get_pixbuf", 1126 "gtk_status_icon_get_pixbuf", 1127 "gtk_text_iter_get_pixbuf", 1128 "gtk_window_get_icon", 1129 "gtk_source_completion_proposal_get_icon", 1130 "gtk_source_completion_provider_get_icon", 1131 "gtk_source_gutter_renderer_pixbuf_get_pixbuf", 1132 "gtk_source_mark_attributes_get_pixbuf", 1133 "gtk_source_mark_attributes_render_icon") ) 1134 { 1135 bd ~= "import gtkc.gobject : g_object_ref;"; 1136 bd ~= "g_object_ref(cast(GObject*)p);"; 1137 bd ~= ""; 1138 } 1139 1140 if ( GtkDClass.endsWith(typeWrap, "[]") ) 1141 { 1142 string id = GtkDClass.idsToGtkD(convParms.array[name]["Return"], convParms, aliases); 1143 1144 if (type[0 .. $-1] == typeWrap[0 .. $-2]) 1145 { 1146 bd ~= "return p[0 .. "~ id ~"];"; 1147 } 1148 else 1149 { 1150 bd ~= typeWrap ~" arr = new "~ typeWrap[0 .. $-2] ~"["~ id ~"];"; 1151 bd ~= "for(int i = 0; i < "~ id ~"; i++)"; 1152 bd ~= "{"; 1153 bd ~= "\tarr[i] = "~ construct(typeWrap[0 .. $-2]) ~"(cast("~ type.chomp("*") ~") p[i]);"; 1154 bd ~= "}"; 1155 bd ~= ""; 1156 bd ~= "return arr;"; 1157 } 1158 } 1159 /* What's with all the casting? */ 1160 /* A; Casting is needed because some GTK+ 1161 * functions can return void pointers. */ 1162 else 1163 bd ~= "return " ~ construct(typeWrap) ~ "(cast(" ~ type ~ ") p);"; 1164 1165 return bd; 1166 } 1167 } 1168 } 1169 } 1170 1171 /* We should never reach here. */ 1172 assert(0, "A strange function body was requested."); 1173 } 1174 }