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.GtkType;
21 
22 import utils.GtkWrapper;
23 import utils.XML;
24 
25 import std.algorithm: among, canFind;
26 import std.array: replace;
27 import std.conv: to;
28 
29 /**
30  * Represent sthe type of an field or a parameter.
31  */
32 final class GtkType
33 {
34 	string name;
35 	string cType;
36 	string dType;
37 	string doc;
38 	bool constType;
39 
40 	int size = -1;   /// The size of a fixed size array.
41 	int length = -1; /// The index of the param representing the length, not counting the instance param.
42 	bool zeroTerminated; /// Is this array zero-terminated.
43 	GtkType elementType; /// The type of the array elements, also set for Glib.List, Glib.SList Glib.Array and GLib.HashTable.
44 	GtkType keyType;     /// The key type of a HashTable;
45 
46 	GtkWrapper wrapper;
47 
48 	this(GtkWrapper wrapper)
49 	{
50 		this.wrapper = wrapper;
51 	}
52 
53 	void parse(T)(XMLReader!T reader)
54 	{
55 		if ( "c:type" in reader.front.attributes )
56 			cType = reader.front.attributes["c:type"];
57 		if ( "length" in reader.front.attributes )
58 			length = to!int(reader.front.attributes["length"]);
59 		if ( "zero-terminated" in reader.front.attributes )
60 			zeroTerminated = to!int(reader.front.attributes["zero-terminated"]) == 1;
61 		if ( "fixed-size" in reader.front.attributes )
62 			size = to!int(reader.front.attributes["fixed-size"]);
63 		if ( "name" in reader.front.attributes )
64 			name = reader.front.attributes["name"];
65 
66 		if ( cType is null && name is null )
67 		{
68 			name = "none";
69 			cType = "void";
70 		}
71 
72 		if ( cType.canFind("const ") )
73 		{
74 			constType = true;
75 			fixType();
76 		}
77 
78 		if ( cType.canFind("unsigned ") )
79 		{
80 			cType = cType.replace("unsigned ", "u");
81 		}
82 
83 		cType = cType.replace("volatile ", "");
84 
85 		if ( cType == "unsigned" )
86 			cType = name;
87 
88 		removeInitialyUnowned();
89 
90 		if ( cType is null && (name == "filename" || name == "utf8") )
91 			cType = "gchar*";
92 
93 		if ( reader.front.type == XMLNodeType.EmptyTag )
94 			return;
95 
96 		reader.popFront();
97 
98 		while ( !reader.empty && !reader.endTag("type", "array") )
99 		{
100 			if ( elementType )
101 				keyType = elementType;
102 
103 			elementType = new GtkType(wrapper);
104 			elementType.parse(reader);
105 
106 			reader.popFront();
107 		}
108 
109 		if ( cType == elementType.cType && !cType.among("void*", "gpointer", "gconstpointer") )
110 			cType ~= "*";
111 
112 		if ( isArray() && cType == "void" )
113 			cType = elementType.cType ~"*";
114 	}
115 
116 	bool isArray()
117 	{
118 		if ( elementType is null )
119 			return false;
120 
121 		if ( name.among("GLib.List", "GLib.SList", "GLib.Array", "GLib.ByteArray", "GLib.HashTable", "GLib.PtrArray") )
122 			return false;
123 
124 		if ( name.among("List", "SList", "Array", "ByteArray", "HashTable", "PtrArray") )
125 			return false;
126 
127 		if ( elementType )
128 			return true;
129 
130 		return false;
131 	}
132 
133 	private void fixType()
134 	{
135 		if ( name == "utf8" && !cType.canFind("**") )
136 		{
137 			cType = "const(char)*";
138 			return;
139 		}
140 
141 		cType = cType.replace("const ", "").replace(" const", "");
142 	}
143 
144 	private void removeInitialyUnowned()
145 	{
146 		if ( name.among("GObject.InitiallyUnowned", "InitiallyUnowned") )
147 		{
148 			if ( name == "GObject.InitiallyUnowned" )
149 				name = "GObject.Object";
150 			else if ( name == "InitiallyUnowned" )
151 				name = "Object";
152 
153 			if ( cType == "GInitiallyUnowned" )
154 				cType = "GObject";
155 			else if ( cType == "GInitiallyUnowned*" )
156 				cType = "GObject*";
157 		}
158 		else if ( name.among("GObject.InitiallyUnownedClass", "InitiallyUnownedClass") )
159 		{
160 			if ( name == "GObject.InitiallyUnownedClass" )
161 				name = "GObject.ObjectClass";
162 			else if ( name == "InitiallyUnownedClass" )
163 				name = "ObjectClass";
164 
165 			if ( cType == "GInitiallyUnownedClass" )
166 				cType = "GObjectClass";
167 			else if ( cType == "GInitiallyUnownedClass*" )
168 				cType = "GObjectClass*";
169 		}
170 	}
171 }