use unsigned types, cc+nested branch fix, var type cast
[ia32rtools.git] / tools / protoparse.h
CommitLineData
c36e914d 1
39b168b8 2struct parsed_proto;
3
3ebea2cf 4struct parsed_type {
5 char *name;
6 unsigned int is_array:1;
7 unsigned int is_ptr:1;
8};
9
39b168b8 10struct parsed_proto_arg {
11 char *reg;
3ebea2cf 12 struct parsed_type type;
39b168b8 13 struct parsed_proto *fptr;
14 void *datap;
15};
16
c36e914d 17struct parsed_proto {
39b168b8 18 char name[256];
3ebea2cf 19 union {
20 struct parsed_type ret_type;
21 struct parsed_type type;
22 };
39b168b8 23 struct parsed_proto_arg arg[16];
c36e914d 24 int argc;
25 int argc_stack;
26 int argc_reg;
06c5d854 27 unsigned int is_func:1;
39b168b8 28 unsigned int is_stdcall:1;
7ba45c34 29 unsigned int is_vararg:1;
39b168b8 30 unsigned int is_fptr:1;
e56ab892 31 unsigned int is_noreturn:1;
c36e914d 32};
33
34static const char *hdrfn;
35static int hdrfline = 0;
36
39b168b8 37static int find_protostr(char *dst, size_t dlen, FILE *fhdr,
38 const char *fname, const char *sym_)
c36e914d 39{
39b168b8 40 const char *sym = sym_;
06c5d854 41 const char *finc_name;
39b168b8 42 FILE *finc;
43 int symlen;
c36e914d 44 int line = 0;
39b168b8 45 int ret;
c36e914d 46 char *p;
47
39b168b8 48 if (sym[0] == '_' && strncmp(fname, "stdc", 4) == 0)
49 sym++;
50 symlen = strlen(sym);
51
c36e914d 52 rewind(fhdr);
53
54 while (fgets(dst, dlen, fhdr))
55 {
56 line++;
06c5d854 57 if (strncmp(dst, "//#include ", 11) == 0) {
58 finc_name = dst + 11;
59 p = strpbrk(finc_name, "\r\n ");
39b168b8 60 if (p != NULL)
61 *p = 0;
62
06c5d854 63 finc = fopen(finc_name, "r");
39b168b8 64 if (finc == NULL) {
65 printf("%s:%d: can't open '%s'\n",
06c5d854 66 fname, line, finc_name);
39b168b8 67 continue;
68 }
69 ret = find_protostr(dst, dlen, finc,
06c5d854 70 finc_name, sym_);
39b168b8 71 fclose(finc);
72 if (ret == 0)
73 break;
74 continue;
75 }
06c5d854 76 if (strncmp(sskip(dst), "//", 2) == 0)
77 continue;
39b168b8 78
79 p = strstr(dst, sym);
06c5d854 80 if (p != NULL && p > dst
81 && (my_isblank(p[-1]) || my_issep(p[-1]))
39b168b8 82 && (my_isblank(p[symlen]) || my_issep(p[symlen])))
c36e914d 83 break;
84 }
85 hdrfline = line;
86
87 if (feof(fhdr))
88 return -1;
89
90 p = dst + strlen(dst);
91 for (p--; p > dst && my_isblank(*p); --p)
92 *p = 0;
93
94 return 0;
95}
96
97static int get_regparm(char *dst, size_t dlen, char *p)
98{
99 int i, o;
100
101 if (*p != '<')
102 return 0;
103
104 for (o = 0, i = 1; o < dlen; i++) {
105 if (p[i] == 0)
106 return 0;
107 if (p[i] == '>')
108 break;
109 dst[o++] = p[i];
110 }
111 dst[o] = 0;
112 return i + 1;
113}
114
115// hmh..
64c59faf 116static const char *known_type_mod[] = {
117 "const",
118 "signed",
119 "unsigned",
3ebea2cf 120 "struct",
121 "enum",
64c59faf 122};
123
3ebea2cf 124static const char *known_ptr_types[] = {
e56ab892 125 "HACCEL",
c36e914d 126 "HANDLE",
e56ab892 127 "HBITMAP",
128 "HCURSOR",
3ebea2cf 129 "HDC",
130 "HGDIOBJ",
e56ab892 131 "HGLOBAL",
132 "HINSTANCE",
133 "HMODULE",
134 "HRGN",
135 "HRSRC",
136 "HKEY",
137 "HMENU",
138 "HWND",
3ebea2cf 139 "PLONG",
140 "PDWORD",
141 "PVOID",
142 "PCVOID",
e56ab892 143 "DLGPROC",
4f12f671 144 "va_list",
145 "__VALIST",
3ebea2cf 146};
147
148static const char *ignored_keywords[] = {
149 "extern",
150 "WINBASEAPI",
151 "WINUSERAPI",
4f12f671 152 "WINGDIAPI",
153 "WINADVAPI",
c36e914d 154};
155
64c59faf 156// returns ptr to char after type ends
3ebea2cf 157static int typecmp(const char *n, const char *t)
39b168b8 158{
159 for (; *t != 0; n++, t++) {
160 while (n[0] == ' ' && (n[1] == ' ' || n[1] == '*'))
161 n++;
162 while (t[0] == ' ' && (t[1] == ' ' || t[1] == '*'))
163 t++;
164 if (*n != *t)
3ebea2cf 165 return *n - *t;
39b168b8 166 }
167
3ebea2cf 168 return 0;
39b168b8 169}
170
3ebea2cf 171static const char *skip_type_mod(const char *n)
c36e914d 172{
64c59faf 173 int len;
39b168b8 174 int i;
c36e914d 175
64c59faf 176 for (i = 0; i < ARRAY_SIZE(known_type_mod); i++) {
177 len = strlen(known_type_mod[i]);
178 if (strncmp(n, known_type_mod[i], len) != 0)
179 continue;
180
181 n += len;
182 while (my_isblank(*n))
183 n++;
184 i = 0;
185 }
186
3ebea2cf 187 return n;
188}
189
190static int check_type(const char *name, struct parsed_type *type)
191{
192 const char *n, *n1;
193 int ret = -1;
194 int i;
195
196 n = skip_type_mod(name);
197
198 for (i = 0; i < ARRAY_SIZE(known_ptr_types); i++) {
199 if (typecmp(n, known_ptr_types[i]))
64c59faf 200 continue;
201
3ebea2cf 202 type->is_ptr = 1;
203 break;
c36e914d 204 }
205
3ebea2cf 206 if (n[0] == 'L' && n[1] == 'P')
207 type->is_ptr = 1;
208
209 // assume single word
210 while (!my_isblank(*n) && !my_issep(*n))
211 n++;
212
213 while (1) {
214 n1 = n;
215 while (my_isblank(*n))
216 n++;
217 if (*n == '*') {
218 type->is_ptr = 1;
219 n++;
220 continue;
221 }
222 break;
223 }
224
225 ret = n1 - name;
226 type->name = strndup(name, ret);
227 return ret;
c36e914d 228}
229
230/* args are always expanded to 32bit */
231static const char *map_reg(const char *reg)
232{
233 const char *regs_f[] = { "eax", "ebx", "ecx", "edx", "esi", "edi" };
234 const char *regs_w[] = { "ax", "bx", "cx", "dx", "si", "di" };
235 const char *regs_b[] = { "al", "bl", "cl", "dl" };
236 int i;
237
238 for (i = 0; i < ARRAY_SIZE(regs_w); i++)
239 if (IS(reg, regs_w[i]))
240 return regs_f[i];
241
242 for (i = 0; i < ARRAY_SIZE(regs_b); i++)
243 if (IS(reg, regs_b[i]))
244 return regs_f[i];
245
246 return reg;
247}
248
249static int parse_protostr(char *protostr, struct parsed_proto *pp)
250{
39b168b8 251 struct parsed_proto_arg *arg;
c36e914d 252 char regparm[16];
253 char buf[256];
254 char cconv[32];
c36e914d 255 int xarg = 0;
39b168b8 256 char *p, *p1;
3ebea2cf 257 int i, l;
c36e914d 258 int ret;
c36e914d 259
06c5d854 260 p = sskip(protostr);
c36e914d 261 if (p[0] == '/' && p[1] == '/') {
06c5d854 262 printf("%s:%d: commented out?\n", hdrfn, hdrfline);
c36e914d 263 p = sskip(p + 2);
264 }
265
06c5d854 266 // strip unneeded stuff
267 for (p1 = p; p1[0] != 0 && p1[1] != 0; p1++) {
268 if ((p1[0] == '/' && p1[1] == '*')
269 || (p1[0] == '*' && p1[1] == '/'))
270 p1[0] = p1[1] = ' ';
271 }
272
e56ab892 273 if (!strncmp(p, "DECLSPEC_NORETURN ", 18)) {
274 pp->is_noreturn = 1;
275 p = sskip(p + 18);
276 }
277
3ebea2cf 278 for (i = 0; i < ARRAY_SIZE(ignored_keywords); i++) {
279 l = strlen(ignored_keywords[i]);
280 if (!strncmp(p, ignored_keywords[i], l) && my_isblank(p[l]))
281 p = sskip(p + l + 1);
282 }
06c5d854 283
3ebea2cf 284 ret = check_type(p, &pp->ret_type);
285 if (ret <= 0) {
63df67be 286 printf("%s:%d:%zd: unhandled return in '%s'\n",
c36e914d 287 hdrfn, hdrfline, (p - protostr) + 1, protostr);
39b168b8 288 return -1;
c36e914d 289 }
64c59faf 290 p = sskip(p + ret);
c36e914d 291
06c5d854 292 if (!strchr(p, ')')) {
293 p = next_idt(buf, sizeof(buf), p);
294 p = sskip(p);
295 if (buf[0] == 0) {
63df67be 296 printf("%s:%d:%zd: var name missing\n",
06c5d854 297 hdrfn, hdrfline, (p - protostr) + 1);
298 return -1;
299 }
300 strcpy(pp->name, buf);
301
302 p1 = strchr(p, ']');
303 if (p1 != NULL) {
304 p = p1 + 1;
3ebea2cf 305 pp->ret_type.is_array = 1;
06c5d854 306 }
307 return p - protostr;
308 }
309
310 pp->is_func = 1;
311
39b168b8 312 if (*p == '(') {
313 pp->is_fptr = 1;
314 p = sskip(p + 1);
315 }
316
c36e914d 317 p = next_word(cconv, sizeof(cconv), p);
318 p = sskip(p);
319 if (cconv[0] == 0) {
63df67be 320 printf("%s:%d:%zd: cconv missing\n",
c36e914d 321 hdrfn, hdrfline, (p - protostr) + 1);
39b168b8 322 return -1;
c36e914d 323 }
324 if (IS(cconv, "__cdecl"))
325 pp->is_stdcall = 0;
326 else if (IS(cconv, "__stdcall"))
327 pp->is_stdcall = 1;
328 else if (IS(cconv, "__fastcall"))
329 pp->is_stdcall = 1;
330 else if (IS(cconv, "__thiscall"))
331 pp->is_stdcall = 1;
332 else if (IS(cconv, "__userpurge"))
de50b98b 333 pp->is_stdcall = 1; // IDA
c36e914d 334 else if (IS(cconv, "__usercall"))
de50b98b 335 pp->is_stdcall = 0; // IDA
64c59faf 336 else if (IS(cconv, "WINAPI"))
337 pp->is_stdcall = 1;
c36e914d 338 else {
63df67be 339 printf("%s:%d:%zd: unhandled cconv: '%s'\n",
c36e914d 340 hdrfn, hdrfline, (p - protostr) + 1, cconv);
39b168b8 341 return -1;
342 }
343
344 if (pp->is_fptr) {
345 if (*p != '*') {
63df67be 346 printf("%s:%d:%zd: '*' expected\n",
39b168b8 347 hdrfn, hdrfline, (p - protostr) + 1);
348 return -1;
349 }
350 p = sskip(p + 1);
c36e914d 351 }
352
353 p = next_idt(buf, sizeof(buf), p);
354 p = sskip(p);
355 if (buf[0] == 0) {
de50b98b 356 //printf("%s:%d:%zd: func name missing\n",
357 // hdrfn, hdrfline, (p - protostr) + 1);
358 //return -1;
c36e914d 359 }
39b168b8 360 strcpy(pp->name, buf);
c36e914d 361
362 ret = get_regparm(regparm, sizeof(regparm), p);
363 if (ret > 0) {
364 if (!IS(regparm, "eax") && !IS(regparm, "ax")
2b43685d 365 && !IS(regparm, "al") && !IS(regparm, "edx:eax"))
c36e914d 366 {
63df67be 367 printf("%s:%d:%zd: bad regparm: %s\n",
c36e914d 368 hdrfn, hdrfline, (p - protostr) + 1, regparm);
39b168b8 369 return -1;
c36e914d 370 }
371 p += ret;
372 p = sskip(p);
373 }
374
39b168b8 375 if (pp->is_fptr) {
376 if (*p != ')') {
63df67be 377 printf("%s:%d:%zd: ')' expected\n",
39b168b8 378 hdrfn, hdrfline, (p - protostr) + 1);
379 return -1;
380 }
381 p = sskip(p + 1);
382 }
383
c36e914d 384 if (*p != '(') {
63df67be 385 printf("%s:%d:%zd: '(' expected, got '%c'\n",
c36e914d 386 hdrfn, hdrfline, (p - protostr) + 1, *p);
39b168b8 387 return -1;
c36e914d 388 }
389 p++;
390
39b168b8 391 // check for x(void)
392 p = sskip(p);
06c5d854 393 if ((!strncmp(p, "void", 4) || !strncmp(p, "VOID", 4))
394 && *sskip(p + 4) == ')')
39b168b8 395 p += 4;
396
c36e914d 397 while (1) {
398 p = sskip(p);
39b168b8 399 if (*p == ')') {
400 p++;
c36e914d 401 break;
39b168b8 402 }
c36e914d 403 if (*p == ',')
404 p = sskip(p + 1);
405
7ba45c34 406 if (!strncmp(p, "...", 3)) {
407 pp->is_vararg = 1;
408 p = sskip(p + 3);
409 if (*p == ')') {
410 p++;
411 break;
412 }
63df67be 413 printf("%s:%d:%zd: ')' expected\n",
7ba45c34 414 hdrfn, hdrfline, (p - protostr) + 1);
415 return -1;
416 }
417
39b168b8 418 arg = &pp->arg[xarg];
c36e914d 419 xarg++;
420
39b168b8 421 p1 = p;
3ebea2cf 422 ret = check_type(p, &arg->type);
423 if (ret <= 0) {
63df67be 424 printf("%s:%d:%zd: unhandled type for arg%d\n",
c36e914d 425 hdrfn, hdrfline, (p - protostr) + 1, xarg);
39b168b8 426 return -1;
c36e914d 427 }
64c59faf 428 p = sskip(p + ret);
c36e914d 429
39b168b8 430 if (*p == '(') {
431 // func ptr
432 arg->fptr = calloc(1, sizeof(*arg->fptr));
433 ret = parse_protostr(p1, arg->fptr);
434 if (ret < 0) {
63df67be 435 printf("%s:%d:%zd: funcarg parse failed\n",
39b168b8 436 hdrfn, hdrfline, p1 - protostr);
437 return -1;
438 }
439 // we'll treat it as void * for non-calls
3ebea2cf 440 arg->type.name = "void *";
441 arg->type.is_ptr = 1;
39b168b8 442
443 p = p1 + ret;
444 }
445
c36e914d 446 p = next_idt(buf, sizeof(buf), p);
447 p = sskip(p);
448#if 0
449 if (buf[0] == 0) {
63df67be 450 printf("%s:%d:%zd: idt missing for arg%d\n",
c36e914d 451 hdrfn, hdrfline, (p - protostr) + 1, xarg);
39b168b8 452 return -1;
c36e914d 453 }
454#endif
39b168b8 455 arg->reg = NULL;
c36e914d 456
457 ret = get_regparm(regparm, sizeof(regparm), p);
458 if (ret > 0) {
459 p += ret;
460 p = sskip(p);
461
39b168b8 462 arg->reg = strdup(map_reg(regparm));
c36e914d 463 }
464 }
465
466 if (xarg > 0 && (IS(cconv, "__fastcall") || IS(cconv, "__thiscall"))) {
467 if (pp->arg[0].reg != NULL) {
468 printf("%s:%d: %s with arg1 spec %s?\n",
469 hdrfn, hdrfline, cconv, pp->arg[0].reg);
470 }
471 pp->arg[0].reg = strdup("ecx");
472 }
473
474 if (xarg > 1 && IS(cconv, "__fastcall")) {
475 if (pp->arg[1].reg != NULL) {
476 printf("%s:%d: %s with arg2 spec %s?\n",
477 hdrfn, hdrfline, cconv, pp->arg[1].reg);
478 }
479 pp->arg[1].reg = strdup("edx");
480 }
481
7ba45c34 482 if (pp->is_vararg && pp->is_stdcall) {
483 printf("%s:%d: vararg stdcall?\n", hdrfn, hdrfline);
484 return -1;
485 }
486
c36e914d 487 pp->argc = xarg;
488
489 for (i = 0; i < pp->argc; i++) {
490 if (pp->arg[i].reg == NULL)
491 pp->argc_stack++;
492 else
493 pp->argc_reg++;
494 }
495
39b168b8 496 return p - protostr;
c36e914d 497}
498
499static int proto_parse(FILE *fhdr, const char *sym, struct parsed_proto *pp)
500{
501 char protostr[256];
502 int ret;
503
504 memset(pp, 0, sizeof(*pp));
505
39b168b8 506 ret = find_protostr(protostr, sizeof(protostr), fhdr, hdrfn, sym);
c36e914d 507 if (ret != 0) {
508 printf("%s: sym '%s' is missing\n", hdrfn, sym);
509 return ret;
510 }
511
39b168b8 512 return parse_protostr(protostr, pp) < 0 ? -1 : 0;
c36e914d 513}
514
515static void proto_release(struct parsed_proto *pp)
516{
517 int i;
518
519 for (i = 0; i < pp->argc; i++) {
39b168b8 520 if (pp->arg[i].reg != NULL)
c36e914d 521 free(pp->arg[i].reg);
3ebea2cf 522 if (pp->arg[i].type.name != NULL)
523 free(pp->arg[i].type.name);
39b168b8 524 if (pp->arg[i].fptr != NULL)
525 free(pp->arg[i].fptr);
c36e914d 526 }
3ebea2cf 527 if (pp->ret_type.name != NULL)
528 free(pp->ret_type.name);
c36e914d 529}