more snd apis
[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",
ead38b9e 237 "REFGUID",
79af284c 238 "REFIID",
239 "HOOKPROC",
e56ab892 240 "DLGPROC",
cdfaeed7 241 "TIMERPROC",
242 "WNDENUMPROC",
4f12f671 243 "va_list",
244 "__VALIST",
3ebea2cf 245};
246
247static const char *ignored_keywords[] = {
248 "extern",
249 "WINBASEAPI",
250 "WINUSERAPI",
4f12f671 251 "WINGDIAPI",
252 "WINADVAPI",
c36e914d 253};
254
3ebea2cf 255static int typecmp(const char *n, const char *t)
39b168b8 256{
257 for (; *t != 0; n++, t++) {
258 while (n[0] == ' ' && (n[1] == ' ' || n[1] == '*'))
259 n++;
260 while (t[0] == ' ' && (t[1] == ' ' || t[1] == '*'))
261 t++;
262 if (*n != *t)
3ebea2cf 263 return *n - *t;
39b168b8 264 }
265
3ebea2cf 266 return 0;
39b168b8 267}
268
3ebea2cf 269static const char *skip_type_mod(const char *n)
c36e914d 270{
64c59faf 271 int len;
39b168b8 272 int i;
c36e914d 273
64c59faf 274 for (i = 0; i < ARRAY_SIZE(known_type_mod); i++) {
275 len = strlen(known_type_mod[i]);
276 if (strncmp(n, known_type_mod[i], len) != 0)
277 continue;
bd96f656 278 if (!my_isblank(n[len]))
279 continue;
64c59faf 280
281 n += len;
282 while (my_isblank(*n))
283 n++;
284 i = 0;
285 }
286
3ebea2cf 287 return n;
288}
289
290static int check_type(const char *name, struct parsed_type *type)
291{
292 const char *n, *n1;
293 int ret = -1;
294 int i;
295
296 n = skip_type_mod(name);
297
865f1aca 298 if (!strncmp(n, "struct", 6) && my_isblank(n[6])) {
299 type->is_struct = 1;
300
301 n += 6;
302 while (my_isblank(*n))
303 n++;
304 }
305
3ebea2cf 306 for (i = 0; i < ARRAY_SIZE(known_ptr_types); i++) {
307 if (typecmp(n, known_ptr_types[i]))
64c59faf 308 continue;
309
3ebea2cf 310 type->is_ptr = 1;
311 break;
c36e914d 312 }
313
a652aa9f 314 if (n[0] == 'L' && n[1] == 'P' && strncmp(n, "LPARAM", 6))
3ebea2cf 315 type->is_ptr = 1;
316
317 // assume single word
318 while (!my_isblank(*n) && !my_issep(*n))
319 n++;
320
321 while (1) {
322 n1 = n;
323 while (my_isblank(*n))
324 n++;
325 if (*n == '*') {
326 type->is_ptr = 1;
327 n++;
328 continue;
329 }
330 break;
331 }
332
333 ret = n1 - name;
334 type->name = strndup(name, ret);
5f70a34f 335 if (IS(type->name, "__VALIST") || IS(type->name, "va_list"))
336 type->is_va_list = 1;
a2c1d768 337 if (IS(type->name, "VOID"))
338 memcpy(type->name, "void", 4);
339
3ebea2cf 340 return ret;
c36e914d 341}
342
343/* args are always expanded to 32bit */
344static const char *map_reg(const char *reg)
345{
346 const char *regs_f[] = { "eax", "ebx", "ecx", "edx", "esi", "edi" };
347 const char *regs_w[] = { "ax", "bx", "cx", "dx", "si", "di" };
348 const char *regs_b[] = { "al", "bl", "cl", "dl" };
349 int i;
350
351 for (i = 0; i < ARRAY_SIZE(regs_w); i++)
352 if (IS(reg, regs_w[i]))
353 return regs_f[i];
354
355 for (i = 0; i < ARRAY_SIZE(regs_b); i++)
356 if (IS(reg, regs_b[i]))
357 return regs_f[i];
358
359 return reg;
360}
361
a652aa9f 362static int check_struct_arg(struct parsed_proto_arg *arg)
363{
364 if (IS(arg->type.name, "POINT"))
365 return 2 - 1;
366
367 return 0;
368}
369
93b5bd18 370static int parse_protostr(char *protostr, struct parsed_proto *pp);
371
372static int parse_arg(char **p_, struct parsed_proto_arg *arg, int xarg)
373{
374 char buf[256];
375 char *p = *p_;
376 char *pe;
377 int ret;
378
379 arg->pp = calloc(1, sizeof(*arg->pp));
380 my_assert_not(arg->pp, NULL);
381 arg->pp->is_arg = 1;
382
383 pe = p;
384 while (1) {
385 pe = strpbrk(pe, ",()");
386 if (pe == NULL)
387 return -1;
388 if (*pe == ',' || *pe == ')')
389 break;
390 pe = strchr(pe, ')');
391 if (pe == NULL)
392 return -1;
393 pe++;
394 }
395
396 if (pe - p > sizeof(buf) - 1)
397 return -1;
398 memcpy(buf, p, pe - p);
399 buf[pe - p] = 0;
400
401 ret = parse_protostr(buf, arg->pp);
402 if (ret < 0)
403 return -1;
404
405 // we don't use actual names right now...
406 snprintf(arg->pp->name, sizeof(arg->pp->name), "a%d", xarg);
407
408 if (!arg->type.is_struct)
409 // we'll treat it as void * for non-calls
410 arg->type.name = strdup("void *");
411 arg->type.is_ptr = 1;
412
413 p += ret;
414 *p_ = p;
415 return 0;
416}
417
c36e914d 418static int parse_protostr(char *protostr, struct parsed_proto *pp)
419{
39b168b8 420 struct parsed_proto_arg *arg;
c36e914d 421 char regparm[16];
422 char buf[256];
423 char cconv[32];
1f84f6b3 424 int is_retreg;
39b168b8 425 char *p, *p1;
93b5bd18 426 int xarg = 0;
3ebea2cf 427 int i, l;
c36e914d 428 int ret;
c36e914d 429
06c5d854 430 p = sskip(protostr);
c36e914d 431 if (p[0] == '/' && p[1] == '/') {
06c5d854 432 printf("%s:%d: commented out?\n", hdrfn, hdrfline);
c36e914d 433 p = sskip(p + 2);
434 }
435
865f1aca 436 // allow start of line comment
437 if (p[0] == '/' && p[1] == '*') {
438 p = strstr(p + 2, "*/");
439 if (p == NULL) {
440 printf("%s:%d: multiline comments unsupported\n",
441 hdrfn, hdrfline);
442 return -1;
443 }
444 p = sskip(p + 2);
445 }
446
447 // we need remaining hints in comments, so strip / *
06c5d854 448 for (p1 = p; p1[0] != 0 && p1[1] != 0; p1++) {
449 if ((p1[0] == '/' && p1[1] == '*')
450 || (p1[0] == '*' && p1[1] == '/'))
451 p1[0] = p1[1] = ' ';
452 }
453
e56ab892 454 if (!strncmp(p, "DECLSPEC_NORETURN ", 18)) {
455 pp->is_noreturn = 1;
456 p = sskip(p + 18);
457 }
458
3ebea2cf 459 for (i = 0; i < ARRAY_SIZE(ignored_keywords); i++) {
460 l = strlen(ignored_keywords[i]);
461 if (!strncmp(p, ignored_keywords[i], l) && my_isblank(p[l]))
462 p = sskip(p + l + 1);
463 }
06c5d854 464
3ebea2cf 465 ret = check_type(p, &pp->ret_type);
466 if (ret <= 0) {
63df67be 467 printf("%s:%d:%zd: unhandled return in '%s'\n",
c36e914d 468 hdrfn, hdrfline, (p - protostr) + 1, protostr);
39b168b8 469 return -1;
c36e914d 470 }
64c59faf 471 p = sskip(p + ret);
c36e914d 472
da87ae38 473 if (!strncmp(p, "noreturn ", 9)) {
474 pp->is_noreturn = 1;
475 p = sskip(p + 9);
476 }
477
06c5d854 478 if (!strchr(p, ')')) {
479 p = next_idt(buf, sizeof(buf), p);
480 p = sskip(p);
93b5bd18 481 if (!pp->is_arg && buf[0] == 0) {
482 printf("%s:%d:%zd: var name is missing\n",
06c5d854 483 hdrfn, hdrfline, (p - protostr) + 1);
484 return -1;
485 }
486 strcpy(pp->name, buf);
487
488 p1 = strchr(p, ']');
489 if (p1 != NULL) {
490 p = p1 + 1;
3ebea2cf 491 pp->ret_type.is_array = 1;
06c5d854 492 }
493 return p - protostr;
494 }
495
496 pp->is_func = 1;
497
39b168b8 498 if (*p == '(') {
499 pp->is_fptr = 1;
500 p = sskip(p + 1);
501 }
502
c36e914d 503 p = next_word(cconv, sizeof(cconv), p);
504 p = sskip(p);
505 if (cconv[0] == 0) {
63df67be 506 printf("%s:%d:%zd: cconv missing\n",
c36e914d 507 hdrfn, hdrfline, (p - protostr) + 1);
39b168b8 508 return -1;
c36e914d 509 }
510 if (IS(cconv, "__cdecl"))
511 pp->is_stdcall = 0;
512 else if (IS(cconv, "__stdcall"))
513 pp->is_stdcall = 1;
c0050df6 514 else if (IS(cconv, "__fastcall")) {
515 pp->is_fastcall = 1;
516 pp->is_stdcall = 1; // sort of..
517 }
c36e914d 518 else if (IS(cconv, "__thiscall"))
519 pp->is_stdcall = 1;
520 else if (IS(cconv, "__userpurge"))
de50b98b 521 pp->is_stdcall = 1; // IDA
c36e914d 522 else if (IS(cconv, "__usercall"))
de50b98b 523 pp->is_stdcall = 0; // IDA
1f84f6b3 524 else if (IS(cconv, "__userstack")) {
525 pp->is_stdcall = 0; // custom
526 pp->is_userstack = 1;
527 }
79af284c 528 else if (IS(cconv, "WINAPI") || IS(cconv, "PASCAL"))
64c59faf 529 pp->is_stdcall = 1;
c36e914d 530 else {
63df67be 531 printf("%s:%d:%zd: unhandled cconv: '%s'\n",
c36e914d 532 hdrfn, hdrfline, (p - protostr) + 1, cconv);
39b168b8 533 return -1;
534 }
535
536 if (pp->is_fptr) {
537 if (*p != '*') {
63df67be 538 printf("%s:%d:%zd: '*' expected\n",
39b168b8 539 hdrfn, hdrfline, (p - protostr) + 1);
540 return -1;
541 }
bd96f656 542 p++;
543 // XXX: skipping extra asterisks, for now
544 while (*p == '*')
545 p++;
546 p = sskip(p);
c36e914d 547 }
548
549 p = next_idt(buf, sizeof(buf), p);
550 p = sskip(p);
551 if (buf[0] == 0) {
de50b98b 552 //printf("%s:%d:%zd: func name missing\n",
553 // hdrfn, hdrfline, (p - protostr) + 1);
554 //return -1;
c36e914d 555 }
39b168b8 556 strcpy(pp->name, buf);
c36e914d 557
1f84f6b3 558 ret = get_regparm(regparm, sizeof(regparm), p, &is_retreg);
c36e914d 559 if (ret > 0) {
560 if (!IS(regparm, "eax") && !IS(regparm, "ax")
2b43685d 561 && !IS(regparm, "al") && !IS(regparm, "edx:eax"))
c36e914d 562 {
63df67be 563 printf("%s:%d:%zd: bad regparm: %s\n",
c36e914d 564 hdrfn, hdrfline, (p - protostr) + 1, regparm);
39b168b8 565 return -1;
c36e914d 566 }
567 p += ret;
568 p = sskip(p);
569 }
570
39b168b8 571 if (pp->is_fptr) {
bd96f656 572 if (*p == '[') {
573 // not really ret_type is array, but ohwell
574 pp->ret_type.is_array = 1;
575 p = strchr(p + 1, ']');
576 if (p == NULL) {
577 printf("%s:%d:%zd: ']' expected\n",
578 hdrfn, hdrfline, (p - protostr) + 1);
579 return -1;
580 }
581 p = sskip(p + 1);
582 }
39b168b8 583 if (*p != ')') {
63df67be 584 printf("%s:%d:%zd: ')' expected\n",
39b168b8 585 hdrfn, hdrfline, (p - protostr) + 1);
586 return -1;
587 }
588 p = sskip(p + 1);
589 }
590
c36e914d 591 if (*p != '(') {
63df67be 592 printf("%s:%d:%zd: '(' expected, got '%c'\n",
c36e914d 593 hdrfn, hdrfline, (p - protostr) + 1, *p);
39b168b8 594 return -1;
c36e914d 595 }
596 p++;
597
39b168b8 598 // check for x(void)
599 p = sskip(p);
06c5d854 600 if ((!strncmp(p, "void", 4) || !strncmp(p, "VOID", 4))
601 && *sskip(p + 4) == ')')
39b168b8 602 p += 4;
603
c36e914d 604 while (1) {
605 p = sskip(p);
39b168b8 606 if (*p == ')') {
607 p++;
c36e914d 608 break;
39b168b8 609 }
840257f6 610 if (xarg > 0) {
611 if (*p != ',') {
612 printf("%s:%d:%zd: ',' expected\n",
613 hdrfn, hdrfline, (p - protostr) + 1);
614 return -1;
615 }
c36e914d 616 p = sskip(p + 1);
840257f6 617 }
c36e914d 618
7ba45c34 619 if (!strncmp(p, "...", 3)) {
620 pp->is_vararg = 1;
621 p = sskip(p + 3);
622 if (*p == ')') {
623 p++;
624 break;
625 }
63df67be 626 printf("%s:%d:%zd: ')' expected\n",
7ba45c34 627 hdrfn, hdrfline, (p - protostr) + 1);
628 return -1;
629 }
630
39b168b8 631 arg = &pp->arg[xarg];
c36e914d 632 xarg++;
633
39b168b8 634 p1 = p;
3ebea2cf 635 ret = check_type(p, &arg->type);
636 if (ret <= 0) {
63df67be 637 printf("%s:%d:%zd: unhandled type for arg%d\n",
c36e914d 638 hdrfn, hdrfline, (p - protostr) + 1, xarg);
39b168b8 639 return -1;
c36e914d 640 }
64c59faf 641 p = sskip(p + ret);
c36e914d 642
93b5bd18 643 if (*p == '(' || arg->type.is_struct) {
644 // func ptr or struct
645 ret = parse_arg(&p1, arg, xarg);
39b168b8 646 if (ret < 0) {
63df67be 647 printf("%s:%d:%zd: funcarg parse failed\n",
39b168b8 648 hdrfn, hdrfline, p1 - protostr);
649 return -1;
650 }
93b5bd18 651 p = p1;
39b168b8 652 }
653
c36e914d 654 p = next_idt(buf, sizeof(buf), p);
655 p = sskip(p);
656#if 0
657 if (buf[0] == 0) {
63df67be 658 printf("%s:%d:%zd: idt missing for arg%d\n",
c36e914d 659 hdrfn, hdrfline, (p - protostr) + 1, xarg);
39b168b8 660 return -1;
c36e914d 661 }
662#endif
39b168b8 663 arg->reg = NULL;
c36e914d 664
1f84f6b3 665 ret = get_regparm(regparm, sizeof(regparm), p, &is_retreg);
c36e914d 666 if (ret > 0) {
667 p += ret;
668 p = sskip(p);
669
39b168b8 670 arg->reg = strdup(map_reg(regparm));
1f84f6b3 671 arg->type.is_retreg = is_retreg;
672 pp->has_retreg |= is_retreg;
c36e914d 673 }
a652aa9f 674
b62264bc 675 if (IS(arg->type.name, "float")
676 || IS(arg->type.name, "double"))
677 {
678 arg->type.is_float = 1;
679 }
680
f9327ad4 681 if (!arg->type.is_ptr && (strstr(arg->type.name, "int64")
682 || IS(arg->type.name, "double")))
7e50b291 683 {
2c31fb4c 684 arg->type.is_64bit = 1;
7e50b291 685 // hack..
7e50b291 686 pp_copy_arg(&pp->arg[xarg], arg);
2c31fb4c 687 arg = &pp->arg[xarg];
7e50b291 688 xarg++;
2c31fb4c 689 free(arg->type.name);
690 arg->type.name = strdup("dummy");
7e50b291 691 }
692
a652aa9f 693 ret = check_struct_arg(arg);
694 if (ret > 0) {
695 pp->has_structarg = 1;
696 arg->type.is_struct = 1;
697 free(arg->type.name);
698 arg->type.name = strdup("int");
699 for (l = 0; l < ret; l++) {
700 pp_copy_arg(&pp->arg[xarg], arg);
701 xarg++;
702 }
703 }
c36e914d 704 }
705
706 if (xarg > 0 && (IS(cconv, "__fastcall") || IS(cconv, "__thiscall"))) {
707 if (pp->arg[0].reg != NULL) {
708 printf("%s:%d: %s with arg1 spec %s?\n",
709 hdrfn, hdrfline, cconv, pp->arg[0].reg);
710 }
711 pp->arg[0].reg = strdup("ecx");
712 }
713
714 if (xarg > 1 && IS(cconv, "__fastcall")) {
715 if (pp->arg[1].reg != NULL) {
716 printf("%s:%d: %s with arg2 spec %s?\n",
717 hdrfn, hdrfline, cconv, pp->arg[1].reg);
718 }
719 pp->arg[1].reg = strdup("edx");
720 }
721
722 pp->argc = xarg;
723
724 for (i = 0; i < pp->argc; i++) {
725 if (pp->arg[i].reg == NULL)
726 pp->argc_stack++;
727 else
728 pp->argc_reg++;
729 }
730
c0050df6 731 if (pp->argc == 1 && pp->arg[0].reg != NULL
732 && IS(pp->arg[0].reg, "ecx"))
733 {
734 pp->is_fastcall = 1;
735 }
736 else if (pp->argc_reg == 2
737 && pp->arg[0].reg != NULL && IS(pp->arg[0].reg, "ecx")
738 && pp->arg[1].reg != NULL && IS(pp->arg[1].reg, "edx"))
739 {
740 pp->is_fastcall = 1;
741 }
742
743 if (pp->is_vararg && (pp->is_stdcall || pp->is_fastcall)) {
744 printf("%s:%d: vararg %s?\n", hdrfn, hdrfline, cconv);
745 return -1;
746 }
747
39b168b8 748 return p - protostr;
c36e914d 749}
750
bd96f656 751static int pp_name_cmp(const void *p1, const void *p2)
752{
753 const struct parsed_proto *pp1 = p1, *pp2 = p2;
754 return strcmp(pp1->name, pp2->name);
755}
756
865f1aca 757static int ps_name_cmp(const void *p1, const void *p2)
758{
759 const struct parsed_struct *ps1 = p1, *ps2 = p2;
760 return strcmp(ps1->name, ps2->name);
761}
762
763// parsed struct cache
764static struct parsed_struct *ps_cache;
765static int ps_cache_size;
766static int ps_cache_alloc;
767
768static int struct_handler(FILE *fhdr, char *proto, int *line)
769{
770 struct parsed_struct *ps;
771 char lstr[256], *p;
772 int offset = 0;
773 int m = 0;
774 int ret;
775
776 if (ps_cache_size >= ps_cache_alloc) {
777 ps_cache_alloc = ps_cache_alloc * 2 + 64;
778 ps_cache = realloc(ps_cache, ps_cache_alloc
779 * sizeof(ps_cache[0]));
780 my_assert_not(ps_cache, NULL);
781 memset(ps_cache + ps_cache_size, 0,
782 (ps_cache_alloc - ps_cache_size)
783 * sizeof(ps_cache[0]));
784 }
785
786 ps = &ps_cache[ps_cache_size++];
787 ret = sscanf(proto, "struct %255s {", ps->name);
788 if (ret != 1) {
789 printf("%s:%d: struct parse failed\n", hdrfn, *line);
790 return -1;
791 }
792
793 while (fgets(lstr, sizeof(lstr), fhdr))
794 {
795 (*line)++;
796
797 p = sskip(lstr);
798 if (p[0] == '/' && p[1] == '/')
799 continue;
800 if (p[0] == '}')
801 break;
802
803 if (m >= ARRAY_SIZE(ps->members)) {
804 printf("%s:%d: too many struct members\n",
805 hdrfn, *line);
806 return -1;
807 }
808
809 hdrfline = *line;
810 ret = parse_protostr(p, &ps->members[m].pp);
811 if (ret < 0) {
812 printf("%s:%d: struct member #%d/%02x "
813 "doesn't parse\n", hdrfn, *line,
814 m, offset);
815 return -1;
816 }
817 ps->members[m].offset = offset;
818 offset += 4;
819 m++;
820 }
821
822 ps->member_count = m;
823
824 return 0;
825}
826
827// parsed proto cache
bd96f656 828static struct parsed_proto *pp_cache;
829static int pp_cache_size;
830static int pp_cache_alloc;
831
61e29183 832static int b_pp_c_handler(char *proto, const char *fname,
ebc4dc43 833 int is_include, int is_osinc, int is_cinc)
bd96f656 834{
835 int ret;
836
837 if (pp_cache_size >= pp_cache_alloc) {
838 pp_cache_alloc = pp_cache_alloc * 2 + 64;
839 pp_cache = realloc(pp_cache, pp_cache_alloc
840 * sizeof(pp_cache[0]));
841 my_assert_not(pp_cache, NULL);
842 memset(pp_cache + pp_cache_size, 0,
843 (pp_cache_alloc - pp_cache_size)
844 * sizeof(pp_cache[0]));
845 }
846
847 ret = parse_protostr(proto, &pp_cache[pp_cache_size]);
848 if (ret < 0)
849 return -1;
850
61e29183 851 pp_cache[pp_cache_size].is_include = is_include;
852 pp_cache[pp_cache_size].is_osinc = is_osinc;
ebc4dc43 853 pp_cache[pp_cache_size].is_cinc = is_cinc;
bd96f656 854 pp_cache_size++;
855 return 0;
856}
857
865f1aca 858static void build_caches(FILE *fhdr)
c36e914d 859{
1f906263 860 long pos;
c36e914d 861 int ret;
862
1f906263 863 pos = ftell(fhdr);
bd96f656 864 rewind(fhdr);
865
61e29183 866 ret = do_protostrs(fhdr, hdrfn, 0);
bd96f656 867 if (ret < 0)
868 exit(1);
869
870 qsort(pp_cache, pp_cache_size, sizeof(pp_cache[0]), pp_name_cmp);
865f1aca 871 qsort(ps_cache, ps_cache_size, sizeof(ps_cache[0]), ps_name_cmp);
1f906263 872 fseek(fhdr, pos, SEEK_SET);
bd96f656 873}
874
36595fd2 875static const struct parsed_proto *proto_parse(FILE *fhdr, const char *sym,
876 int quiet)
bd96f656 877{
878 const struct parsed_proto *pp_ret;
879 struct parsed_proto pp_search;
7aca4698 880 char *p;
bd96f656 881
882 if (pp_cache == NULL)
865f1aca 883 build_caches(fhdr);
bd96f656 884
f9327ad4 885 // ugh...
886 if (sym[0] == '_' && !IS_START(sym, "__W"))
bd96f656 887 sym++;
c36e914d 888
bd96f656 889 strcpy(pp_search.name, sym);
7aca4698 890 p = strchr(pp_search.name, '@');
891 if (p != NULL)
892 *p = 0;
893
bd96f656 894 pp_ret = bsearch(&pp_search, pp_cache, pp_cache_size,
895 sizeof(pp_cache[0]), pp_name_cmp);
36595fd2 896 if (pp_ret == NULL && !quiet)
c36e914d 897 printf("%s: sym '%s' is missing\n", hdrfn, sym);
bd96f656 898
899 return pp_ret;
900}
901
865f1aca 902static const struct parsed_proto *proto_lookup_struct(FILE *fhdr,
903 const char *type, int offset)
904{
905 struct parsed_struct ps_search, *ps;
906 int m;
907
908 if (pp_cache == NULL)
909 build_caches(fhdr);
910 if (ps_cache_size == 0)
911 return NULL;
912
913 while (my_isblank(*type))
914 type++;
915 if (!strncmp(type, "struct", 6) && my_isblank(type[6]))
916 type += 7;
917
918 if (sscanf(type, "%255s", ps_search.name) != 1)
919 return NULL;
920
921 ps = bsearch(&ps_search, ps_cache, ps_cache_size,
922 sizeof(ps_cache[0]), ps_name_cmp);
923 if (ps == NULL) {
924 printf("%s: struct '%s' is missing\n",
925 hdrfn, ps_search.name);
926 return NULL;
927 }
928
929 for (m = 0; m < ps->member_count; m++) {
930 if (ps->members[m].offset == offset)
931 return &ps->members[m].pp;
932 }
933
934 return NULL;
935}
936
a652aa9f 937static void pp_copy_arg(struct parsed_proto_arg *d,
938 const struct parsed_proto_arg *s)
939{
940 memcpy(d, s, sizeof(*d));
941
942 if (s->reg != NULL) {
943 d->reg = strdup(s->reg);
944 my_assert_not(d->reg, NULL);
945 }
946 if (s->type.name != NULL) {
947 d->type.name = strdup(s->type.name);
948 my_assert_not(d->type.name, NULL);
949 }
93b5bd18 950 if (s->pp != NULL) {
951 d->pp = malloc(sizeof(*d->pp));
952 my_assert_not(d->pp, NULL);
953 memcpy(d->pp, s->pp, sizeof(*d->pp));
a652aa9f 954 }
955}
956
bd96f656 957struct parsed_proto *proto_clone(const struct parsed_proto *pp_c)
958{
959 struct parsed_proto *pp;
960 int i;
961
962 pp = malloc(sizeof(*pp));
963 my_assert_not(pp, NULL);
964 memcpy(pp, pp_c, sizeof(*pp)); // lazy..
965
966 // do the actual deep copy..
a652aa9f 967 for (i = 0; i < pp_c->argc; i++)
968 pp_copy_arg(&pp->arg[i], &pp_c->arg[i]);
bd96f656 969 if (pp_c->ret_type.name != NULL)
970 pp->ret_type.name = strdup(pp_c->ret_type.name);
c36e914d 971
bd96f656 972 return pp;
c36e914d 973}
974
27ebfaed 975
976static inline int pp_cmp_func(const struct parsed_proto *pp1,
977 const struct parsed_proto *pp2)
978{
979 int i;
980
981 if (pp1->argc != pp2->argc || pp1->argc_reg != pp2->argc_reg)
982 return 1;
983 else {
984 for (i = 0; i < pp1->argc; i++) {
985 if ((pp1->arg[i].reg != NULL) != (pp2->arg[i].reg != NULL))
986 return 1;
987
988 if ((pp1->arg[i].reg != NULL)
989 && !IS(pp1->arg[i].reg, pp2->arg[i].reg))
990 {
991 return 1;
992 }
993 }
994 }
995
996 return 0;
997}
998
b74c31e3 999static inline void pp_print(char *buf, size_t buf_size,
1000 const struct parsed_proto *pp)
1001{
1002 size_t l;
1003 int i;
1004
1005 snprintf(buf, buf_size, "%s %s(", pp->ret_type.name, pp->name);
1006 l = strlen(buf);
1007
1008 for (i = 0; i < pp->argc_reg; i++) {
1009 snprintf(buf + l, buf_size - l, "%s%s",
1010 i == 0 ? "" : ", ", pp->arg[i].reg);
1011 l = strlen(buf);
1012 }
1013 if (pp->argc_stack > 0) {
1014 snprintf(buf + l, buf_size - l, "%s{%d stack}",
1015 i == 0 ? "" : ", ", pp->argc_stack);
1016 l = strlen(buf);
1017 }
1018 snprintf(buf + l, buf_size - l, ")");
1019}
1020
bd96f656 1021static inline void proto_release(struct parsed_proto *pp)
c36e914d 1022{
1023 int i;
1024
1025 for (i = 0; i < pp->argc; i++) {
39b168b8 1026 if (pp->arg[i].reg != NULL)
c36e914d 1027 free(pp->arg[i].reg);
3ebea2cf 1028 if (pp->arg[i].type.name != NULL)
1029 free(pp->arg[i].type.name);
93b5bd18 1030 if (pp->arg[i].pp != NULL)
1031 free(pp->arg[i].pp);
c36e914d 1032 }
3ebea2cf 1033 if (pp->ret_type.name != NULL)
1034 free(pp->ret_type.name);
bd96f656 1035 free(pp);
865f1aca 1036
1037 (void)proto_lookup_struct;
c36e914d 1038}