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