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