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