translate: more float stuff
[ia32rtools.git] / tools / protoparse.h
CommitLineData
7637b6cc 1/*
2 * ia32rtools
3 * (C) notaz, 2013,2014
4 *
5 * This work is licensed under the terms of 3-clause BSD license.
6 * See COPYING file in the top-level directory.
7 */
c36e914d 8
39b168b8 9struct parsed_proto;
10
3ebea2cf 11struct parsed_type {
12 char *name;
13 unsigned int is_array:1;
14 unsigned int is_ptr:1;
a652aa9f 15 unsigned int is_struct:1; // split for args
5f70a34f 16 unsigned int is_retreg:1; // register to return to caller
17 unsigned int is_va_list:1;
2c31fb4c 18 unsigned int is_64bit:1;
3ebea2cf 19};
20
39b168b8 21struct parsed_proto_arg {
22 char *reg;
3ebea2cf 23 struct parsed_type type;
93b5bd18 24 struct parsed_proto *pp; // fptr or struct
39b168b8 25 void *datap;
8c83cc48 26 unsigned int is_saved:1; // not set here, for tool use
39b168b8 27};
28
c36e914d 29struct parsed_proto {
39b168b8 30 char name[256];
3ebea2cf 31 union {
32 struct parsed_type ret_type;
33 struct parsed_type type;
34 };
39b168b8 35 struct parsed_proto_arg arg[16];
c36e914d 36 int argc;
37 int argc_stack;
38 int argc_reg;
06c5d854 39 unsigned int is_func:1;
39b168b8 40 unsigned int is_stdcall:1;
c0050df6 41 unsigned int is_fastcall:1;
efea2951 42 unsigned int is_vararg:1; // vararg func
39b168b8 43 unsigned int is_fptr:1;
e56ab892 44 unsigned int is_noreturn:1;
89ff3147 45 unsigned int is_unresolved:1;
1f84f6b3 46 unsigned int is_userstack:1;
61e29183 47 unsigned int is_include:1; // not from top-level header
48 unsigned int is_osinc:1; // OS/system library func
ebc4dc43 49 unsigned int is_cinc:1; // crt library func
179b79a9 50 unsigned int is_arg:1; // declared in some func arg
a652aa9f 51 unsigned int has_structarg:1;
1f84f6b3 52 unsigned int has_retreg:1;
c36e914d 53};
54
865f1aca 55struct parsed_struct {
56 char name[256];
57 struct {
58 int offset;
59 struct parsed_proto pp;
60 } members[64];
61 int member_count;
62};
63
c36e914d 64static const char *hdrfn;
65static int hdrfline = 0;
66
a652aa9f 67static void pp_copy_arg(struct parsed_proto_arg *d,
68 const struct parsed_proto_arg *s);
69
61e29183 70static int b_pp_c_handler(char *proto, const char *fname,
ebc4dc43 71 int is_include, int is_osinc, int is_cinc);
865f1aca 72static int struct_handler(FILE *fhdr, char *proto, int *line);
bd96f656 73
61e29183 74static int do_protostrs(FILE *fhdr, const char *fname, int is_include)
c36e914d 75{
06c5d854 76 const char *finc_name;
bd96f656 77 const char *hdrfn_saved;
78 char protostr[256];
36595fd2 79 char path[256];
80 char fname_inc[256];
61e29183 81 int is_osinc;
ebc4dc43 82 int is_cinc;
39b168b8 83 FILE *finc;
c36e914d 84 int line = 0;
39b168b8 85 int ret;
c36e914d 86 char *p;
87
bd96f656 88 hdrfn_saved = hdrfn;
89 hdrfn = fname;
39b168b8 90
ebc4dc43 91 is_cinc = strstr(fname, "stdc.hlist") != NULL;
edeadc28 92 is_osinc = is_cinc || strstr(fname, "win32.hlist") != NULL;
179b79a9 93
bd96f656 94 while (fgets(protostr, sizeof(protostr), fhdr))
c36e914d 95 {
96 line++;
bd96f656 97 if (strncmp(protostr, "//#include ", 11) == 0) {
98 finc_name = protostr + 11;
06c5d854 99 p = strpbrk(finc_name, "\r\n ");
39b168b8 100 if (p != NULL)
101 *p = 0;
102
36595fd2 103 path[0] = 0;
104 p = strrchr(hdrfn_saved, '/');
105 if (p) {
106 memcpy(path, hdrfn_saved,
107 p - hdrfn_saved + 1);
108 path[p - hdrfn_saved + 1] = 0;
109 }
110 snprintf(fname_inc, sizeof(fname_inc), "%s%s",
111 path, finc_name);
112 finc = fopen(fname_inc, "r");
39b168b8 113 if (finc == NULL) {
114 printf("%s:%d: can't open '%s'\n",
36595fd2 115 fname_inc, line, finc_name);
39b168b8 116 continue;
117 }
61e29183 118 ret = do_protostrs(finc, finc_name, 1);
39b168b8 119 fclose(finc);
bd96f656 120 if (ret < 0)
39b168b8 121 break;
122 continue;
123 }
bd96f656 124 if (strncmp(sskip(protostr), "//", 2) == 0)
125 continue;
126
127 p = protostr + strlen(protostr);
128 for (p--; p >= protostr && my_isblank(*p); --p)
129 *p = 0;
130 if (p < protostr)
06c5d854 131 continue;
39b168b8 132
bd96f656 133 hdrfline = line;
134
865f1aca 135 if (!strncmp(protostr, "struct", 6)
136 && strchr(protostr, '{') != NULL)
137 ret = struct_handler(fhdr, protostr, &line);
138 else
139 ret = b_pp_c_handler(protostr, hdrfn,
140 is_include, is_osinc, is_cinc);
bd96f656 141 if (ret < 0)
c36e914d 142 break;
143 }
c36e914d 144
bd96f656 145 hdrfn = hdrfn_saved;
c36e914d 146
bd96f656 147 if (feof(fhdr))
148 return 0;
c36e914d 149
bd96f656 150 return -1;
c36e914d 151}
152
1f84f6b3 153static int get_regparm(char *dst, size_t dlen, char *p, int *retreg)
c36e914d 154{
1f84f6b3 155 int i = 0, o;
156
157 *retreg = 0;
c36e914d 158
159 if (*p != '<')
160 return 0;
161
1f84f6b3 162 i++;
163 if (p[i] == '*') {
164 *retreg = 1;
165 i++;
166 }
167
168 for (o = 0; o < dlen; i++) {
c36e914d 169 if (p[i] == 0)
170 return 0;
171 if (p[i] == '>')
172 break;
173 dst[o++] = p[i];
174 }
175 dst[o] = 0;
176 return i + 1;
177}
178
179// hmh..
64c59faf 180static const char *known_type_mod[] = {
181 "const",
182 "signed",
183 "unsigned",
3ebea2cf 184 "enum",
840257f6 185 "CONST",
92804a48 186 "volatile",
64c59faf 187};
188
3ebea2cf 189static const char *known_ptr_types[] = {
da87ae38 190 "FARPROC",
92804a48 191 "WNDPROC",
bf2471e9 192 "LINECALLBACK",
e56ab892 193 "HACCEL",
c36e914d 194 "HANDLE",
e56ab892 195 "HBITMAP",
79af284c 196 "HBRUSH",
bf2471e9 197 "HCALL",
e56ab892 198 "HCURSOR",
3ebea2cf 199 "HDC",
a652aa9f 200 "HFONT",
3ebea2cf 201 "HGDIOBJ",
e56ab892 202 "HGLOBAL",
79af284c 203 "HHOOK",
da87ae38 204 "HICON",
e56ab892 205 "HINSTANCE",
c7ed83dd 206 "HIMC", // DWORD in mingw, ptr in wine..
bf2471e9 207 "HLINE",
208 "HLINEAPP",
209 "HLOCAL",
e56ab892 210 "HMODULE",
da87ae38 211 "HPALETTE",
e56ab892 212 "HRGN",
213 "HRSRC",
214 "HKEY",
215 "HMENU",
7aca4698 216 "HWAVEOUT",
e56ab892 217 "HWND",
ef6b315d 218 "PBYTE",
a2c1d768 219 "PCRITICAL_SECTION",
3ebea2cf 220 "PDWORD",
92804a48 221 "PFILETIME",
bf2471e9 222 "PLARGE_INTEGER",
79af284c 223 "PHANDLE",
94d447fb 224 "PHKEY",
225 "PLONG",
a2c1d768 226 "PMEMORY_BASIC_INFORMATION",
46411e6c 227 "PUINT",
f9327ad4 228 "PULARGE_INTEGER",
229 "PULONG_PTR",
3ebea2cf 230 "PVOID",
231 "PCVOID",
ef6b315d 232 "PWORD",
79af284c 233 "REFCLSID",
234 "REFIID",
235 "HOOKPROC",
e56ab892 236 "DLGPROC",
cdfaeed7 237 "TIMERPROC",
238 "WNDENUMPROC",
4f12f671 239 "va_list",
240 "__VALIST",
3ebea2cf 241};
242
243static const char *ignored_keywords[] = {
244 "extern",
245 "WINBASEAPI",
246 "WINUSERAPI",
4f12f671 247 "WINGDIAPI",
248 "WINADVAPI",
c36e914d 249};
250
3ebea2cf 251static int typecmp(const char *n, const char *t)
39b168b8 252{
253 for (; *t != 0; n++, t++) {
254 while (n[0] == ' ' && (n[1] == ' ' || n[1] == '*'))
255 n++;
256 while (t[0] == ' ' && (t[1] == ' ' || t[1] == '*'))
257 t++;
258 if (*n != *t)
3ebea2cf 259 return *n - *t;
39b168b8 260 }
261
3ebea2cf 262 return 0;
39b168b8 263}
264
3ebea2cf 265static const char *skip_type_mod(const char *n)
c36e914d 266{
64c59faf 267 int len;
39b168b8 268 int i;
c36e914d 269
64c59faf 270 for (i = 0; i < ARRAY_SIZE(known_type_mod); i++) {
271 len = strlen(known_type_mod[i]);
272 if (strncmp(n, known_type_mod[i], len) != 0)
273 continue;
bd96f656 274 if (!my_isblank(n[len]))
275 continue;
64c59faf 276
277 n += len;
278 while (my_isblank(*n))
279 n++;
280 i = 0;
281 }
282
3ebea2cf 283 return n;
284}
285
286static int check_type(const char *name, struct parsed_type *type)
287{
288 const char *n, *n1;
289 int ret = -1;
290 int i;
291
292 n = skip_type_mod(name);
293
865f1aca 294 if (!strncmp(n, "struct", 6) && my_isblank(n[6])) {
295 type->is_struct = 1;
296
297 n += 6;
298 while (my_isblank(*n))
299 n++;
300 }
301
3ebea2cf 302 for (i = 0; i < ARRAY_SIZE(known_ptr_types); i++) {
303 if (typecmp(n, known_ptr_types[i]))
64c59faf 304 continue;
305
3ebea2cf 306 type->is_ptr = 1;
307 break;
c36e914d 308 }
309
a652aa9f 310 if (n[0] == 'L' && n[1] == 'P' && strncmp(n, "LPARAM", 6))
3ebea2cf 311 type->is_ptr = 1;
312
313 // assume single word
314 while (!my_isblank(*n) && !my_issep(*n))
315 n++;
316
317 while (1) {
318 n1 = n;
319 while (my_isblank(*n))
320 n++;
321 if (*n == '*') {
322 type->is_ptr = 1;
323 n++;
324 continue;
325 }
326 break;
327 }
328
329 ret = n1 - name;
330 type->name = strndup(name, ret);
5f70a34f 331 if (IS(type->name, "__VALIST") || IS(type->name, "va_list"))
332 type->is_va_list = 1;
a2c1d768 333 if (IS(type->name, "VOID"))
334 memcpy(type->name, "void", 4);
335
3ebea2cf 336 return ret;
c36e914d 337}
338
339/* args are always expanded to 32bit */
340static const char *map_reg(const char *reg)
341{
342 const char *regs_f[] = { "eax", "ebx", "ecx", "edx", "esi", "edi" };
343 const char *regs_w[] = { "ax", "bx", "cx", "dx", "si", "di" };
344 const char *regs_b[] = { "al", "bl", "cl", "dl" };
345 int i;
346
347 for (i = 0; i < ARRAY_SIZE(regs_w); i++)
348 if (IS(reg, regs_w[i]))
349 return regs_f[i];
350
351 for (i = 0; i < ARRAY_SIZE(regs_b); i++)
352 if (IS(reg, regs_b[i]))
353 return regs_f[i];
354
355 return reg;
356}
357
a652aa9f 358static int check_struct_arg(struct parsed_proto_arg *arg)
359{
360 if (IS(arg->type.name, "POINT"))
361 return 2 - 1;
362
363 return 0;
364}
365
93b5bd18 366static int parse_protostr(char *protostr, struct parsed_proto *pp);
367
368static int parse_arg(char **p_, struct parsed_proto_arg *arg, int xarg)
369{
370 char buf[256];
371 char *p = *p_;
372 char *pe;
373 int ret;
374
375 arg->pp = calloc(1, sizeof(*arg->pp));
376 my_assert_not(arg->pp, NULL);
377 arg->pp->is_arg = 1;
378
379 pe = p;
380 while (1) {
381 pe = strpbrk(pe, ",()");
382 if (pe == NULL)
383 return -1;
384 if (*pe == ',' || *pe == ')')
385 break;
386 pe = strchr(pe, ')');
387 if (pe == NULL)
388 return -1;
389 pe++;
390 }
391
392 if (pe - p > sizeof(buf) - 1)
393 return -1;
394 memcpy(buf, p, pe - p);
395 buf[pe - p] = 0;
396
397 ret = parse_protostr(buf, arg->pp);
398 if (ret < 0)
399 return -1;
400
401 // we don't use actual names right now...
402 snprintf(arg->pp->name, sizeof(arg->pp->name), "a%d", xarg);
403
404 if (!arg->type.is_struct)
405 // we'll treat it as void * for non-calls
406 arg->type.name = strdup("void *");
407 arg->type.is_ptr = 1;
408
409 p += ret;
410 *p_ = p;
411 return 0;
412}
413
c36e914d 414static int parse_protostr(char *protostr, struct parsed_proto *pp)
415{
39b168b8 416 struct parsed_proto_arg *arg;
c36e914d 417 char regparm[16];
418 char buf[256];
419 char cconv[32];
1f84f6b3 420 int is_retreg;
39b168b8 421 char *p, *p1;
93b5bd18 422 int xarg = 0;
3ebea2cf 423 int i, l;
c36e914d 424 int ret;
c36e914d 425
06c5d854 426 p = sskip(protostr);
c36e914d 427 if (p[0] == '/' && p[1] == '/') {
06c5d854 428 printf("%s:%d: commented out?\n", hdrfn, hdrfline);
c36e914d 429 p = sskip(p + 2);
430 }
431
865f1aca 432 // allow start of line comment
433 if (p[0] == '/' && p[1] == '*') {
434 p = strstr(p + 2, "*/");
435 if (p == NULL) {
436 printf("%s:%d: multiline comments unsupported\n",
437 hdrfn, hdrfline);
438 return -1;
439 }
440 p = sskip(p + 2);
441 }
442
443 // we need remaining hints in comments, so strip / *
06c5d854 444 for (p1 = p; p1[0] != 0 && p1[1] != 0; p1++) {
445 if ((p1[0] == '/' && p1[1] == '*')
446 || (p1[0] == '*' && p1[1] == '/'))
447 p1[0] = p1[1] = ' ';
448 }
449
e56ab892 450 if (!strncmp(p, "DECLSPEC_NORETURN ", 18)) {
451 pp->is_noreturn = 1;
452 p = sskip(p + 18);
453 }
454
3ebea2cf 455 for (i = 0; i < ARRAY_SIZE(ignored_keywords); i++) {
456 l = strlen(ignored_keywords[i]);
457 if (!strncmp(p, ignored_keywords[i], l) && my_isblank(p[l]))
458 p = sskip(p + l + 1);
459 }
06c5d854 460
3ebea2cf 461 ret = check_type(p, &pp->ret_type);
462 if (ret <= 0) {
63df67be 463 printf("%s:%d:%zd: unhandled return in '%s'\n",
c36e914d 464 hdrfn, hdrfline, (p - protostr) + 1, protostr);
39b168b8 465 return -1;
c36e914d 466 }
64c59faf 467 p = sskip(p + ret);
c36e914d 468
da87ae38 469 if (!strncmp(p, "noreturn ", 9)) {
470 pp->is_noreturn = 1;
471 p = sskip(p + 9);
472 }
473
06c5d854 474 if (!strchr(p, ')')) {
475 p = next_idt(buf, sizeof(buf), p);
476 p = sskip(p);
93b5bd18 477 if (!pp->is_arg && buf[0] == 0) {
478 printf("%s:%d:%zd: var name is missing\n",
06c5d854 479 hdrfn, hdrfline, (p - protostr) + 1);
480 return -1;
481 }
482 strcpy(pp->name, buf);
483
484 p1 = strchr(p, ']');
485 if (p1 != NULL) {
486 p = p1 + 1;
3ebea2cf 487 pp->ret_type.is_array = 1;
06c5d854 488 }
489 return p - protostr;
490 }
491
492 pp->is_func = 1;
493
39b168b8 494 if (*p == '(') {
495 pp->is_fptr = 1;
496 p = sskip(p + 1);
497 }
498
c36e914d 499 p = next_word(cconv, sizeof(cconv), p);
500 p = sskip(p);
501 if (cconv[0] == 0) {
63df67be 502 printf("%s:%d:%zd: cconv missing\n",
c36e914d 503 hdrfn, hdrfline, (p - protostr) + 1);
39b168b8 504 return -1;
c36e914d 505 }
506 if (IS(cconv, "__cdecl"))
507 pp->is_stdcall = 0;
508 else if (IS(cconv, "__stdcall"))
509 pp->is_stdcall = 1;
c0050df6 510 else if (IS(cconv, "__fastcall")) {
511 pp->is_fastcall = 1;
512 pp->is_stdcall = 1; // sort of..
513 }
c36e914d 514 else if (IS(cconv, "__thiscall"))
515 pp->is_stdcall = 1;
516 else if (IS(cconv, "__userpurge"))
de50b98b 517 pp->is_stdcall = 1; // IDA
c36e914d 518 else if (IS(cconv, "__usercall"))
de50b98b 519 pp->is_stdcall = 0; // IDA
1f84f6b3 520 else if (IS(cconv, "__userstack")) {
521 pp->is_stdcall = 0; // custom
522 pp->is_userstack = 1;
523 }
79af284c 524 else if (IS(cconv, "WINAPI") || IS(cconv, "PASCAL"))
64c59faf 525 pp->is_stdcall = 1;
c36e914d 526 else {
63df67be 527 printf("%s:%d:%zd: unhandled cconv: '%s'\n",
c36e914d 528 hdrfn, hdrfline, (p - protostr) + 1, cconv);
39b168b8 529 return -1;
530 }
531
532 if (pp->is_fptr) {
533 if (*p != '*') {
63df67be 534 printf("%s:%d:%zd: '*' expected\n",
39b168b8 535 hdrfn, hdrfline, (p - protostr) + 1);
536 return -1;
537 }
bd96f656 538 p++;
539 // XXX: skipping extra asterisks, for now
540 while (*p == '*')
541 p++;
542 p = sskip(p);
c36e914d 543 }
544
545 p = next_idt(buf, sizeof(buf), p);
546 p = sskip(p);
547 if (buf[0] == 0) {
de50b98b 548 //printf("%s:%d:%zd: func name missing\n",
549 // hdrfn, hdrfline, (p - protostr) + 1);
550 //return -1;
c36e914d 551 }
39b168b8 552 strcpy(pp->name, buf);
c36e914d 553
1f84f6b3 554 ret = get_regparm(regparm, sizeof(regparm), p, &is_retreg);
c36e914d 555 if (ret > 0) {
556 if (!IS(regparm, "eax") && !IS(regparm, "ax")
2b43685d 557 && !IS(regparm, "al") && !IS(regparm, "edx:eax"))
c36e914d 558 {
63df67be 559 printf("%s:%d:%zd: bad regparm: %s\n",
c36e914d 560 hdrfn, hdrfline, (p - protostr) + 1, regparm);
39b168b8 561 return -1;
c36e914d 562 }
563 p += ret;
564 p = sskip(p);
565 }
566
39b168b8 567 if (pp->is_fptr) {
bd96f656 568 if (*p == '[') {
569 // not really ret_type is array, but ohwell
570 pp->ret_type.is_array = 1;
571 p = strchr(p + 1, ']');
572 if (p == NULL) {
573 printf("%s:%d:%zd: ']' expected\n",
574 hdrfn, hdrfline, (p - protostr) + 1);
575 return -1;
576 }
577 p = sskip(p + 1);
578 }
39b168b8 579 if (*p != ')') {
63df67be 580 printf("%s:%d:%zd: ')' expected\n",
39b168b8 581 hdrfn, hdrfline, (p - protostr) + 1);
582 return -1;
583 }
584 p = sskip(p + 1);
585 }
586
c36e914d 587 if (*p != '(') {
63df67be 588 printf("%s:%d:%zd: '(' expected, got '%c'\n",
c36e914d 589 hdrfn, hdrfline, (p - protostr) + 1, *p);
39b168b8 590 return -1;
c36e914d 591 }
592 p++;
593
39b168b8 594 // check for x(void)
595 p = sskip(p);
06c5d854 596 if ((!strncmp(p, "void", 4) || !strncmp(p, "VOID", 4))
597 && *sskip(p + 4) == ')')
39b168b8 598 p += 4;
599
c36e914d 600 while (1) {
601 p = sskip(p);
39b168b8 602 if (*p == ')') {
603 p++;
c36e914d 604 break;
39b168b8 605 }
840257f6 606 if (xarg > 0) {
607 if (*p != ',') {
608 printf("%s:%d:%zd: ',' expected\n",
609 hdrfn, hdrfline, (p - protostr) + 1);
610 return -1;
611 }
c36e914d 612 p = sskip(p + 1);
840257f6 613 }
c36e914d 614
7ba45c34 615 if (!strncmp(p, "...", 3)) {
616 pp->is_vararg = 1;
617 p = sskip(p + 3);
618 if (*p == ')') {
619 p++;
620 break;
621 }
63df67be 622 printf("%s:%d:%zd: ')' expected\n",
7ba45c34 623 hdrfn, hdrfline, (p - protostr) + 1);
624 return -1;
625 }
626
39b168b8 627 arg = &pp->arg[xarg];
c36e914d 628 xarg++;
629
39b168b8 630 p1 = p;
3ebea2cf 631 ret = check_type(p, &arg->type);
632 if (ret <= 0) {
63df67be 633 printf("%s:%d:%zd: unhandled type for arg%d\n",
c36e914d 634 hdrfn, hdrfline, (p - protostr) + 1, xarg);
39b168b8 635 return -1;
c36e914d 636 }
64c59faf 637 p = sskip(p + ret);
c36e914d 638
93b5bd18 639 if (*p == '(' || arg->type.is_struct) {
640 // func ptr or struct
641 ret = parse_arg(&p1, arg, xarg);
39b168b8 642 if (ret < 0) {
63df67be 643 printf("%s:%d:%zd: funcarg parse failed\n",
39b168b8 644 hdrfn, hdrfline, p1 - protostr);
645 return -1;
646 }
93b5bd18 647 p = p1;
39b168b8 648 }
649
c36e914d 650 p = next_idt(buf, sizeof(buf), p);
651 p = sskip(p);
652#if 0
653 if (buf[0] == 0) {
63df67be 654 printf("%s:%d:%zd: idt missing for arg%d\n",
c36e914d 655 hdrfn, hdrfline, (p - protostr) + 1, xarg);
39b168b8 656 return -1;
c36e914d 657 }
658#endif
39b168b8 659 arg->reg = NULL;
c36e914d 660
1f84f6b3 661 ret = get_regparm(regparm, sizeof(regparm), p, &is_retreg);
c36e914d 662 if (ret > 0) {
663 p += ret;
664 p = sskip(p);
665
39b168b8 666 arg->reg = strdup(map_reg(regparm));
1f84f6b3 667 arg->type.is_retreg = is_retreg;
668 pp->has_retreg |= is_retreg;
c36e914d 669 }
a652aa9f 670
f9327ad4 671 if (!arg->type.is_ptr && (strstr(arg->type.name, "int64")
672 || IS(arg->type.name, "double")))
7e50b291 673 {
2c31fb4c 674 arg->type.is_64bit = 1;
7e50b291 675 // hack..
7e50b291 676 pp_copy_arg(&pp->arg[xarg], arg);
2c31fb4c 677 arg = &pp->arg[xarg];
7e50b291 678 xarg++;
2c31fb4c 679 free(arg->type.name);
680 arg->type.name = strdup("dummy");
7e50b291 681 }
682
a652aa9f 683 ret = check_struct_arg(arg);
684 if (ret > 0) {
685 pp->has_structarg = 1;
686 arg->type.is_struct = 1;
687 free(arg->type.name);
688 arg->type.name = strdup("int");
689 for (l = 0; l < ret; l++) {
690 pp_copy_arg(&pp->arg[xarg], arg);
691 xarg++;
692 }
693 }
c36e914d 694 }
695
696 if (xarg > 0 && (IS(cconv, "__fastcall") || IS(cconv, "__thiscall"))) {
697 if (pp->arg[0].reg != NULL) {
698 printf("%s:%d: %s with arg1 spec %s?\n",
699 hdrfn, hdrfline, cconv, pp->arg[0].reg);
700 }
701 pp->arg[0].reg = strdup("ecx");
702 }
703
704 if (xarg > 1 && IS(cconv, "__fastcall")) {
705 if (pp->arg[1].reg != NULL) {
706 printf("%s:%d: %s with arg2 spec %s?\n",
707 hdrfn, hdrfline, cconv, pp->arg[1].reg);
708 }
709 pp->arg[1].reg = strdup("edx");
710 }
711
712 pp->argc = xarg;
713
714 for (i = 0; i < pp->argc; i++) {
715 if (pp->arg[i].reg == NULL)
716 pp->argc_stack++;
717 else
718 pp->argc_reg++;
719 }
720
c0050df6 721 if (pp->argc == 1 && pp->arg[0].reg != NULL
722 && IS(pp->arg[0].reg, "ecx"))
723 {
724 pp->is_fastcall = 1;
725 }
726 else if (pp->argc_reg == 2
727 && pp->arg[0].reg != NULL && IS(pp->arg[0].reg, "ecx")
728 && pp->arg[1].reg != NULL && IS(pp->arg[1].reg, "edx"))
729 {
730 pp->is_fastcall = 1;
731 }
732
733 if (pp->is_vararg && (pp->is_stdcall || pp->is_fastcall)) {
734 printf("%s:%d: vararg %s?\n", hdrfn, hdrfline, cconv);
735 return -1;
736 }
737
39b168b8 738 return p - protostr;
c36e914d 739}
740
bd96f656 741static int pp_name_cmp(const void *p1, const void *p2)
742{
743 const struct parsed_proto *pp1 = p1, *pp2 = p2;
744 return strcmp(pp1->name, pp2->name);
745}
746
865f1aca 747static int ps_name_cmp(const void *p1, const void *p2)
748{
749 const struct parsed_struct *ps1 = p1, *ps2 = p2;
750 return strcmp(ps1->name, ps2->name);
751}
752
753// parsed struct cache
754static struct parsed_struct *ps_cache;
755static int ps_cache_size;
756static int ps_cache_alloc;
757
758static int struct_handler(FILE *fhdr, char *proto, int *line)
759{
760 struct parsed_struct *ps;
761 char lstr[256], *p;
762 int offset = 0;
763 int m = 0;
764 int ret;
765
766 if (ps_cache_size >= ps_cache_alloc) {
767 ps_cache_alloc = ps_cache_alloc * 2 + 64;
768 ps_cache = realloc(ps_cache, ps_cache_alloc
769 * sizeof(ps_cache[0]));
770 my_assert_not(ps_cache, NULL);
771 memset(ps_cache + ps_cache_size, 0,
772 (ps_cache_alloc - ps_cache_size)
773 * sizeof(ps_cache[0]));
774 }
775
776 ps = &ps_cache[ps_cache_size++];
777 ret = sscanf(proto, "struct %255s {", ps->name);
778 if (ret != 1) {
779 printf("%s:%d: struct parse failed\n", hdrfn, *line);
780 return -1;
781 }
782
783 while (fgets(lstr, sizeof(lstr), fhdr))
784 {
785 (*line)++;
786
787 p = sskip(lstr);
788 if (p[0] == '/' && p[1] == '/')
789 continue;
790 if (p[0] == '}')
791 break;
792
793 if (m >= ARRAY_SIZE(ps->members)) {
794 printf("%s:%d: too many struct members\n",
795 hdrfn, *line);
796 return -1;
797 }
798
799 hdrfline = *line;
800 ret = parse_protostr(p, &ps->members[m].pp);
801 if (ret < 0) {
802 printf("%s:%d: struct member #%d/%02x "
803 "doesn't parse\n", hdrfn, *line,
804 m, offset);
805 return -1;
806 }
807 ps->members[m].offset = offset;
808 offset += 4;
809 m++;
810 }
811
812 ps->member_count = m;
813
814 return 0;
815}
816
817// parsed proto cache
bd96f656 818static struct parsed_proto *pp_cache;
819static int pp_cache_size;
820static int pp_cache_alloc;
821
61e29183 822static int b_pp_c_handler(char *proto, const char *fname,
ebc4dc43 823 int is_include, int is_osinc, int is_cinc)
bd96f656 824{
825 int ret;
826
827 if (pp_cache_size >= pp_cache_alloc) {
828 pp_cache_alloc = pp_cache_alloc * 2 + 64;
829 pp_cache = realloc(pp_cache, pp_cache_alloc
830 * sizeof(pp_cache[0]));
831 my_assert_not(pp_cache, NULL);
832 memset(pp_cache + pp_cache_size, 0,
833 (pp_cache_alloc - pp_cache_size)
834 * sizeof(pp_cache[0]));
835 }
836
837 ret = parse_protostr(proto, &pp_cache[pp_cache_size]);
838 if (ret < 0)
839 return -1;
840
61e29183 841 pp_cache[pp_cache_size].is_include = is_include;
842 pp_cache[pp_cache_size].is_osinc = is_osinc;
ebc4dc43 843 pp_cache[pp_cache_size].is_cinc = is_cinc;
bd96f656 844 pp_cache_size++;
845 return 0;
846}
847
865f1aca 848static void build_caches(FILE *fhdr)
c36e914d 849{
1f906263 850 long pos;
c36e914d 851 int ret;
852
1f906263 853 pos = ftell(fhdr);
bd96f656 854 rewind(fhdr);
855
61e29183 856 ret = do_protostrs(fhdr, hdrfn, 0);
bd96f656 857 if (ret < 0)
858 exit(1);
859
860 qsort(pp_cache, pp_cache_size, sizeof(pp_cache[0]), pp_name_cmp);
865f1aca 861 qsort(ps_cache, ps_cache_size, sizeof(ps_cache[0]), ps_name_cmp);
1f906263 862 fseek(fhdr, pos, SEEK_SET);
bd96f656 863}
864
36595fd2 865static const struct parsed_proto *proto_parse(FILE *fhdr, const char *sym,
866 int quiet)
bd96f656 867{
868 const struct parsed_proto *pp_ret;
869 struct parsed_proto pp_search;
7aca4698 870 char *p;
bd96f656 871
872 if (pp_cache == NULL)
865f1aca 873 build_caches(fhdr);
bd96f656 874
f9327ad4 875 // ugh...
876 if (sym[0] == '_' && !IS_START(sym, "__W"))
bd96f656 877 sym++;
c36e914d 878
bd96f656 879 strcpy(pp_search.name, sym);
7aca4698 880 p = strchr(pp_search.name, '@');
881 if (p != NULL)
882 *p = 0;
883
bd96f656 884 pp_ret = bsearch(&pp_search, pp_cache, pp_cache_size,
885 sizeof(pp_cache[0]), pp_name_cmp);
36595fd2 886 if (pp_ret == NULL && !quiet)
c36e914d 887 printf("%s: sym '%s' is missing\n", hdrfn, sym);
bd96f656 888
889 return pp_ret;
890}
891
865f1aca 892static const struct parsed_proto *proto_lookup_struct(FILE *fhdr,
893 const char *type, int offset)
894{
895 struct parsed_struct ps_search, *ps;
896 int m;
897
898 if (pp_cache == NULL)
899 build_caches(fhdr);
900 if (ps_cache_size == 0)
901 return NULL;
902
903 while (my_isblank(*type))
904 type++;
905 if (!strncmp(type, "struct", 6) && my_isblank(type[6]))
906 type += 7;
907
908 if (sscanf(type, "%255s", ps_search.name) != 1)
909 return NULL;
910
911 ps = bsearch(&ps_search, ps_cache, ps_cache_size,
912 sizeof(ps_cache[0]), ps_name_cmp);
913 if (ps == NULL) {
914 printf("%s: struct '%s' is missing\n",
915 hdrfn, ps_search.name);
916 return NULL;
917 }
918
919 for (m = 0; m < ps->member_count; m++) {
920 if (ps->members[m].offset == offset)
921 return &ps->members[m].pp;
922 }
923
924 return NULL;
925}
926
a652aa9f 927static void pp_copy_arg(struct parsed_proto_arg *d,
928 const struct parsed_proto_arg *s)
929{
930 memcpy(d, s, sizeof(*d));
931
932 if (s->reg != NULL) {
933 d->reg = strdup(s->reg);
934 my_assert_not(d->reg, NULL);
935 }
936 if (s->type.name != NULL) {
937 d->type.name = strdup(s->type.name);
938 my_assert_not(d->type.name, NULL);
939 }
93b5bd18 940 if (s->pp != NULL) {
941 d->pp = malloc(sizeof(*d->pp));
942 my_assert_not(d->pp, NULL);
943 memcpy(d->pp, s->pp, sizeof(*d->pp));
a652aa9f 944 }
945}
946
bd96f656 947struct parsed_proto *proto_clone(const struct parsed_proto *pp_c)
948{
949 struct parsed_proto *pp;
950 int i;
951
952 pp = malloc(sizeof(*pp));
953 my_assert_not(pp, NULL);
954 memcpy(pp, pp_c, sizeof(*pp)); // lazy..
955
956 // do the actual deep copy..
a652aa9f 957 for (i = 0; i < pp_c->argc; i++)
958 pp_copy_arg(&pp->arg[i], &pp_c->arg[i]);
bd96f656 959 if (pp_c->ret_type.name != NULL)
960 pp->ret_type.name = strdup(pp_c->ret_type.name);
c36e914d 961
bd96f656 962 return pp;
c36e914d 963}
964
27ebfaed 965
966static inline int pp_cmp_func(const struct parsed_proto *pp1,
967 const struct parsed_proto *pp2)
968{
969 int i;
970
971 if (pp1->argc != pp2->argc || pp1->argc_reg != pp2->argc_reg)
972 return 1;
973 else {
974 for (i = 0; i < pp1->argc; i++) {
975 if ((pp1->arg[i].reg != NULL) != (pp2->arg[i].reg != NULL))
976 return 1;
977
978 if ((pp1->arg[i].reg != NULL)
979 && !IS(pp1->arg[i].reg, pp2->arg[i].reg))
980 {
981 return 1;
982 }
983 }
984 }
985
986 return 0;
987}
988
b74c31e3 989static inline void pp_print(char *buf, size_t buf_size,
990 const struct parsed_proto *pp)
991{
992 size_t l;
993 int i;
994
995 snprintf(buf, buf_size, "%s %s(", pp->ret_type.name, pp->name);
996 l = strlen(buf);
997
998 for (i = 0; i < pp->argc_reg; i++) {
999 snprintf(buf + l, buf_size - l, "%s%s",
1000 i == 0 ? "" : ", ", pp->arg[i].reg);
1001 l = strlen(buf);
1002 }
1003 if (pp->argc_stack > 0) {
1004 snprintf(buf + l, buf_size - l, "%s{%d stack}",
1005 i == 0 ? "" : ", ", pp->argc_stack);
1006 l = strlen(buf);
1007 }
1008 snprintf(buf + l, buf_size - l, ")");
1009}
1010
bd96f656 1011static inline void proto_release(struct parsed_proto *pp)
c36e914d 1012{
1013 int i;
1014
1015 for (i = 0; i < pp->argc; i++) {
39b168b8 1016 if (pp->arg[i].reg != NULL)
c36e914d 1017 free(pp->arg[i].reg);
3ebea2cf 1018 if (pp->arg[i].type.name != NULL)
1019 free(pp->arg[i].type.name);
93b5bd18 1020 if (pp->arg[i].pp != NULL)
1021 free(pp->arg[i].pp);
c36e914d 1022 }
3ebea2cf 1023 if (pp->ret_type.name != NULL)
1024 free(pp->ret_type.name);
bd96f656 1025 free(pp);
865f1aca 1026
1027 (void)proto_lookup_struct;
c36e914d 1028}