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 if ( std..string.indexOf(elem, "[") > 0 )
1881 			{
1882 				string member;
1883 				size_t space = std..string.indexOf(elem, " ");
1884 				size_t startBracket = std..string.indexOf(elem, "[");
1885 				size_t endBracket = std..string.indexOf(elem, "]");
1886 
1887 				member = elem[0..space];
1888 
1889 				if ( elem[space+1] == '*' )
1890 					member ~= "*";
1891 
1892 				member ~= elem[startBracket..endBracket+1] ~ " ";
1893 
1894 				if ( elem[space+1] == '*' )
1895 					member ~= elem[space+2..startBracket];
1896 				else
1897 					member ~= elem[space+1..startBracket];
1898 
1899 				collectedStructs ~= member ~ elem[endBracket+1..$];				
1900 			}
1901 			else
1902 			{
1903 				collectedStructs ~= elem;
1904 			}
1905 		}
1906 	}
1907 
1908 	/// hack... we don't have all types (do we?)
1909 	bool isEnum(string type)
1910 	{
1911 		if ( type == "GdkEventType" )
1912 		{
1913 			return true;
1914 		}
1915 		return false;
1916 	}
1917 
1918 	bool primitiveType(string line)
1919 	{
1920 		int p=0;
1921 		skipBlank(p, line);
1922 		string type = untilBlank(p, line);
1923 		if ( isEnum(type) )
1924 		{
1925 			return true;
1926 		}
1927 		foreach(primitive; wrapper.getAliases())
1928 		{
1929 			if(primitive == type)
1930 				return true;
1931 		}
1932 		return (type in wrapper.getAliases()) !is null;
1933 	}
1934 
1935 	public static void skipBlank(ref int p, string text)
1936 	{
1937 		while( p<text.length && text[p]<=' ' )
1938 		{
1939 			++p;
1940 		}
1941 	}
1942 
1943 	public static void skip(ref int p, string text, char s)
1944 	{
1945 		while( p<text.length && text[p]==s)
1946 		{
1947 			++p;
1948 		}
1949 	}
1950 
1951 	public static string untilBlank(ref int p, string text)
1952 	{
1953 		int start=p;
1954 		while ( p<text.length && text[p]>' ')
1955 		{
1956 			++p;
1957 		}
1958 		return text[start..p];
1959 	}
1960 
1961 	public static string untilBlank(ref int p, string text, string s)
1962 	{
1963 		int start=p;
1964 		while ( p<text.length && text[p]>' ' && std..string.indexOf(s,text[p])<0 )
1965 		{
1966 			++p;
1967 		}
1968 		return text[start..p];
1969 	}
1970 
1971 	public static string until(ref int p, string text, char s)
1972 	{
1973 		int start=p;
1974 		while ( p<text.length && text[p]!=s)
1975 		{
1976 			++p;
1977 		}
1978 		return text[start..p];
1979 	}
1980 
1981 	public static string until(ref int p, string text, string s)
1982 	{
1983 		int start=p;
1984 		while ( p<text.length && std..string.indexOf(s,text[p])<0 )
1985 		{
1986 			++p;
1987 		}
1988 		return text[start..p];
1989 	}
1990 
1991 	private string getFunctionDeclaration(ref int line, string[] lines)
1992 	{
1993 		string funct;
1994 		while ( line<lines.length
1995 				&& (!endsWith(lines[line], ");")
1996 					&& !startsWith(funct, "#define"))
1997 			)
1998 		{
1999 			funct ~= lines[line]~ " ";
2000 			debug(endFunction)writefln("funct line = >>>%s<<< endWith(\");\") = ",
2001 										lines[line],
2002 										endsWith(lines[line], ");")
2003 										);
2004 			++line;
2005 		}
2006 		if ( line<lines.length && endsWith(lines[line], ");") )
2007 		{
2008 			funct ~= lines[line++];
2009 		}
2010 
2011 		return funct;
2012 	}
2013 
2014 	/** Builds the declaration of a new method for a class, according to
2015 	 *  the information retrieved from the documentation.
2016 	 *  Params:
2017 	 *   lines = the lines containing the definition of the original GTK+
2018 	 *			 function, extracted from the documentation.
2019 	 *	 prefixes = a list of prefixes to look for in 'lines' (gtk_xxx).
2020 	 */
2021 	private string[] getFunction(string[] lines, string[] prefixes)
2022 	{
2023 		string[] member;
2024 
2025 		int line = 1;
2026 
2027 		string funct = getFunctionDeclaration(line, lines);
2028 
2029 		Funct fun = Funct(funct, convParms, wrapper.getAliases());
2030 
2031 		/**
2032 		 * Checks restrictions on the functions to include
2033 		 * Params:
2034 		 *    	lines =
2035 		 *    	prefix =
2036 		 * Returns:
2037 		 */
2038 		bool includeFunction(ConvParms* convParms)
2039 		{
2040 			bool inc = true;
2041 
2042 			int nPrefix = 0;
2043 			while ( inc && nPrefix<convParms.noPrefixes.length )
2044 			{
2045 				debug(noPrefixes)writefln("\ttest noPrefix %s ?= %s", fun.name, convParms.noPrefixes[nPrefix]);
2046 				inc = !startsWith(fun.name, convParms.noPrefixes[nPrefix++]);
2047 			}
2048 			if ( inc )
2049 			{
2050 				inc = false;
2051 
2052 				if ( convParms.containsPrefix(fun.name) )
2053 				{
2054 					debug(noPrefixes)writefln("included  by name");
2055 					inc = true;
2056 				}
2057 				else if ( convParms.strictPrefix && convParms.prefixes.length>0 )
2058 				{
2059 					debug(noPrefixes) writefln("dropped by strictPrefix");
2060 					inc = false;
2061 				}
2062 				else
2063 				{
2064 					inc = true;
2065 					debug(noPrefixes)if ( !inc) writefln("dropped by noPrefixes");
2066 				}
2067 			}
2068 			//debug(noPrefixes)writefln("%s : %s (%s)", (inc?"included":"dropped"),fun.name, convParms.prefix);
2069 			return inc;
2070 		}
2071 
2072 		if ( includeFunction(convParms) )
2073 		{
2074 			if ( funct[0] == '#' )
2075 			{
2076 				if ( !convParms.strictPrefix )
2077 				{
2078 					collectedTypes ~= "";
2079 					debug(defines)writefln("it's define: %s",funct);
2080 					// comment
2081 					if ( wrapper.includeComments() )
2082 					{
2083 						collectedTypes ~= "/*";
2084 						while ( line<lines.length )
2085 						{
2086 							collectedTypes ~= " * "~lines[line++];
2087 						}
2088 						collectedTypes ~= " */";
2089 					}
2090 					collectedTypes ~= "// TODO";
2091 					// body
2092 					collectedTypes ~= "// "~funct;
2093 				}
2094 
2095 			}
2096 			else
2097 			{
2098 				debug(functName) writefln("funct name = %s", fun.name);
2099 				if ( fun.name.length==0 || fun.name[0] == '(' )
2100 				{
2101 					if ( !convParms.isInterface )
2102 					{
2103 						if ( !convParms.strictPrefix )
2104 						{
2105 							collectedFuncts ~= "";
2106 							// comment
2107 							if ( wrapper.includeComments() )
2108 							{
2109 								collectedFuncts ~= "/*";
2110 								while ( line<lines.length )
2111 								{
2112 									collectedFuncts ~= " * "~lines[line++];
2113 								}
2114 								collectedFuncts ~= " */";
2115 								collectedFuncts ~= "// "~funct;
2116 							}
2117 							// body
2118 							string decl = getFunction(funct, convParms);
2119 							
2120 							if ( decl.length > 0 )
2121 								collectedFuncts ~= "public alias "~ decl;
2122 						}
2123 					}
2124 				}
2125 				else // the regular function
2126 				{
2127 					bool tooSoon = false;	// reject for 2.10
2128 					// comment
2129 					void addComments()
2130 					{
2131 						string[] phraseParams(string[] comments)
2132 						{
2133 							string[] description;
2134 							string[] params;
2135 							string ret;
2136 							
2137 							for(int i; i < comments.length; i++)
2138 							{
2139 								if(indexOf(comments[i], ":") == comments[i].length-1 && comments[i].chomp(":").strip() != "Returns" )
2140 								{
2141 									//Get the GtkD name of the param
2142 									string param = strip( idsToGtkD(comments[i][0 .. $-1], convParms, wrapper.getAliases()) );
2143 
2144 									//If this param is not in the Gtkd Function Skip it.
2145 									if(indexOf(fun.declaration(), param) == -1)
2146 									{
2147 										//Loop for multi line descriptons for this param.
2148 										while(i+1 < comments.length && stilInParam(comments[i+1]))
2149 											i++;
2150 										continue;
2151 									}
2152 
2153 									if(params.length == 0)
2154 										params ~= "Params:";
2155 
2156 									//Loop for multi line descriptons for this param.
2157 									bool firstRun = true;
2158 									while(i+1 < comments.length && stilInParam(comments[i+1]))
2159 									{
2160 										i++;
2161 										if(firstRun)
2162 										{
2163 											params ~= param ~" = "~ stripLeft(comments[i]);
2164 											firstRun = false;
2165 										}
2166 										else
2167 											params ~= comments[i];
2168 									}
2169 								}
2170 								else if( comments[i].chomp(":").strip() == "Returns" )
2171 								{
2172 									//Skip return for Constructors.
2173 									if(indexOf(fun.declaration(), "this (") > -1)
2174 									{
2175 										//Loop for multi line descriptons for this return.
2176 										while(i+1 < comments.length && stilInParam(comments[i+1]))
2177 											i++;
2178 										continue;
2179 									}
2180 
2181 									ret ~= "Returns:";
2182 
2183 									//Loop for multi line descriptons for this return.
2184 									bool firstRun = true;
2185 									while(i+1 < comments.length && stilInParam(comments[i+1]))
2186 									{
2187 										i++;
2188 										ret ~= " " ~ comments[i].strip();
2189 									}
2190 								}
2191 								else if(indexOf(comments[i], "See Also") == 0 || indexOf(comments[i], "Property Details") == 0)
2192 								{
2193 									//These sections get included with the last function.
2194 									break;
2195 								}
2196 								else
2197 								{
2198 									//Add the rest to the description.
2199 									description ~= comments[i];
2200 								}
2201 							}
2202 
2203 							if(params.length > 0)
2204 							{
2205 								foreach(string line; params)
2206 									description ~= line;
2207 							}
2208 
2209 							if(ret.length > 0)
2210 								description ~= ret;
2211 
2212 							if ( indexOf(fun.getExternal(), "GError**") > -1
2213 								 && indexOf(fun.declaration(), "Error") == -1 )
2214 							{
2215 								description ~= "Throws: GException on failure.";
2216 							}
2217 
2218 							if ( indexOf(fun.declaration(), "this (") > -1 )
2219 							{
2220 								description ~= "Throws: ConstructionException GTK+ fails to create the object.";
2221 							}
2222 
2223 							return description;
2224 						}
2225 
2226 						if ( wrapper.includeComments() )
2227 						{
2228 							string[] comments;
2229 							while ( line<lines.length )
2230 							{
2231 								//if ( !tooSoon )
2232 								//{
2233 								//	tooSoon = lines[line]=="Since 2.10";
2234 								//}
2235 								comments ~= lines[line++];
2236 							}
2237 
2238 							member ~= "/**";
2239 
2240 							comments = phraseParams(comments);
2241 							foreach(string line; comments)
2242 								member ~= " * "~ line;
2243 
2244 							member ~= " */";
2245 						}
2246 					}
2247 
2248 					if ( tooSoon )
2249 					{
2250 						addComments();
2251 						member ~= "// next release";
2252 					}
2253 					else
2254 					{
2255 						if ( !convParms.isInterface )
2256 						{
2257 							string externalDeclaration = fun.getExternal();
2258 							
2259 							/* Don't add repeated declarations. */
2260 							bool addme = true;
2261 												                
2262 							foreach(ref string declaration; externalDeclarations)
2263 							{
2264 								if(externalDeclaration == declaration){ addme = false; break; }
2265 							}
2266 
2267 							if(addme) externalDeclarations ~= externalDeclaration;
2268 						}
2269 						// body
2270 						if ( !convParms.omitCode(fun.name) && indexOf(fun.declaration(), "...") < 0 )
2271 						{
2272 							string gtkDDeclaration = fun.declaration();
2273 							//string gtkDDeclaration = stringToGtkD(rawDeclaration,convParms,wrapper.getAliases());
2274 							debug(declaration) writefln("Declaration\n\t%s\n\t%s",rawDeclaration, gtkDDeclaration);
2275 							addComments();
2276 							member ~= gtkDDeclaration~iFaceChar;
2277 							if ( !convParms.isInterface )
2278 							{
2279 								member ~= "{";
2280 								member ~= "// "~funct;
2281 								member ~= fun.bod();
2282 								member ~= "}";
2283 							}
2284 							/* Duplicated functions are omitted. */
2285 							if(checkIfDupFunction(fun)) member.length = 0;
2286 							checkIfGtkStructs(fun);
2287 						}
2288 					}
2289 				}
2290 			}
2291 		}
2292 
2293 		return member;
2294 	}
2295 
2296 	private bool checkIfDupFunction(Funct fun)
2297 	{
2298 		string signature = fun.convName~'('~fun.getWrapParametersType()~')';
2299 		if ( signature in functionSignatures )
2300 		{
2301 			writefln("######################## duplicated function %s", signature);
2302 			return true;
2303 		}
2304 		else
2305 		{
2306 			functionSignatures[signature] = 1;
2307 			return false;
2308 		}
2309 	}
2310 
2311 	/*
2312 	 * Checks if the current line is still part of the param description.
2313 	 * it does this by checking for things not normaly in the param description
2314 	 * Params:
2315 	 *  comments = Line to check.
2316 	 * Returns: true if we are still in the description of the param.
2317 	 */
2318 	bool stilInParam(string comments)
2319 	{
2320 		return !(indexOf(comments, ":")  == comments.length-1 ||
2321 						 comments.chomp(":").strip() == "Returns" ||
2322 						 ( indexOf(comments, "Since 2.") == 0 || indexOf(comments, "Since 1.") == 0) ||
2323 						 indexOf(comments, "See Also") == 0 ||
2324 						 indexOf(comments, "Property Details") == 0 ||
2325 						 comments == "<hr>");
2326 	}
2327 
2328 	/**
2329 	 * Prints out the potential Gtk struct to be wrapped
2330 	 * so that the wrap parameter can be set on the APILookupXXX.txt
2331 	 * TODO assume all structs are to be wrapped an explicitly declare the ones not to be wrapped
2332 	 * Params:
2333 	 *    	fun =
2334 	 */
2335 	private void checkIfGtkStructs(Funct fun)
2336 	{
2337 		bool found = false;
2338 		void check(string type)
2339 		{
2340 			if ( startsWith(type, 'G')
2341 					&& endsWith(type, '*')
2342 				)
2343 			{
2344 				if ( type in gtkStructs )
2345 				{
2346 					// nothing
2347 				}
2348 				else
2349 				{
2350 					found = true;
2351 					gtkStructs[type] = 1;
2352 					//writefln("######################## Gtk struct found %s\t\t%s",
2353 					//		type,
2354 					//		fun.convName~"("~fun.getWrapParametersType()~")"
2355 					//		);
2356 
2357 					string strct = type;
2358 					string dName = "";
2359 					string pack = "";
2360 					if ( startsWith(strct, "Gtk") )
2361 					{
2362 						pack = "gtk";
2363 						dName = strct[3..strct.length-1];
2364 						//dName[0] = std.ascii.toLower(dName[0]);
2365 					}
2366 					else if ( startsWith(strct, "Gdk") )
2367 					{
2368 						pack = "gdk";
2369 						dName = strct[3..strct.length-1];
2370 						//dName[0] = std.ascii.toLower(dName[0]);
2371 						if ( dName ==  "Pixbuf") pack = "gdkpixbuf";
2372 					}
2373 					else if ( startsWith(strct, "Gst") )
2374 					{
2375 						pack = "gstreamer";
2376 						dName = strct[3..strct.length-1];
2377 						//dName[0] = std.ascii.toLower(dName[0]);
2378 					}
2379 					else if ( startsWith(strct, "G") )
2380 					{
2381 						dName = strct[1..strct.length-1];
2382 						switch ( dName )
2383 						{
2384 							case "Object":
2385 
2386 								if ( pack == "g" )
2387 								{
2388 									pack = "gobject"; dName = "ObjectG";
2389 								}
2390 								else if ( pack == "gdk" )
2391 								{
2392 									dName = "ObjectG";
2393 								}
2394 								else if ( pack == "gtk" )
2395 								{
2396 									dName = "ObjectGtk";
2397 								}
2398 								else if ( pack == "gstreamer" )
2399 								{
2400 									dName = "ObjectGst";
2401 								}
2402 								else if ( pack == "atk" )
2403 								{
2404 									dName = "ObjectAtk";
2405 								}
2406 								break;
2407 							case "Closure": pack = "gobject"; break;
2408 							case "Type": pack = "gobject"; break;
2409 							case "Value": pack = "gobject"; break;
2410 							case "List": pack = "glib"; dName = "ListG"; break;
2411 							case "SList": pack = "glib"; dName = "ListSG"; break;
2412 							case "String": pack = "glib"; dName = "StringG"; break;
2413 							case "IOChannel": pack = "glib"; break;
2414 							case "Quark": pack = "glib"; break;
2415 							case "ParmSpec": pack = "gobject"; break;
2416 							case "TypeModule": pack = "gobject"; break;
2417 							case "Flags": pack = "gobject"; break;
2418 							case "Enums": pack = "gobject"; break;
2419 							default:
2420 								pack = "g";
2421 								break;
2422 						}
2423 					}
2424 					debug(structs)writefln("import: %s.%s", pack, dName);
2425 					debug(structs)writefln("structWrap: %s %s", strct, dName);
2426 				}
2427 			}
2428 		}
2429 
2430 		if ( !fun.ctor
2431 			&& !endsWith(fun.convName, "Struct")
2432 			)
2433 		{
2434 			check(fun.typeWrap);
2435 		}
2436 		foreach ( count , param ; fun.params )
2437 		{
2438 			if ( count > 0 || param.typeWrap != convParms.strct~'*' )
2439 			{
2440 				check(param.typeWrap);
2441 			}
2442 		}
2443 	}
2444 
2445 	/**
2446 	 * Params:
2447 	 *    	line = 	The API line of the function
2448 	 *    	convParms = 	the Conversion parameters
2449 	 * Returns:
2450 	 */
2451 	private string getFunction(string line, ConvParms* convParms)
2452 	{
2453 		debug(functionType) writefln("\ngetFunction line = %s", line);
2454 		// void (*GChildWatchFunc) (GPid pid,  gint status,  gpointer data);
2455 		// public typedef extern(C) void function(int, int, void*) GChildWatchFunc;
2456 
2457 
2458 
2459 		string f = "extern(C) ";
2460 		int pos = 0;
2461 		string type = until(pos, line, "(");
2462 		until(pos, line, "*");
2463 		skip(pos, line, '*');
2464 		string name = until(pos, line, ")");
2465 		if (convParms.omitCode(name)) {
2466 			return "";
2467 		}
2468 
2469 		f ~= stringToGtkD(type, convParms, wrapper.getAliases()).strip();
2470 		f ~= " function(";
2471 
2472 		until(pos, line, "(");
2473 		skip(pos, line, '(');
2474 		skipBlank(pos, line);
2475 
2476 		string sourceParms = std..string.strip(until(pos, line, ")"));
2477 		string parms;
2478 
2479 		if ( sourceParms != "void" )
2480 		{
2481 			int sPos = 0;
2482 			int count = 0;
2483 			debug(functionType) writefln("sourceParms = %s", sourceParms);
2484 			while ( sPos < sourceParms.length )
2485 			{
2486 				skipBlank(sPos, sourceParms);
2487 				debug(functionType)writefln("parms sPos=%s [%s]",sPos, sourceParms[sPos..sourceParms.length]);
2488 				if (count++ > 0 )
2489 				{
2490 					parms ~= ", ";
2491 				}
2492 				string pType = untilBlank(sPos, sourceParms);
2493 				fixType(pType, sPos, sourceParms);
2494 
2495 				string pName = until(sPos, sourceParms, ",)");
2496 
2497 				debug(parmType)writefln("\tParameter type before = %s", pType);
2498 				debug(parmName)writefln("\tParameter name before = %s", pName);
2499 				adjustTypeName(pType, pName);
2500 				debug(parmType)writefln("\tParameter type after = %s", pType);
2501 				debug(parmName)writefln("\tParameter name after = %s", pName);
2502 
2503 				parms ~= tokenToGtkD(pType, convParms, wrapper.getAliases()) ~" "~ idsToGtkD(pName, convParms, wrapper.getAliases());
2504 				++sPos;
2505 			}
2506 		}
2507 
2508 		if ( name == "ref" )
2509 			 name = "doref";
2510 
2511 		f ~= parms ~ ") " ~ name ~ ";";
2512 
2513 		return f;
2514 	}
2515 
2516 	/**
2517 	 * Wraps a set of lines in the block documentation comment
2518 	 * Returns: The comment formated for D block documentation comment
2519 	 */
2520 	private string[] getDescription()
2521 	{
2522 		string[] desc;
2523 		desc ~= "";
2524 		desc ~= tabs ~ "/**";
2525 		string[] block = getBlock ("Description", "Details");
2526 		foreach ( string line; block )
2527 		{
2528 			if( startsWith(line, "--") && endsWith(line, "--") )
2529 				line = std.array.replace(line, "-", "_");
2530 
2531 			desc ~= " * " ~ line;
2532 		}
2533 		desc ~= tabs ~ " */";
2534 
2535 		return desc;
2536 
2537 	}
2538 
2539 	/**
2540 	 * Finds a block of lines delimited by the marker lines from the start of the text
2541 	 * Params:
2542 	 *    	startLine = 	The Start marker line
2543 	 *    	endLine = 		The end marker line
2544 	 * Returns: The block os lines
2545 	 */
2546 	private string[] getBlock(string startLine, string endLine)
2547 	{
2548 		currLine = 0;
2549 
2550 		debug(getBlock) writefln("getBlock for ]%s,%s[", startLine, endLine);
2551 
2552 		// TODO use slicing instead of this array
2553 		string[] block;
2554 
2555 		while ( currLine<inLines.length && inLines[currLine]!=startLine )
2556 		{
2557 			debug(getBlock) writefln("-\t\t[%s]%s",currLine,inLines[currLine]);
2558 			++currLine;
2559 		}
2560 
2561 		return getUntil(endLine);
2562 	}
2563 
2564 	private int moveToBlockStart(string startLine, string[] inLines)
2565 	{
2566 		int startPos = 0;
2567 		while ( startPos < inLines.length && inLines[startPos]!= startLine )
2568 		{
2569 			++startPos;
2570 		}
2571 		return startPos;
2572 	}
2573 
2574 	/**
2575 	 * Gets all the non empty lines until a marker line
2576 	 * Params:
2577 	 *    	endLine = 	the marker line
2578 	 * Returns:
2579 	 */
2580 	private string[] getUntil(string endLine)
2581 	{
2582 		bool end = false;
2583 
2584 		string[] block;
2585 
2586 		while ( currLine < inLines.length && !end )
2587 		{
2588 			if ( inLines[currLine] == endLine )
2589 			{
2590 				end = true;
2591 				debug(getUntil) writefln("getBlock end at line %s",currLine,"\n");
2592 			}
2593 			else
2594 			{
2595 				if ( std..string.strip(inLines[currLine]).length > 0 )
2596 				{
2597 					block ~= inLines[currLine];
2598 				}
2599 				debug(getUntil) writefln("+[%s]%s",currLine,inLines[currLine]);
2600 			}
2601 			++currLine;
2602 		}
2603 		return block;
2604 	}
2605 
2606 	/**
2607 	 * Gets all the non empty lines until a marker line
2608 	 * Params:
2609 	 *    	endLine = 	the marker line
2610 	 * Returns:
2611 	 */
2612 	private string[] getUntil(string endLine, string[] lines)
2613 	{
2614 		bool end = false;
2615 		int currLine;
2616 
2617 		string[] block;
2618 
2619 		while ( currLine < lines.length && !end )
2620 		{
2621 			if ( lines[currLine] == endLine )
2622 			{
2623 				end = true;
2624 				debug(getUntil) writefln("getBlock end at line %s",currLine,"\n");
2625 			}
2626 			else
2627 			{
2628 				if ( std..string.strip(lines[currLine]).length > 0 )
2629 				{
2630 					block ~= lines[currLine];
2631 				}
2632 				debug(getUntil) writefln("+[%s]%s",currLine,lines[currLine]);
2633 			}
2634 			++currLine;
2635 		}
2636 		return block;
2637 	}
2638 
2639 	/**
2640 	 * Converts a GTK strin to a GtkD string.
2641 	 * This removes the "_" and capitalises the next letter and converts the basic types
2642 	 * Params:
2643 	 *    	gString =
2644 	 * Returns:
2645 	 */
2646 	public static string stringToGtkD(string gString, ConvParms* convParms, string[string] aliases, bool caseConvert=true)
2647 	{
2648 		string converted;
2649 
2650 		int pos = 0 ;
2651 		string seps = " \n\r\t\f\v()[]*,;";
2652 
2653 		char c = ' ';
2654 		char pc;
2655 		int start = 0;
2656 		int end = 0;
2657 		while ( pos < gString.length )
2658 		{
2659 			pc = c;
2660 			c = gString[pos];
2661 			if ( std..string.indexOf(seps,c) >= 0 )
2662 			{
2663 				end = pos;
2664 				converted ~= tokenToGtkD(gString[start..end], convParms, aliases, caseConvert);
2665 				if ( c=='*' )
2666 				{
2667 					//if ( pc==' ' )
2668 					//{
2669 					//	converted.length = converted.length-1;
2670 					//}
2671 					//converted ~= "[] ";
2672 					converted ~= c;
2673 
2674 				}
2675 				else if ( c<=' ' )
2676 				{
2677 					if ( converted.length >0 && converted[converted.length-1] != ' ' )
2678 					{
2679 						converted ~= ' ';
2680 					}
2681 					c = ' ';
2682 				}
2683 				else
2684 				{
2685 					converted ~= c;
2686 				}
2687 				start = pos+1;
2688 			}
2689 			++pos;
2690 		}
2691 		if ( pos > start )
2692 		{
2693 			converted ~= tokenToGtkD(gString[start..pos], convParms, aliases, caseConvert);
2694 		}
2695 		return converted;
2696 	}
2697 
2698 
2699 	public static string idsToGtkD(string gToken, ConvParms* convParms, string[string] aliases, bool caseConvert=true)
2700 	{
2701 		string converted = tokenToGtkD(gToken, convParms, aliases, caseConvert);
2702 		switch ( converted )
2703 		{
2704 			case "alias" : converted = "alia"; break;
2705 			case "class" : converted = "clss"; break;
2706 			case "interface" : converted = "intrface"; break;
2707 			case "debug" : converted = "dbug"; break;
2708 			case "version" : converted = "vrsion"; break;
2709 			case "out" : converted = "f_out"; break;
2710 			case "in" : converted = "f_in"; break;
2711 			case "inout" : converted = "f_inout"; break;
2712 			//case "ref" : converted = "doref"; break; // TODO why wasn't this converted from the alias on APILookup.txt
2713 			default:
2714 				// done
2715 				break;
2716 		}
2717 		return converted;
2718 	}
2719 
2720 	/**
2721 	 * Convert for normal GtkD conversion and after verifies if is necessary to use a enumType for references enum values
2722 	 * Params:
2723 	 *    	enumType =
2724 	 *    	gToken =
2725 	 *    	convParms =
2726 	 *    	aliases =
2727 	 *    	caseConvert =
2728 	 * Returns:
2729 	 */
2730 	public static string enumToGtkD(string enumType, string gToken, ConvParms* convParms, WrapperIF wrapper, bool caseConvert=true)
2731 	{
2732 		debug(enumToGtkD)writefln("enumLine (%s) BEFORE %s", enumType, gToken);
2733 		string converted = stringToGtkD(gToken, convParms, wrapper.getAliases());
2734 
2735 		sizediff_t pos = std..string.indexOf(converted, '=');
2736 		debug(enumToGtkD)writefln("\t pos = %s", pos);
2737 		if ( pos > 0 )
2738 		{
2739 			string refValue = std..string.strip(converted[pos+1..converted.length]);
2740 			converted = converted[0..pos+1]~ " ";
2741 
2742 			debug(enumToGtkD)writefln("\t refValue = %s", refValue);
2743 			bool needComa = false;
2744 			if ( endsWith(refValue, ',') )
2745 			{
2746 				refValue = std..string.strip(refValue[0..refValue.length-1]);
2747 				needComa = true;
2748 			}
2749 
2750 			debug(enumToGtkD)writefln("\t refValue = %s", refValue);
2751 
2752 			debug(enumToGtkD)
2753 			{
2754 				foreach(string key ; wrapper.getEnumTypes().keys)
2755 				{
2756 					writefln("\t\t [%s] = %s", key, wrapper.getEnumTypes()[key]);
2757 				}
2758 			}
2759 
2760 			if ( std..string.indexOf(refValue, ' ') > 0 && std..string.indexOf(refValue, '<') > 0 )
2761 			{
2762 				string[] parts = std..string.split(refValue);
2763 
2764 				foreach ( part; parts )
2765 				{
2766 					if ( startsWith(part, "(") )
2767 					{
2768 						converted ~= "(";
2769 						part = part[1 .. $];
2770 					}
2771 
2772 					if ( part in wrapper.getEnumTypes() )
2773 					{
2774 						part = wrapper.getEnumTypes()[part] ~" ";
2775 					}
2776 					else if ( std..string.indexOf(part, "<<") > 0 )
2777 					{
2778 						string[] values = std..string.split(part, "<<");
2779 
2780 						if ( values[0] in wrapper.getEnumTypes() )
2781 							values[0] = wrapper.getEnumTypes()[values[0]];
2782 						if ( values[1] in wrapper.getEnumTypes() )
2783 							values[1] = wrapper.getEnumTypes()[values[1]];
2784 
2785 						part = values[0] ~" << "~ values[1] ~ " ";
2786 					}
2787 
2788 					converted ~= part ~" ";
2789 				}
2790 			}
2791 			else if ( refValue in wrapper.getEnumTypes() )
2792 			{
2793 				converted ~= wrapper.getEnumTypes()[refValue];
2794 			}
2795 			else
2796 			{
2797 				converted ~= refValue;
2798 			}
2799 
2800 			converted = std..string.stripRight(converted);
2801 
2802 			if (needComa)
2803 				converted ~= ",";
2804 		}
2805 		debug(enumToGtkD)writefln("enumLine (%s) AFTER  %s", enumType, converted);
2806 
2807 		return converted;
2808 	}
2809 
2810 	/**
2811 	 * Converts a GTK token to a Dui token
2812 	 * This removes the "_" and capitalises the next letter and converts the basic types.
2813 	 * Doesn't do it if it's cairo name
2814 	 * Params:
2815 	 *    	gToken =
2816 	 * Returns:
2817 	 */
2818 	public static string tokenToGtkD(string gToken, ConvParms* convParms, string[string] aliases, bool caseConvert=true)
2819 	{
2820 		string converted;
2821 
2822 		debug(tokenToGtkD) writefln("gToken=>>>%s<<<", gToken);
2823 
2824 		if ( (aliases !is null) && (gToken in aliases) )
2825 		{
2826 			converted = aliases[gToken];
2827 		}
2828 		else if ( (convParms.aliases !is null) && (gToken in convParms.aliases) )
2829 		{
2830 			converted = convParms.aliases[gToken];
2831 		}
2832 		else if ( endsWith(gToken, "_t") && startsWith(gToken,"cairo_") )
2833 		{
2834 			converted = gToken;
2835 		}
2836 		else if ( endsWith(gToken, "_t*") && startsWith(gToken,"cairo_") )
2837 		{
2838 			converted = gToken;
2839 		}
2840 		else if ( endsWith(gToken, "_t**") && startsWith(gToken,"cairo_") )
2841 		{
2842 			converted = gToken;
2843 		}
2844 		else if ( startsWith(gToken,"f_") && (endsWith(gToken,"_out") || endsWith(gToken,"_in") || endsWith(gToken,"_inout") ) )
2845 		{
2846 			converted = gToken;
2847 		}
2848 		else if ( caseConvert )
2849 		{
2850 			converted = gToken.removePrefix(convParms).removeUnderscore();
2851 			// do it again after the gToken is converted
2852 			if ( (aliases !is null) && (converted in aliases) )
2853 			{
2854 				converted = aliases[converted];
2855 			}
2856 		}
2857 		else
2858 		{
2859 			converted = gToken;
2860 		}
2861 
2862 		debug(tokenToGtkD) writefln("converted=>>>%s<<<\n", converted);
2863 
2864 		return converted;
2865 	}
2866 
2867 
2868 
2869 	/**
2870 	 * Moves '*' and 'const' and trailing '[]' from the name to the type token
2871 	 * Params:
2872 	 *    	type =
2873 	 *    	name =
2874 	 */
2875 	public static void adjustTypeName(ref string type, ref string name)
2876 	{
2877 		debug(type)writefln("type before %s", type);
2878 		debug(name)writefln("name before %s", name);
2879 		name = std..string.strip(name);
2880 		while ( name.length > 0
2881 				&& (GtkDClass.startsWith(name,"const") || name[0] == '*'
2882 				|| GtkDClass.startsWith(name,"G_GNUC_MAY_ALIAS") )
2883 				)
2884 		{
2885 			if ( name[0] == '*' )
2886 			{
2887 				type = type ~ '*';
2888 				name = std..string.strip(name[1..name.length]);
2889 			}
2890 			else if (GtkDClass.startsWith(name,"const"))
2891 			{
2892 				name = std..string.strip(name[5..name.length]);
2893 			}
2894 			else
2895 			{
2896 				name = std..string.strip(name[16..name.length]);
2897 			}
2898 			name = std..string.strip(name);
2899 		}
2900 		while ( GtkDClass.endsWith(name, "[]") )
2901 		{
2902 			type ~= "*";
2903 			name = std..string.strip(name[0..name.length-2]);
2904 		}
2905 		debug(type)writefln("type after %s", type);
2906 		debug(name)writefln("name after %s", name);
2907 	}
2908 
2909 	/**
2910 	 * Consumes "const" and "unsigned" adding "u" to the type when "unsigned" is found
2911 	 * (? uchar will become just char)
2912 	 * Params:
2913 	 *    	type =
2914 	 *    	p =
2915 	 *    	text =
2916 	 */
2917 	public static void fixType(ref string type, ref int p, ref string text)
2918 	{
2919 		if ( type == "const" || type == "struct" )
2920 		{
2921 			GtkDClass.skipBlank(p, text);
2922 			type = untilBlank(p, text);
2923 		}
2924 		if ( type == "unsigned" )
2925 		{
2926 			GtkDClass.skipBlank(p, text);
2927 			type = "u" ~ untilBlank(p, text);
2928 		}
2929 		if ( startsWith(type, "_") )
2930 		{
2931 			type = type[1..$];
2932 		}
2933 //		if ( type == "uchar" )
2934 //		{
2935 //			type = "char";
2936 //		}
2937 	}
2938 
2939 
2940 
2941 
2942 	public static bool startsWith(string str, string prefix)
2943 	{
2944 		return str.length >= prefix.length
2945 				&& str[0..prefix.length] == prefix;
2946 	}
2947 
2948 	public static bool startsWith(string str, char prefix)
2949 	{
2950 		return str.length > 0
2951 				&& str[0] == prefix;
2952 	}
2953 
2954 	public static bool endsWith(string str, string suffix)
2955 	{
2956 		return str.length >= suffix.length
2957 				&& str[str.length-suffix.length..str.length] == suffix;
2958 	}
2959 
2960 	public static bool endsWith(string str, char suffix)
2961 	{
2962 		return str.length >= 1
2963 				&& str[str.length-1] == suffix;
2964 	}
2965 
2966 }
2967 	
2968 string removePrefix(string gToken, string prefix)
2969 {
2970 	if ( startsWith(gToken, prefix) )
2971 	{
2972 		return gToken[prefix.length..gToken.length];
2973 	}
2974 	return gToken;
2975 }
2976 
2977 string removePrefix(string gToken, ConvParms* convParms)
2978 {
2979 	//debug(tokenToGtkD) writefln("gToken.length > prefix.length %s",gToken.length > convParms.prefix.length);
2980 	string prefix = convParms.getPrefix(gToken);
2981 	if ( prefix.length > 0 )
2982 	{
2983 		return gToken[prefix.length..gToken.length];
2984 	}
2985 
2986 	return gToken;
2987 
2988 }
2989 
2990 string removeUnderscore(string gToken)
2991 {
2992 	string converted;
2993 
2994 	char c = ' ';
2995 	char pc = ' ';
2996 	char ppc = ' ';
2997 	int pos = 0;
2998 	while ( pos < gToken.length )
2999 	{
3000 		c = gToken[pos];
3001 		if ( pc == '_' )
3002 		{
3003 			c = to!char(std.ascii.toUpper(c));
3004 		}
3005 		else if ( c == '_' && std.ascii.isLower(pc) )
3006 		{
3007 			pc = c;
3008 			c = '\0';
3009 		}
3010 
3011 		if ( c > '\0' )
3012 		{
3013 			if ( ppc == '_'
3014 					&& pc == 'g'
3015 					&& c == 'l'
3016 					&& gToken.length-1 > pos
3017 					&& gToken[pos+1] == '_'
3018 				 )
3019 			{
3020 				c = 'L';
3021 			}
3022 			ppc = pc;
3023 			pc = gToken[pos];
3024 			converted ~= c;
3025 		}
3026 		++pos;
3027 	}
3028 	return converted;
3029 }
3030