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