sub_401000 compiles
[ia32rtools.git] / tools / protoparse.h
1
2 struct parsed_proto {
3         struct {
4                 char *reg;
5                 const char *type;
6                 void *datap;
7         } arg[16];
8         const char *ret_type;
9         int is_stdcall;
10         int argc;
11         int argc_stack;
12         int argc_reg;
13 };
14
15 static const char *hdrfn;
16 static int hdrfline = 0;
17
18 static int find_protostr(char *dst, size_t dlen, FILE *fhdr, const char *sym)
19 {
20         int line = 0;
21         char *p;
22
23         rewind(fhdr);
24
25         while (fgets(dst, dlen, fhdr))
26         {
27                 line++;
28                 if (strstr(dst, sym) != NULL)
29                         break;
30         }
31         hdrfline = line;
32
33         if (feof(fhdr))
34                 return -1;
35
36         p = dst + strlen(dst);
37         for (p--; p > dst && my_isblank(*p); --p)
38                 *p = 0;
39
40         return 0;
41 }
42
43 static int get_regparm(char *dst, size_t dlen, char *p)
44 {
45         int i, o;
46
47         if (*p != '<')
48                 return 0;
49
50         for (o = 0, i = 1; o < dlen; i++) {
51                 if (p[i] == 0)
52                         return 0;
53                 if (p[i] == '>')
54                         break;
55                 dst[o++] = p[i];
56         }
57         dst[o] = 0;
58         return i + 1;
59 }
60
61 // hmh..
62 static const char *known_types[] = {
63         "const void *",
64         "void *",
65         "char *",
66         "FILE *",
67         "unsigned __int8",
68         "unsigned __int16",
69         "unsigned int",
70         "signed int",
71         "char",
72         "__int8",
73         "__int16",
74         "int",
75         "bool",
76         "void",
77         "BYTE",
78         "WORD",
79         "DWORD",
80         "_DWORD",
81         "HMODULE",
82         "HANDLE",
83         "HWND",
84         "LPCSTR",
85         "size_t",
86 };
87
88 static const char *check_type(const char *name)
89 {
90         int i, l;
91
92         for (i = 0; i < ARRAY_SIZE(known_types); i++) {
93                 l = strlen(known_types[i]);
94                 if (strncmp(known_types[i], name, l) == 0)
95                         return known_types[i];
96         }
97
98         return NULL;
99 }
100
101 /* args are always expanded to 32bit */
102 static const char *map_reg(const char *reg)
103 {
104         const char *regs_f[] = { "eax", "ebx", "ecx", "edx", "esi", "edi" };
105         const char *regs_w[] = { "ax",  "bx",  "cx",  "dx",  "si",  "di" };
106         const char *regs_b[] = { "al",  "bl",  "cl",  "dl" };
107         int i;
108
109         for (i = 0; i < ARRAY_SIZE(regs_w); i++)
110                 if (IS(reg, regs_w[i]))
111                         return regs_f[i];
112
113         for (i = 0; i < ARRAY_SIZE(regs_b); i++)
114                 if (IS(reg, regs_b[i]))
115                         return regs_f[i];
116
117         return reg;
118 }
119
120 static int parse_protostr(char *protostr, struct parsed_proto *pp)
121 {
122         char regparm[16];
123         char buf[256];
124         char cconv[32];
125         const char *kt;
126         int xarg = 0;
127         int ret;
128         char *p;
129         int i;
130
131         p = protostr;
132         if (p[0] == '/' && p[1] == '/') {
133                 //printf("warning: decl for sym '%s' is commented out\n", sym);
134                 p = sskip(p + 2);
135         }
136
137         kt = check_type(p);
138         if (kt == NULL) {
139                 printf("%s:%d:%ld: unhandled return in '%s'\n",
140                         hdrfn, hdrfline, (p - protostr) + 1, protostr);
141                 return 1;
142         }
143         pp->ret_type = kt;
144         p += strlen(kt);
145         p = sskip(p);
146
147         p = next_word(cconv, sizeof(cconv), p);
148         p = sskip(p);
149         if (cconv[0] == 0) {
150                 printf("%s:%d:%ld: cconv missing\n",
151                         hdrfn, hdrfline, (p - protostr) + 1);
152                 return 1;
153         }
154         if      (IS(cconv, "__cdecl"))
155                 pp->is_stdcall = 0;
156         else if (IS(cconv, "__stdcall"))
157                 pp->is_stdcall = 1;
158         else if (IS(cconv, "__fastcall"))
159                 pp->is_stdcall = 1;
160         else if (IS(cconv, "__thiscall"))
161                 pp->is_stdcall = 1;
162         else if (IS(cconv, "__userpurge"))
163                 pp->is_stdcall = 1; // in all cases seen..
164         else if (IS(cconv, "__usercall"))
165                 pp->is_stdcall = 0; // ..or is it?
166         else {
167                 printf("%s:%d:%ld: unhandled cconv: '%s'\n",
168                         hdrfn, hdrfline, (p - protostr) + 1, cconv);
169                 return 1;
170         }
171
172         p = next_idt(buf, sizeof(buf), p);
173         p = sskip(p);
174         if (buf[0] == 0) {
175                 printf("%s:%d:%ld: func name missing\n",
176                                 hdrfn, hdrfline, (p - protostr) + 1);
177                 return 1;
178         }
179
180         ret = get_regparm(regparm, sizeof(regparm), p);
181         if (ret > 0) {
182                 if (!IS(regparm, "eax") && !IS(regparm, "ax")
183                  && !IS(regparm, "al"))
184                 {
185                         printf("%s:%d:%ld: bad regparm: %s\n",
186                                 hdrfn, hdrfline, (p - protostr) + 1, regparm);
187                         return 1;
188                 }
189                 p += ret;
190                 p = sskip(p);
191         }
192
193         if (*p != '(') {
194                 printf("%s:%d:%ld: '(' expected, got '%c'\n",
195                                 hdrfn, hdrfline, (p - protostr) + 1, *p);
196                 return 1;
197         }
198         p++;
199
200         while (1) {
201                 p = sskip(p);
202                 if (*p == ')')
203                         break;
204                 if (*p == ',')
205                         p = sskip(p + 1);
206
207                 xarg++;
208
209                 kt = check_type(p);
210                 if (kt == NULL) {
211                         printf("%s:%d:%ld: unhandled type for arg%d\n",
212                                 hdrfn, hdrfline, (p - protostr) + 1, xarg);
213                         return 1;
214                 }
215                 pp->arg[xarg - 1].type = kt;
216                 p += strlen(kt);
217                 p = sskip(p);
218
219                 p = next_idt(buf, sizeof(buf), p);
220                 p = sskip(p);
221 #if 0
222                 if (buf[0] == 0) {
223                         printf("%s:%d:%ld: idt missing for arg%d\n",
224                                 hdrfn, hdrfline, (p - protostr) + 1, xarg);
225                         return 1;
226                 }
227 #endif
228                 pp->arg[xarg - 1].reg = NULL;
229
230                 ret = get_regparm(regparm, sizeof(regparm), p);
231                 if (ret > 0) {
232                         p += ret;
233                         p = sskip(p);
234
235                         pp->arg[xarg - 1].reg = strdup(map_reg(regparm));
236                 }
237         }
238
239         if (xarg > 0 && (IS(cconv, "__fastcall") || IS(cconv, "__thiscall"))) {
240                 if (pp->arg[0].reg != NULL) {
241                         printf("%s:%d: %s with arg1 spec %s?\n",
242                                 hdrfn, hdrfline, cconv, pp->arg[0].reg);
243                 }
244                 pp->arg[0].reg = strdup("ecx");
245         }
246
247         if (xarg > 1 && IS(cconv, "__fastcall")) {
248                 if (pp->arg[1].reg != NULL) {
249                         printf("%s:%d: %s with arg2 spec %s?\n",
250                                 hdrfn, hdrfline, cconv, pp->arg[1].reg);
251                 }
252                 pp->arg[1].reg = strdup("edx");
253         }
254
255         pp->argc = xarg;
256
257         for (i = 0; i < pp->argc; i++) {
258                 if (pp->arg[i].reg == NULL)
259                         pp->argc_stack++;
260                 else
261                         pp->argc_reg++;
262         }
263
264         return 0;
265 }
266
267 static int proto_parse(FILE *fhdr, const char *sym, struct parsed_proto *pp)
268 {
269         char protostr[256];
270         int ret;
271
272         memset(pp, 0, sizeof(*pp));
273
274         ret = find_protostr(protostr, sizeof(protostr), fhdr, sym);
275         if (ret != 0) {
276                 printf("%s: sym '%s' is missing\n", hdrfn, sym);
277                 return ret;
278         }
279
280         return parse_protostr(protostr, pp);
281 }
282
283 static void proto_release(struct parsed_proto *pp)
284 {
285         int i;
286
287         for (i = 0; i < pp->argc; i++) {
288                 if (pp->arg[i].reg == NULL)
289                         free(pp->arg[i].reg);
290         }
291 }