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