more wip, handle C calls
[ia32rtools.git] / tools / protoparse.h
CommitLineData
c36e914d 1
39b168b8 2struct parsed_proto;
3
4struct parsed_proto_arg {
5 char *reg;
6 const char *type;
7 struct parsed_proto *fptr;
8 void *datap;
9};
10
c36e914d 11struct parsed_proto {
39b168b8 12 char name[256];
c36e914d 13 const char *ret_type;
39b168b8 14 struct parsed_proto_arg arg[16];
c36e914d 15 int argc;
16 int argc_stack;
17 int argc_reg;
39b168b8 18 unsigned int is_stdcall:1;
19 unsigned int is_fptr:1;
c36e914d 20};
21
22static const char *hdrfn;
23static int hdrfline = 0;
24
39b168b8 25static int find_protostr(char *dst, size_t dlen, FILE *fhdr,
26 const char *fname, const char *sym_)
c36e914d 27{
39b168b8 28 const char *sym = sym_;
29 FILE *finc;
30 int symlen;
c36e914d 31 int line = 0;
39b168b8 32 int ret;
c36e914d 33 char *p;
34
39b168b8 35 if (sym[0] == '_' && strncmp(fname, "stdc", 4) == 0)
36 sym++;
37 symlen = strlen(sym);
38
c36e914d 39 rewind(fhdr);
40
41 while (fgets(dst, dlen, fhdr))
42 {
43 line++;
39b168b8 44 if (strncmp(dst, "#include ", 9) == 0) {
45 p = strpbrk(dst + 9, "\r\n ");
46 if (p != NULL)
47 *p = 0;
48
49 finc = fopen(dst + 9, "r");
50 if (finc == NULL) {
51 printf("%s:%d: can't open '%s'\n",
52 fname, line, dst + 9);
53 continue;
54 }
55 ret = find_protostr(dst, dlen, finc,
56 dst + 9, sym_);
57 fclose(finc);
58 if (ret == 0)
59 break;
60 continue;
61 }
62
63 p = strstr(dst, sym);
64 if (p != NULL
65 && (my_isblank(p[symlen]) || my_issep(p[symlen])))
c36e914d 66 break;
67 }
68 hdrfline = line;
69
70 if (feof(fhdr))
71 return -1;
72
73 p = dst + strlen(dst);
74 for (p--; p > dst && my_isblank(*p); --p)
75 *p = 0;
76
77 return 0;
78}
79
80static int get_regparm(char *dst, size_t dlen, char *p)
81{
82 int i, o;
83
84 if (*p != '<')
85 return 0;
86
87 for (o = 0, i = 1; o < dlen; i++) {
88 if (p[i] == 0)
89 return 0;
90 if (p[i] == '>')
91 break;
92 dst[o++] = p[i];
93 }
94 dst[o] = 0;
95 return i + 1;
96}
97
98// hmh..
99static const char *known_types[] = {
100 "const void *",
101 "void *",
102 "char *",
103 "FILE *",
f3d05b09 104 "int *",
c36e914d 105 "unsigned __int8",
106 "unsigned __int16",
107 "unsigned int",
108 "signed int",
109 "char",
110 "__int8",
111 "__int16",
112 "int",
113 "bool",
114 "void",
115 "BYTE",
116 "WORD",
117 "DWORD",
91977a1c 118 "_DWORD",
c36e914d 119 "HMODULE",
120 "HANDLE",
121 "HWND",
122 "LPCSTR",
123 "size_t",
124};
125
39b168b8 126static int typecmp(const char *n, const char *t)
127{
128 for (; *t != 0; n++, t++) {
129 while (n[0] == ' ' && (n[1] == ' ' || n[1] == '*'))
130 n++;
131 while (t[0] == ' ' && (t[1] == ' ' || t[1] == '*'))
132 t++;
133 if (*n != *t)
134 return *n - *t;
135 }
136
137 return 0;
138}
139
c36e914d 140static const char *check_type(const char *name)
141{
39b168b8 142 int i;
c36e914d 143
144 for (i = 0; i < ARRAY_SIZE(known_types); i++) {
39b168b8 145 if (typecmp(name, known_types[i]) == 0)
c36e914d 146 return known_types[i];
147 }
148
149 return NULL;
150}
151
152/* args are always expanded to 32bit */
153static const char *map_reg(const char *reg)
154{
155 const char *regs_f[] = { "eax", "ebx", "ecx", "edx", "esi", "edi" };
156 const char *regs_w[] = { "ax", "bx", "cx", "dx", "si", "di" };
157 const char *regs_b[] = { "al", "bl", "cl", "dl" };
158 int i;
159
160 for (i = 0; i < ARRAY_SIZE(regs_w); i++)
161 if (IS(reg, regs_w[i]))
162 return regs_f[i];
163
164 for (i = 0; i < ARRAY_SIZE(regs_b); i++)
165 if (IS(reg, regs_b[i]))
166 return regs_f[i];
167
168 return reg;
169}
170
171static int parse_protostr(char *protostr, struct parsed_proto *pp)
172{
39b168b8 173 struct parsed_proto_arg *arg;
c36e914d 174 char regparm[16];
175 char buf[256];
176 char cconv[32];
177 const char *kt;
178 int xarg = 0;
39b168b8 179 char *p, *p1;
c36e914d 180 int ret;
c36e914d 181 int i;
182
183 p = protostr;
184 if (p[0] == '/' && p[1] == '/') {
185 //printf("warning: decl for sym '%s' is commented out\n", sym);
186 p = sskip(p + 2);
187 }
188
189 kt = check_type(p);
190 if (kt == NULL) {
191 printf("%s:%d:%ld: unhandled return in '%s'\n",
192 hdrfn, hdrfline, (p - protostr) + 1, protostr);
39b168b8 193 return -1;
c36e914d 194 }
195 pp->ret_type = kt;
196 p += strlen(kt);
197 p = sskip(p);
198
39b168b8 199 if (*p == '(') {
200 pp->is_fptr = 1;
201 p = sskip(p + 1);
202 }
203
c36e914d 204 p = next_word(cconv, sizeof(cconv), p);
205 p = sskip(p);
206 if (cconv[0] == 0) {
207 printf("%s:%d:%ld: cconv missing\n",
208 hdrfn, hdrfline, (p - protostr) + 1);
39b168b8 209 return -1;
c36e914d 210 }
211 if (IS(cconv, "__cdecl"))
212 pp->is_stdcall = 0;
213 else if (IS(cconv, "__stdcall"))
214 pp->is_stdcall = 1;
215 else if (IS(cconv, "__fastcall"))
216 pp->is_stdcall = 1;
217 else if (IS(cconv, "__thiscall"))
218 pp->is_stdcall = 1;
219 else if (IS(cconv, "__userpurge"))
220 pp->is_stdcall = 1; // in all cases seen..
221 else if (IS(cconv, "__usercall"))
222 pp->is_stdcall = 0; // ..or is it?
223 else {
224 printf("%s:%d:%ld: unhandled cconv: '%s'\n",
225 hdrfn, hdrfline, (p - protostr) + 1, cconv);
39b168b8 226 return -1;
227 }
228
229 if (pp->is_fptr) {
230 if (*p != '*') {
231 printf("%s:%d:%ld: '*' expected\n",
232 hdrfn, hdrfline, (p - protostr) + 1);
233 return -1;
234 }
235 p = sskip(p + 1);
c36e914d 236 }
237
238 p = next_idt(buf, sizeof(buf), p);
239 p = sskip(p);
240 if (buf[0] == 0) {
241 printf("%s:%d:%ld: func name missing\n",
39b168b8 242 hdrfn, hdrfline, (p - protostr) + 1);
243 return -1;
c36e914d 244 }
39b168b8 245 strcpy(pp->name, buf);
c36e914d 246
247 ret = get_regparm(regparm, sizeof(regparm), p);
248 if (ret > 0) {
249 if (!IS(regparm, "eax") && !IS(regparm, "ax")
250 && !IS(regparm, "al"))
251 {
252 printf("%s:%d:%ld: bad regparm: %s\n",
253 hdrfn, hdrfline, (p - protostr) + 1, regparm);
39b168b8 254 return -1;
c36e914d 255 }
256 p += ret;
257 p = sskip(p);
258 }
259
39b168b8 260 if (pp->is_fptr) {
261 if (*p != ')') {
262 printf("%s:%d:%ld: ')' expected\n",
263 hdrfn, hdrfline, (p - protostr) + 1);
264 return -1;
265 }
266 p = sskip(p + 1);
267 }
268
c36e914d 269 if (*p != '(') {
270 printf("%s:%d:%ld: '(' expected, got '%c'\n",
271 hdrfn, hdrfline, (p - protostr) + 1, *p);
39b168b8 272 return -1;
c36e914d 273 }
274 p++;
275
39b168b8 276 // check for x(void)
277 p = sskip(p);
278 if (strncmp(p, "void", 4) == 0 && *sskip(p + 4) == ')')
279 p += 4;
280
c36e914d 281 while (1) {
282 p = sskip(p);
39b168b8 283 if (*p == ')') {
284 p++;
c36e914d 285 break;
39b168b8 286 }
c36e914d 287 if (*p == ',')
288 p = sskip(p + 1);
289
39b168b8 290 arg = &pp->arg[xarg];
c36e914d 291 xarg++;
292
39b168b8 293 p1 = p;
c36e914d 294 kt = check_type(p);
295 if (kt == NULL) {
296 printf("%s:%d:%ld: unhandled type for arg%d\n",
297 hdrfn, hdrfline, (p - protostr) + 1, xarg);
39b168b8 298 return -1;
c36e914d 299 }
39b168b8 300 arg->type = kt;
c36e914d 301 p += strlen(kt);
302 p = sskip(p);
303
39b168b8 304 if (*p == '(') {
305 // func ptr
306 arg->fptr = calloc(1, sizeof(*arg->fptr));
307 ret = parse_protostr(p1, arg->fptr);
308 if (ret < 0) {
309 printf("%s:%d:%ld: funcarg parse failed\n",
310 hdrfn, hdrfline, p1 - protostr);
311 return -1;
312 }
313 // we'll treat it as void * for non-calls
314 arg->type = "void *";
315
316 p = p1 + ret;
317 }
318
c36e914d 319 p = next_idt(buf, sizeof(buf), p);
320 p = sskip(p);
321#if 0
322 if (buf[0] == 0) {
323 printf("%s:%d:%ld: idt missing for arg%d\n",
324 hdrfn, hdrfline, (p - protostr) + 1, xarg);
39b168b8 325 return -1;
c36e914d 326 }
327#endif
39b168b8 328 arg->reg = NULL;
c36e914d 329
330 ret = get_regparm(regparm, sizeof(regparm), p);
331 if (ret > 0) {
332 p += ret;
333 p = sskip(p);
334
39b168b8 335 arg->reg = strdup(map_reg(regparm));
c36e914d 336 }
337 }
338
339 if (xarg > 0 && (IS(cconv, "__fastcall") || IS(cconv, "__thiscall"))) {
340 if (pp->arg[0].reg != NULL) {
341 printf("%s:%d: %s with arg1 spec %s?\n",
342 hdrfn, hdrfline, cconv, pp->arg[0].reg);
343 }
344 pp->arg[0].reg = strdup("ecx");
345 }
346
347 if (xarg > 1 && IS(cconv, "__fastcall")) {
348 if (pp->arg[1].reg != NULL) {
349 printf("%s:%d: %s with arg2 spec %s?\n",
350 hdrfn, hdrfline, cconv, pp->arg[1].reg);
351 }
352 pp->arg[1].reg = strdup("edx");
353 }
354
355 pp->argc = xarg;
356
357 for (i = 0; i < pp->argc; i++) {
358 if (pp->arg[i].reg == NULL)
359 pp->argc_stack++;
360 else
361 pp->argc_reg++;
362 }
363
39b168b8 364 return p - protostr;
c36e914d 365}
366
367static int proto_parse(FILE *fhdr, const char *sym, struct parsed_proto *pp)
368{
369 char protostr[256];
370 int ret;
371
372 memset(pp, 0, sizeof(*pp));
373
39b168b8 374 ret = find_protostr(protostr, sizeof(protostr), fhdr, hdrfn, sym);
c36e914d 375 if (ret != 0) {
376 printf("%s: sym '%s' is missing\n", hdrfn, sym);
377 return ret;
378 }
379
39b168b8 380 return parse_protostr(protostr, pp) < 0 ? -1 : 0;
c36e914d 381}
382
383static void proto_release(struct parsed_proto *pp)
384{
385 int i;
386
387 for (i = 0; i < pp->argc; i++) {
39b168b8 388 if (pp->arg[i].reg != NULL)
c36e914d 389 free(pp->arg[i].reg);
39b168b8 390 if (pp->arg[i].fptr != NULL)
391 free(pp->arg[i].fptr);
c36e914d 392 }
393}