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.GtkEnum;
21 
22 import std.algorithm;
23 import std.string : splitLines, strip, toUpper;
24 
25 import utils.GtkPackage;
26 import utils.GtkWrapper;
27 import utils.XML;
28 
29 final class GtkEnum
30 {
31 	string name;
32 	string cName;
33 	string libVersion;
34 	string doc;
35 
36 	GtkEnumMember[] members;
37 	GtkWrapper wrapper;
38 	GtkPackage pack;
39 
40 	this(GtkWrapper wrapper, GtkPackage pack)
41 	{
42 		this.wrapper = wrapper;
43 		this.pack = pack;
44 	}
45 
46 	void parse(T)(XMLReader!T reader)
47 	{
48 		name = reader.front.attributes["name"];
49 		cName = reader.front.attributes["c:type"];
50 
51 		if ( "version" in reader.front.attributes )
52 			libVersion = reader.front.attributes["version"];
53 		reader.popFront();
54 
55 		while ( !reader.empty && !reader.endTag("bitfield", "enumeration") )
56 		{
57 			switch (reader.front.value)
58 			{
59 				case "doc":
60 					reader.popFront();
61 					doc ~= reader.front.value;
62 					reader.popFront();
63 					break;
64 				case "doc-deprecated":
65 					reader.popFront();
66 					doc ~= "\n\nDeprecated: "~ reader.front.value;
67 					reader.popFront();
68 					break;
69 				case "member":
70 					if ( reader.front.attributes["name"].startsWith("2bu", "2bi", "3bu") )
71 					{
72 						reader.skipTag();
73 						break;
74 					}
75 
76 					GtkEnumMember member = GtkEnumMember(wrapper);
77 					member.parse(reader);
78 					members ~= member;
79 					break;
80 				case "function":
81 					//Skip these functions for now
82 					//as they are also availabe as global functions.
83 					//pack.parseFunction(reader);
84 					reader.skipTag();
85 					break;
86 				default:
87 					assert(false, "Unexpected tag: "~ reader.front.value);
88 			}
89 			reader.popFront();
90 		}
91 	}
92 
93 	string[] getEnumDeclaration()
94 	{
95 		string[] buff;
96 		if ( doc !is null && wrapper.includeComments )
97 		{
98 			buff ~= "/**";
99 			foreach ( line; doc.splitLines() )
100 				buff ~= " * "~ line.strip();
101 
102 			if ( libVersion )
103 			{
104 				buff ~= " *";
105 				buff ~= " * Since: "~ libVersion;
106 			}
107 
108 			buff ~= " */";
109 		}
110 
111 		buff ~= "public enum "~ cName ~(name.among("ParamFlags", "MessageType") ? " : uint" : "");
112 		buff ~= "{";
113 
114 		foreach ( member; members )
115 		{
116 			buff ~= member.getEnumMemberDeclaration();
117 		}
118 
119 		buff ~= "}";
120 		if ( name !is null && pack.name.among("glgdk", "glgtk") )
121 			buff ~= "alias "~ cName ~" GL"~ name ~";";
122 		else if ( name !is null && pack.name != "pango" )
123 			buff ~= "alias "~ cName ~" "~ name ~";";
124 
125 		return buff;
126 	}
127 }
128 
129 struct GtkEnumMember
130 {
131 	string name;
132 	string value;
133 	string doc;
134 
135 	GtkWrapper wrapper;
136 
137 	@disable this();
138 
139 	this(GtkWrapper wrapper)
140 	{
141 		this.wrapper = wrapper;
142 	}
143 
144 	void parse(T)(XMLReader!T reader)
145 	{
146 		name = reader.front.attributes["name"];
147 		value = reader.front.attributes["value"];
148 
149 		if ( reader.front.type == XMLNodeType.EmptyTag )
150 			return;
151 
152 		reader.popFront();
153 
154 		while ( !reader.empty && !reader.endTag("member", "constant") )
155 		{
156 			switch (reader.front.value)
157 			{
158 				case "doc":
159 					reader.popFront();
160 					doc ~= reader.front.value;
161 					reader.popFront();
162 					break;
163 				case "doc-deprecated":
164 					reader.popFront();
165 					doc ~= "\n\nDeprecated: "~ reader.front.value;
166 					reader.popFront();
167 					break;
168 				case "type":
169 					if ( reader.front.attributes["name"] == "utf8" )
170 						value = "\""~ value ~"\"";
171 					break;
172 				default:
173 					import std.stdio;
174 					writeln(reader.front.type);
175 					assert(false, "Unexpected tag: "~ reader.front.value);
176 			}
177 			reader.popFront();
178 		}
179 	}
180 
181 	string[] getEnumMemberDeclaration()
182 	{
183 		string[] buff;
184 		if ( doc !is null && wrapper.includeComments )
185 		{
186 			buff ~= "/**";
187 			foreach ( line; doc.splitLines() )
188 				buff ~= " * "~ line.strip();
189 			buff ~= " */";
190 		}
191 
192 		buff ~= tokenToGtkD(name.toUpper(), wrapper.aliasses, false) ~" = "~ value ~",";
193 
194 		return buff;
195 	}
196 }