1 /// A program to simplify the process of translating UEFI headers from C -> D 2 /// Usage: efihdrtool InFile OutFile 3 module efihdrtool; 4 5 import std.stdio, std..string, std.array, std.algorithm, std.range, std.math, std.format, std.conv; 6 import std.path, std.process; 7 8 File fpIn; 9 File fpOut; 10 char[] cLine; 11 string moduleName = "0"; 12 string inFile; 13 14 void main(string[] args) 15 { 16 if(args.length!=3) 17 { 18 stderr.writefln("Usage: %s InFile.h OutFile.d", args[0]); 19 return; 20 } 21 inFile = args[1]; 22 inFile = inFile[inFile.indexOf("Include/")+8..$]; 23 fpIn = File(args[1],"r"); 24 fpOut = File(args[2],"w"); 25 if(args[2].startsWith("source/")) 26 moduleName = args[2]["source/uefi/".length .. $-2].replace("/","."); 27 while(!fpIn.eof()) 28 { 29 nextLine(); 30 process(); 31 } 32 fpOut.flush(); 33 fpIn.close(); 34 fpOut.close(); 35 execute(["dfix",args[2]]); 36 execute(["dfmt",args[2],"-i"]); 37 } 38 39 void nextLine() 40 { 41 fpIn.readln(cLine); 42 cLine = cLine.strip; 43 } 44 45 bool startsWith(const(char[]) a, const(char[]) b) 46 { 47 size_t bl = b.length; 48 if(b[$-1]=='\0')bl--; 49 if(a.length<bl)return false; 50 for(int i=0;i<bl;i++) 51 { 52 if(a[i]!=b[i])return false; 53 } 54 return true; 55 } 56 57 bool endsWith(const(char[]) a, const(char[]) b) 58 { 59 size_t bl = b.length; 60 if(b[$-1]=='\0')bl--; 61 if(a.length<bl)return false; 62 for(int i=0;i<bl;i++) 63 { 64 if(a[$-bl+i]!=b[i])return false; 65 } 66 return true; 67 } 68 69 void process() 70 { 71 if(cLine.length<1) 72 { 73 //fpOut.writeln(); 74 return; 75 } 76 if(cLine=="///")return; 77 if(cLine.startsWith("///")) 78 { 79 fpOut.writeln(cLine); 80 } 81 if(cLine=="/** @file") 82 { 83 fpOut.writeln("/**"); 84 fpOut.writefln("\tBased on %s, original notice:\n",inFile); 85 while(true) 86 { 87 nextLine(); 88 if(cLine != "**/") 89 { 90 fpOut.writeln("\t",cLine.replace("<BR>","")); 91 } 92 else 93 { 94 break; 95 } 96 } 97 fpOut.writeln("**/"); 98 fpOut.writefln("module uefi.%s;",moduleName); 99 fpOut.writeln("import uefi.base;"); 100 fpOut.writeln("import uefi.base_type;"); 101 fpOut.writeln("public:"); 102 fpOut.writeln("extern (C):"); 103 return; 104 } 105 if(cLine=="/**") 106 { 107 fpOut.writeln("/**"); 108 while(true) 109 { 110 nextLine(); 111 if(!cLine.endsWith("**/")) 112 { 113 fpOut.writeln("\t",cLine); 114 } 115 else 116 { 117 break; 118 } 119 } 120 fpOut.writeln("**/"); 121 return; 122 } 123 if(cLine.startsWith("#ifndef __")) 124 { 125 nextLine(); // skip header safeguard 126 return; 127 } 128 if(cLine.startsWith("#include ")) 129 { 130 fpOut.writeln("// FIXME: INCLUDE ",cLine[9..$]); 131 stderr.writeln("// FIXME: INCLUDE ",cLine[9..$]); 132 return; 133 } 134 if(cLine.startsWith("#define")) 135 { 136 if(cLine.endsWith("_GUID \\")) 137 { 138 string Id = cLine[ 8 .. $-2 ].idup; 139 nextLine(); 140 nextLine(); 141 string Guid = cLine[0..$-2].idup; 142 nextLine(); 143 fpOut.writeln("enum EFI_GUID ",Id," = EFI_GUID(",Guid.replace("{","[").replace("}","]"),");"); 144 } 145 else 146 { 147 // #define abc def 148 auto Split = cLine.replace("ULL","UL").split; 149 if(Split[1].indexOf("(")>0) 150 { 151 fpOut.writeln("// ", cLine); 152 while(cLine[$-1]=='\\') 153 { 154 nextLine(); 155 fpOut.writeln("// ", cLine); 156 } 157 } 158 else 159 { 160 fpOut.writef("enum %s = ", Split[1]); //Split[2..$].join(" ") 161 bool hadSemicolon = false; 162 foreach(txt;Split[2..$]) 163 { 164 if(txt.startsWith("//") || txt.startsWith("/*")) 165 { 166 hadSemicolon = true; 167 fpOut.write("; "); 168 } 169 fpOut.write(txt, ' '); 170 } 171 fpOut.write((hadSemicolon)?"\n":";\n"); 172 } 173 } 174 return; 175 } 176 if(cLine.startsWith("typedef ")) 177 { 178 cLine = cLine[8..$]; 179 if(cLine.startsWith("struct _")&&(cLine[$-1]!='{'))cLine = cLine[7..$]; 180 if(cLine.startsWith("union _")&&(cLine[$-1]!='{'))cLine = cLine[6..$]; 181 if(cLine.startsWith("struct")) 182 { 183 auto app = appender!string; 184 nextLine(); 185 while(!cLine.startsWith("}")) 186 { 187 app ~= cLine.idup; 188 app ~= '\n'; 189 nextLine(); 190 } 191 string Id = cLine[2..$-1].idup; 192 fpOut.writeln("struct ", Id, " {\n", app.data, "}"); 193 } 194 else if(cLine.startsWith("enum")) 195 { 196 auto app = appender!string; 197 nextLine(); 198 while(!cLine.startsWith("}")) 199 { 200 app ~= cLine.idup; 201 app ~= '\n'; 202 nextLine(); 203 } 204 string Id = cLine[2..$-1].idup; 205 fpOut.writeln("alias ", Id," = UINT32;"); 206 fpOut.writeln("enum :", Id, " {\n", app.data, "}"); 207 } 208 else if(cLine.startsWith("union")) 209 { 210 auto app = appender!string; 211 nextLine(); 212 while(!cLine.startsWith("}")) 213 { 214 app ~= cLine.idup; 215 app ~= '\n'; 216 nextLine(); 217 } 218 string Id = cLine[2..$-1].idup; 219 fpOut.writeln("union ", Id, " {\n", app.data, "}"); 220 } 221 else 222 { 223 auto Split = cLine[0..$-1].split; 224 fpOut.writefln("alias %s = %s;",Split[$-1],Split[0..$-1].join(" ")); 225 } 226 return; 227 } 228 if(cLine=="typedef") // function pointer 229 { 230 nextLine(); 231 string RetType = cLine.idup; 232 nextLine(); 233 // (EFIAPI *EFI_TEXT_CLEAR_SCREEN)( 234 string FunName = cLine[9..$-2].idup; 235 nextLine(); 236 auto Args = appender!string; 237 while(cLine!=");") 238 { 239 auto Kw = cLine.split; 240 foreach(K;Kw) 241 { 242 if((K=="IN")||(K=="OUT")||(K=="EFIAPI")||(K=="OPTIONAL"))continue; 243 if((K=="IN,")||(K=="OUT,")||(K=="EFIAPI,")||(K=="OPTIONAL,")){Args~=',';continue;} 244 if(K=="CONST")K="const".dup; 245 if(K=="VOID")K="void".dup; 246 Args ~= K; 247 Args ~= ' '; 248 } 249 nextLine(); 250 } 251 fpOut.writefln("alias %s = %s function(%s) @nogc nothrow;", FunName, RetType, Args.data); 252 } 253 if(cLine.startsWith("struct")) 254 { 255 256 while(cLine != "};") 257 { 258 fpOut.writeln(cLine); 259 nextLine(); 260 } 261 fpOut.writeln("}"); 262 return; 263 } 264 } 265