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