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