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