1 /*
2  * This file is part of gir-to-d.
3  *
4  * gir-to-d 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.
8  *
9  * gir-to-d is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with gir-to-d.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 module gtd.GirField;
19 
20 import std.algorithm: among, endsWith;
21 import std.conv;
22 import std.range;
23 import std.string: splitLines, strip;
24 
25 import gtd.Log;
26 import gtd.GirFunction;
27 import gtd.GirStruct;
28 import gtd.GirType;
29 import gtd.GirWrapper;
30 import gtd.XMLReader;
31 
32 final class GirField
33 {
34 	string name;
35 	string doc;
36 	GirType type;
37 	int bits = -1;
38 	bool writable = false;
39 	bool isLength = false;   ///This field holds the length of an other field.
40 	bool noProperty = false; ///Don't generate a property for this field.
41 
42 	GirFunction callback;
43 	GirUnion gtkUnion;
44 	GirStruct gtkStruct;
45 
46 	GirWrapper wrapper;
47 	GirStruct strct;
48 
49 	this(GirWrapper wrapper, GirStruct strct)
50 	{
51 		this.wrapper = wrapper;
52 		this.strct = strct;
53 	}
54 
55 	void parse(T)(XMLReader!T reader)
56 	{
57 		name = reader.front.attributes["name"];
58 
59 		if ( "bits" in reader.front.attributes )
60 			bits = to!int(reader.front.attributes["bits"]);
61 		if ( auto write = "writable" in reader.front.attributes )
62 			writable = *write == "1";
63 
64 		//TODO: readable private?
65 
66 		reader.popFront();
67 
68 		while( !reader.empty && !reader.endTag("field") )
69 		{
70 			if ( reader.front.type == XMLNodeType.EndTag )
71 			{
72 				reader.popFront();
73 				continue;
74 			}
75 
76 			switch(reader.front.value)
77 			{
78 				case "doc":
79 					reader.popFront();
80 					doc ~= reader.front.value;
81 					reader.popFront();
82 					break;
83 				case "doc-deprecated":
84 					reader.popFront();
85 					doc ~= "\n\nDeprecated: "~ reader.front.value;
86 					reader.popFront();
87 					break;
88 				case "array":
89 				case "type":
90 					type = new GirType(wrapper);
91 					type.parse(reader);
92 					break;
93 				case "callback":
94 					callback = new GirFunction(wrapper, strct);
95 					callback.parse(reader);
96 					break;
97 				case "source-position":
98 					reader.skipTag();
99 					break;
100 				default:
101 					warning("Unexpected tag: ", reader.front.value, " in GirField: ", name, reader);
102 			}
103 			reader.popFront();
104 		}
105 	}
106 
107 	/**
108 	 * A special case for fields, we need to know about all of then
109 	 * to properly construct the bitfields.
110 	 */
111 	static string[] getFieldDeclarations(GirField[] fields, GirWrapper wrapper)
112 	{
113 		string[] buff;
114 		int bitcount;
115 
116 		void endBitfield()
117 		{
118 			//AFAIK: C bitfields are padded to a multiple of sizeof uint.
119 			int padding = 32 - (bitcount % 32);
120 
121 			if ( padding > 0 && padding < 32)
122 			{
123 				buff[buff.length-1] ~= ",";
124 				buff ~= "uint, \"\", "~ to!string(padding);
125 				buff ~= "));";
126 			}
127 			else
128 			{
129 				buff ~= "));";
130 			}
131 
132 			bitcount = 0;
133 		}
134 
135 		foreach ( field; fields )
136 		{
137 			if ( field.callback )
138 			{
139 				if ( bitcount > 0 )
140 					endBitfield();
141 				buff ~= field.callback.getFunctionPointerDeclaration();
142 				continue;
143 			}
144 
145 			if ( field.gtkUnion )
146 			{
147 				if ( bitcount > 0 )
148 					endBitfield();
149 				buff ~= field.gtkUnion.getUnionDeclaration();
150 				continue;
151 			}
152 
153 			if ( field.gtkStruct )
154 			{
155 				if ( bitcount > 0 )
156 					endBitfield();
157 				buff ~= field.gtkStruct.getStructDeclaration();
158 				buff ~= stringToGtkD(field.gtkStruct.cType ~" "~ field.gtkStruct.name ~";", wrapper.aliasses);
159 				continue;
160 			}
161 
162 			if ( field.bits > 0 )
163 			{
164 				if ( bitcount == 0 )
165 				{
166 					buff ~= "import std.bitmanip: bitfields;";
167 					buff ~= "mixin(bitfields!(";
168 				}
169 				else
170 				{
171 					buff[buff.length-1] ~= ",";
172 				}
173 
174 				bitcount += field.bits;
175 				buff ~= stringToGtkD(field.type.cType ~", \""~ field.name ~"\", "~ to!string(field.bits), wrapper.aliasses);
176 				continue;
177 			}
178 			else if ( bitcount > 0)
179 			{
180 				endBitfield();
181 			}
182 
183 			if ( field.doc !is null && wrapper.includeComments && field.bits < 0 )
184 			{
185 				buff ~= "/**";
186 				foreach ( line; field.doc.splitLines() )
187 					buff ~= " * "~ line.strip();
188 				buff ~= " */";
189 			}
190 
191 			string dType;
192 
193 			if ( field.type.size == -1 )
194 			{
195 				if ( field.type.cType.empty )
196 					dType = stringToGtkD(field.type.name, wrapper.aliasses, false);
197 				else
198 					dType = stringToGtkD(field.type.cType, wrapper.aliasses, false);
199 			}
200 			else if ( field.type.elementType.cType.empty )
201 			{
202 				//Special case for GObject.Value.
203 				dType = stringToGtkD(field.type.elementType.name, wrapper.aliasses, false);
204 				dType ~= "["~ to!string(field.type.size) ~"]";
205 			}
206 			else
207 			{
208 				dType = stringToGtkD(field.type.elementType.cType, wrapper.aliasses, false);
209 				dType ~= "["~ to!string(field.type.size) ~"]";
210 			}
211 
212 			buff ~= dType ~" "~ tokenToGtkD(field.name, wrapper.aliasses) ~";";
213 		}
214 
215 		if ( bitcount > 0)
216 		{
217 			endBitfield();
218 		}
219 
220 		return buff;
221 	}
222 
223 	string[] getProperty()
224 	{
225 		string[] buff;
226 
227 		if ( !writable || isLength || noProperty )
228 			return null;
229 
230 		writeDocs(buff);
231 		writeGetter(buff);
232 
233 		buff ~= "";
234 		if ( wrapper.includeComments )
235 			buff ~= "/** Ditto */";
236 
237 		writeSetter(buff);
238 
239 		return buff;
240 	}
241 
242 	private void writeGetter(ref string[] buff)
243 	{
244 		GirStruct dType;
245 		string dTypeName;
246 
247 		if ( type.isArray() )
248 			dType = strct.pack.getStruct(type.elementType.name);
249 		else if ( auto dStrct = strct.pack.getStruct(strct.structWrap.get(type.name, "")) )
250 			dType = dStrct;
251 		else
252 			dType = strct.pack.getStruct(type.name);
253 
254 		if ( dType )
255 		{
256 			if ( dType.name in strct.structWrap )
257 				dTypeName = strct.structWrap[dType.name];
258 			else if ( dType.type == GirStructType.Interface )
259 				dTypeName = dType.name ~"IF";
260 			else
261 				dTypeName = dType.name;
262 		}
263 
264 		if ( type.isString() )
265 		{
266 			if ( type.isArray() && type.elementType.isString() )
267 			{
268 				buff ~= "public @property string["~ ((type.size > 0)?type.size.to!string:"") ~"] "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"()";
269 				buff ~= "{";
270 
271 				if ( type.length > -1 )
272 					buff ~= "return Str.toStringArray("~ strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~", "~ getLengthID(strct) ~");";
273 				else if ( type.size > 0 )
274 				{
275 					buff ~= "string["~ type.size.to!string ~"] arr;";
276 					buff ~= "foreach( i, str; "~ strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~" )";
277 					buff ~= "{";
278 					buff ~= "arr[i] = Str.toString(str);";
279 					buff ~= "}";
280 					buff ~= "return arr;";
281 				}
282 				else
283 					buff ~= "return Str.toStringArray("~ strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~");";
284 
285 				buff ~= "}";
286 			}
287 			else
288 			{
289 				if ( type.size > 0 )
290 				{
291 					buff ~= "public @property char["~ type.size.to!string ~"] "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"()";
292 					buff ~= "{";
293 					buff ~= "return "~ strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~";";
294 					buff ~= "}";
295 				}
296 				else
297 				{
298 					buff ~= "public @property string "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"()";
299 					buff ~= "{";
300 					buff ~= "return Str.toString("~ strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~");";
301 					buff ~= "}";
302 				}
303 			}
304 		}
305 		else if ( dType && dType.isDClass() && type.cType.endsWith("*") )
306 		{
307 			if ( type.isArray() )
308 			{
309 				buff ~= "public @property "~ dTypeName ~"["~ ((type.size > 0)?type.size.to!string:"") ~"] "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"()";
310 				buff ~= "{";
311 
312 				if ( type.length > -1 )
313 					buff ~= dTypeName ~"[] arr = new "~ dTypeName ~"["~ getLengthID(strct) ~"];";
314 				else if ( type.size > 0 )
315 					buff ~= dTypeName ~"["~ type.size.to!string ~"] arr;";
316 				else
317 					buff ~= dTypeName ~"[] arr = new "~ dTypeName ~"[getArrayLength("~ strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~")];";
318 				
319 				buff ~= "for ( int i = 0; i < arr.length; i++ )";
320 				buff ~= "{";
321 				
322 				if ( dType.pack.name.among("cairo", "glib", "gthread") )
323 					buff ~= "arr[i] = new "~ dTypeName ~"("~ strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~"[i], false);";
324 				else if( dType.type == GirStructType.Interface )
325 					buff ~= "arr[i] = ObjectG.getDObject!("~ dTypeName ~"IF)("~ strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~"[i], false);";
326 				else
327 					buff ~= "arr[i] = ObjectG.getDObject!("~ dTypeName ~")("~ strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~"[i], false);";
328 
329 				buff ~= "}";
330 				buff ~= "";
331 				buff ~= "return arr;";
332 				buff ~= "}";
333 			}
334 			else
335 			{
336 				buff ~= "public @property "~ dTypeName ~" "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"()";
337 				buff ~= "{";
338 				
339 				if ( dType.pack.name.among("cairo", "glib", "gthread") )
340 					buff ~= "return new "~ dTypeName ~"("~ strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~", false);";
341 				else if( dType.type == GirStructType.Interface )
342 					buff ~= "return ObjectG.getDObject!("~ dTypeName ~"IF)("~ strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~", false);";
343 				else
344 					buff ~= "return ObjectG.getDObject!("~ dTypeName ~")("~ strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~", false);";
345 
346 				buff ~= "}";
347 			}
348 		}
349 		else if ( type.name.among("bool", "gboolean") || ( type.isArray && type.elementType.name.among("bool", "gboolean") ) )
350 		{
351 			if ( type.isArray() )
352 			{
353 				buff ~= "public @property bool["~ ((type.size > 0)?type.size.to!string:"") ~"] "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"()";
354 				buff ~= "{";
355 
356 				if ( type.length > -1 )
357 					buff ~= "return "~ strct.getHandleVar ~"."~ tokenToGtkD(name, wrapper.aliasses) ~"[0.."~ getLengthID(strct) ~"];";
358 				else if ( type.size > 0 )
359 					buff ~= "return "~ strct.getHandleVar ~"."~ tokenToGtkD(name, wrapper.aliasses) ~";";
360 				else
361 					error("Is boolean[] field: ", strct.name, ".", name, " really zero terminated?");
362 
363 				buff ~= "}";
364 			}
365 			else
366 			{
367 				buff ~= "public @property bool "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"()";
368 				buff ~= "{";
369 				buff ~= "return "~ strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~" != 0;";
370 				buff ~= "}";
371 			}
372 		}
373 		else
374 		{
375 			if ( type.isArray() )
376 			{
377 				if ( type.size > 0 && dType && dType.isDClass() )
378 				{
379 					buff ~= "public @property "~ dTypeName ~"["~ type.size.to!string() ~"] "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"()";
380 					buff ~= "{";
381 					buff ~= dTypeName ~"["~ type.size.to!string() ~"] arr;";
382 
383 					buff ~= "for ( int i = 0; i < arr.length; i++ )";
384 					buff ~= "{";
385 					
386 					if ( dType.pack.name.among("cairo", "glib", "gthread") )
387 						buff ~= "arr[i] = new "~ dTypeName ~"(&("~ strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~"[i]), false);";
388 					else if( dType.type == GirStructType.Interface )
389 						buff ~= "arr[i] = ObjectG.getDObject!("~ dTypeName ~"IF)(&("~ strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~"[i]), false);";
390 					else
391 						buff ~= "arr[i] = ObjectG.getDObject!("~ dTypeName ~")(&("~ strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~"[i]), false);";
392 
393 					buff ~= "}";
394 					buff ~= "";
395 					buff ~= "return arr;";
396 					buff ~= "}";
397 				}
398 				else if ( type.size > 0 )
399 				{
400 					buff ~= "public @property "~ stringToGtkD(type.cType, wrapper.aliasses, strct.aliases) ~"["~ ((type.size > 0)?type.size.to!string:"") ~"] "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"()";
401 					buff ~= "{";
402 					buff ~= "return "~ strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~";";
403 					buff ~= "}";
404 				}
405 				else
406 				{
407 					buff ~= "public @property "~ stringToGtkD(type.cType[0..$-1], wrapper.aliasses, strct.aliases) ~"["~ ((type.size > 0)?type.size.to!string:"") ~"] "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"()";
408 					buff ~= "{";
409 
410 					if ( type.length > -1 )
411 						buff ~= "return "~ strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~"[0.."~ getLengthID(strct) ~"];";
412 					else
413 						buff ~= "return "~ strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~"[0..getArrayLength("~ strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~")];";
414 					
415 					buff ~= "}";
416 				}
417 			}
418 			else
419 			{
420 				buff ~= "public @property "~ stringToGtkD(type.cType, wrapper.aliasses, strct.aliases) ~" "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"()";
421 				buff ~= "{";
422 				buff ~= "return "~ strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~";";
423 				buff ~= "}";
424 			}
425 		}
426 	}
427 
428 	private void writeSetter(ref string[] buff)
429 	{
430 		GirStruct dType;
431 		string    dTypeName;
432 
433 		if ( type.isArray() )
434 			dType = strct.pack.getStruct(type.elementType.name);
435 		else if ( auto dStrct = strct.pack.getStruct(strct.structWrap.get(type.name, "")) )
436 			dType = dStrct;
437 		else
438 			dType = strct.pack.getStruct(type.name);
439 
440 		if ( dType )
441 		{
442 			if ( dType.name in strct.structWrap )
443 				dTypeName = strct.structWrap[dType.name];
444 			else if ( dType.type == GirStructType.Interface )
445 				dTypeName = dType.name ~"IF";
446 			else
447 				dTypeName = dType.name;
448 		}
449 
450 		if ( type.isString() )
451 		{
452 			if ( type.isArray() && type.elementType.isString() )
453 			{
454 				buff ~= "public @property void "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"(string["~ ((type.size > 0)?type.size.to!string:"") ~"] value)";
455 				buff ~= "{";
456 
457 				if ( type.size > 0 )
458 				{
459 					buff ~= stringToGtkD(type.elementType.cType, wrapper.aliasses) ~"["~ type.size.to!string ~"] arr;";
460 					buff ~= "foreach( i, str; value )";
461 					buff ~= "{";
462 					buff ~= "arr[i] = Str.toStringz(str);";
463 					buff ~= "}";
464 					buff ~= strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~" = arr;";
465 				}
466 				else
467 				{
468 					buff ~= strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~" = Str.toStringzArray(value);";
469 					if ( type.length > -1 )
470 						buff ~= strct.getHandleVar() ~"."~ tokenToGtkD(strct.fields[type.length].name, wrapper.aliasses) ~" = cast("~ stringToGtkD(strct.fields[type.length].type.cType, wrapper.aliasses) ~")value.length;";
471 				}
472 				buff ~= "}";
473 			}
474 			else
475 			{
476 				if ( type.size > 0 )
477 				{
478 					buff ~= "public @property void "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"(char["~ type.size.to!string ~"] value)";
479 					buff ~= "{";
480 					buff ~= strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~" = value;";
481 					buff ~= "}";
482 				}
483 				else
484 				{
485 					buff ~= "public @property void "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"(string value)";
486 					buff ~= "{";
487 					buff ~= strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~" = Str.toStringz(value);";
488 					buff ~= "}";
489 				}
490 			}
491 		}
492 		else if ( dType && dType.isDClass() && type.cType.endsWith("*") )
493 		{
494 			if ( type.isArray() )
495 			{
496 				buff ~= "public @property void "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"("~ dTypeName ~"["~ ((type.size > 0)?type.size.to!string:"") ~"] value)";
497 				buff ~= "{";
498 				if ( type.size > 0 )
499 					buff ~= dType.cType ~"*["~ type.size.to!string ~"] arr;";
500 				else
501 					buff ~= dType.cType ~"*[] arr = new "~ dType.cType ~"*[value.length+1];";
502 				buff ~= "for ( int i = 0; i < value.length; i++ )";
503 				buff ~= "{";
504 				buff ~= "arr[i] = value[i]."~ dType.getHandleFunc() ~"();";
505 				buff ~= "}";
506 				buff ~= "arr[value.length] = null;";
507 				buff ~= "";
508 				buff ~= strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~" = arr.ptr;";
509 
510 				if ( type.length > -1 )
511 					buff ~= strct.getHandleVar() ~"."~ tokenToGtkD(strct.fields[type.length].name, wrapper.aliasses) ~" = cast("~ stringToGtkD(strct.fields[type.length].type.cType, wrapper.aliasses) ~")value.length;";
512 
513 				buff ~= "}";
514 			}
515 			else
516 			{
517 				buff ~= "public @property void "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"("~ dTypeName ~" value)";
518 				buff ~= "{";
519 				buff ~= strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~" = value."~ dType.getHandleFunc() ~"();";
520 				buff ~= "}";
521 			}
522 		}
523 		else if ( type.name.among("bool", "gboolean") || ( type.isArray && type.elementType.name.among("bool", "gboolean") ) )
524 		{
525 			if ( type.isArray() )
526 			{
527 				buff ~= "public @property void "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"(bool["~ ((type.size > 0)?type.size.to!string:"") ~"] value)";
528 				buff ~= "{";
529 				if ( type.size > 0 )
530 				{
531 					buff ~= strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~" = value;";	
532 				}
533 				else
534 				{
535 					buff ~= strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~" = value.ptr;";
536 					if ( type.length > -1 )
537 						buff ~= strct.getHandleVar() ~"."~ tokenToGtkD(strct.fields[type.length].name, wrapper.aliasses) ~" = cast("~ stringToGtkD(strct.fields[type.length].type.cType, wrapper.aliasses) ~")value.length;";
538 				}
539 				buff ~= "}";
540 			}
541 			else
542 			{
543 				buff ~= "public @property void "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"(bool value)";
544 				buff ~= "{";
545 				buff ~= strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~" = value;";				
546 				buff ~= "}";
547 			}
548 		}
549 		else
550 		{
551 			if ( type.isArray() )
552 			{
553 				if ( type.size > 0 && dType && dType.isDClass() )
554 				{
555 					buff ~= "public @property void "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"("~ dTypeName ~"["~ type.size.to!string() ~"] value)";
556 					buff ~= "{";
557 					buff ~= "for ( int i = 0; i < value.length; i++ )";
558 					buff ~= "{";
559 					buff ~= strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~"[i] = *(value[i]."~ dType.getHandleFunc() ~"());";
560 					buff ~= "}";
561 					buff ~= "}";
562 				}
563 				else if ( type.size > 0 )
564 				{
565 					buff ~= "public @property void "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"("~ stringToGtkD(type.cType, wrapper.aliasses, strct.aliases) ~"["~ ((type.size > 0)?type.size.to!string:"") ~"] value)";
566 					buff ~= "{";
567 					buff ~= strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~" = value;";	
568 					buff ~= "}";
569 				}
570 				else
571 				{
572 					buff ~= "public @property void "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"("~ stringToGtkD(type.cType[0..$-1], wrapper.aliasses, strct.aliases) ~"["~ ((type.size > 0)?type.size.to!string:"") ~"] value)";
573 					buff ~= "{";
574 					buff ~= strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~" = value.ptr;";
575 	
576 					if ( type.length > -1 )
577 						buff ~= strct.getHandleVar() ~"."~ tokenToGtkD(strct.fields[type.length].name, wrapper.aliasses) ~" = cast("~ stringToGtkD(strct.fields[type.length].type.cType, wrapper.aliasses) ~")value.length;";
578 
579 					buff ~= "}";
580 				}
581 			}
582 			else
583 			{
584 				buff ~= "public @property void "~ tokenToGtkD(name, wrapper.aliasses, strct.aliases) ~"("~ stringToGtkD(type.cType, wrapper.aliasses, strct.aliases) ~" value)";
585 				buff ~= "{";
586 				buff ~= strct.getHandleVar() ~"."~ tokenToGtkD(name, wrapper.aliasses) ~" = value;";
587 				buff ~= "}";
588 			}
589 		}
590 	}
591 
592 	private void writeDocs(ref string[] buff)
593 	{
594 		if ( doc !is null && wrapper.includeComments )
595 		{
596 			buff ~= "/**";
597 			foreach ( line; doc.splitLines() )
598 				buff ~= " * "~ line.strip();
599 
600 			buff ~= " */";
601 		}
602 		else if ( wrapper.includeComments )
603 		{
604 			buff ~= "/** */";
605 		}
606 	}
607 
608 	private string getLengthID(GirStruct strct)
609 	{
610 		if ( type.length > -1 )
611 			return strct.getHandleVar() ~"."~ tokenToGtkD(strct.fields[type.length].name, wrapper.aliasses);
612 		else if ( type.size > 0 )
613 			return to!string(type.size);
614 
615 		return null;
616 	}
617 }