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