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