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