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