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