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