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