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.GirType; 19 20 import std.algorithm: among, canFind, startsWith; 21 import std.array: replace, split; 22 import std.conv: to; 23 import std.range: empty; 24 25 import gtd.GirWrapper; 26 import gtd.XMLReader; 27 28 /** 29 * Represent sthe type of an field or a parameter. 30 */ 31 final class GirType 32 { 33 string name; 34 string cType; 35 string dType; 36 string doc; 37 bool constType; 38 39 int size = -1; /// The size of a fixed size array. 40 int length = -1; /// The index of the param representing the length, not counting the instance param. 41 bool zeroTerminated; /// Is this array zero-terminated. 42 bool girArray = false; /// The gir file specifies this as an array. Use isArray to check if this is actually an array. 43 GirType elementType; /// The type of the array elements, also set for Glib.List, Glib.SList Glib.Array and GLib.HashTable. 44 GirType keyType; /// The key type of a HashTable; 45 46 GirWrapper wrapper; 47 48 this(GirWrapper wrapper) 49 { 50 this.wrapper = wrapper; 51 } 52 53 void parse(T)(XMLReader!T reader) 54 { 55 if ( reader.front.value == "array" ) 56 girArray = true; 57 58 if ( "c:type" in reader.front.attributes ) 59 cType = reader.front.attributes["c:type"]; 60 if ( "length" in reader.front.attributes ) 61 length = to!int(reader.front.attributes["length"]); 62 if ( "zero-terminated" in reader.front.attributes ) 63 zeroTerminated = to!int(reader.front.attributes["zero-terminated"]) == 1; 64 if ( "fixed-size" in reader.front.attributes ) 65 size = to!int(reader.front.attributes["fixed-size"]); 66 if ( "name" in reader.front.attributes ) 67 name = reader.front.attributes["name"]; 68 69 if ( cType is null && name is null ) 70 { 71 name = "none"; 72 } 73 74 // Some GIR files have a none type name. 75 if (name == "none") { 76 cType = "void"; 77 } 78 79 if ( cType.canFind(" const") || cType.canFind("const ") ) 80 { 81 constType = true; 82 fixType(); 83 } 84 85 if ( cType.canFind("unsigned ") ) 86 { 87 cType = cType.replace("unsigned ", "u"); 88 } 89 90 if ( name == "long double" ) 91 { 92 name = "greal"; 93 cType = "greal"; 94 } 95 96 cType = cType.replace("volatile ", ""); 97 98 if ( cType == "unsigned" ) 99 cType = name; 100 101 removeInitialyUnowned(); 102 103 if ( cType is null && (name == "filename" || name == "utf8") ) 104 cType = "gchar*"; 105 106 //Vala libraries can have the package name in there name twice, befoer and after the dot. 107 string[] arr = split(name, '.'); 108 if ( arr.length > 1 && arr[1].startsWith(arr[0]) ) 109 { 110 name = arr[1][arr[0].length .. $]; 111 } 112 113 if ( reader.front.type == XMLNodeType.EmptyTag ) 114 return; 115 116 reader.popFront(); 117 118 while ( !reader.empty && !reader.endTag("type", "array") ) 119 { 120 if ( elementType ) 121 keyType = elementType; 122 123 elementType = new GirType(wrapper); 124 elementType.parse(reader); 125 126 reader.popFront(); 127 } 128 129 if ( cType == elementType.cType && !cType.among("void*", "gpointer", "gconstpointer") && size < 0 ) 130 cType ~= "*"; 131 132 if ( isArray() && (cType == "void" || cType.empty) ) 133 { 134 if ( size > 0 ) 135 cType = elementType.cType; 136 else 137 cType = elementType.cType ~"*"; 138 } 139 } 140 141 bool isString() 142 { 143 if ( cType.startsWith("gchar*", "char*", "const(char)*") ) 144 return true; 145 if ( name.among("utf8", "filename") ) 146 return true; 147 if ( isArray() && elementType.cType.startsWith("gchar", "char", "const(char)") ) 148 return true; 149 150 return false; 151 } 152 153 bool isArray() 154 { 155 if ( elementType is null ) 156 return false; 157 158 // The GLib Arrays are in the GIR files as arrays but they shouldn't be wrapped as such. 159 if ( name.among("GLib.Array", "Array", "GLib.ByteArray", "ByteArray", "GLib.PtrArray", "PtrArray") ) 160 return false; 161 162 if ( girArray ) 163 return true; 164 165 return false; 166 } 167 168 private void fixType() 169 { 170 if ( name == "utf8" && !cType.canFind("**") ) 171 { 172 cType = "const(char)*"; 173 return; 174 } 175 176 cType = cType.replace("const ", "").replace(" const", ""); 177 } 178 179 private void removeInitialyUnowned() 180 { 181 if ( name.among("GObject.InitiallyUnowned", "InitiallyUnowned") ) 182 { 183 if ( name == "GObject.InitiallyUnowned" ) 184 name = "GObject.Object"; 185 else if ( name == "InitiallyUnowned" ) 186 name = "Object"; 187 188 if ( cType == "GInitiallyUnowned" ) 189 cType = "GObject"; 190 else if ( cType == "GInitiallyUnowned*" ) 191 cType = "GObject*"; 192 } 193 else if ( name.among("GObject.InitiallyUnownedClass", "InitiallyUnownedClass") ) 194 { 195 if ( name == "GObject.InitiallyUnownedClass" ) 196 name = "GObject.ObjectClass"; 197 else if ( name == "InitiallyUnownedClass" ) 198 name = "ObjectClass"; 199 200 if ( cType == "GInitiallyUnownedClass" ) 201 cType = "GObjectClass"; 202 else if ( cType == "GInitiallyUnownedClass*" ) 203 cType = "GObjectClass*"; 204 } 205 } 206 }