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