2647bba5093f65f97e21abf97879ee34be3ba653
[ia32rtools.git] / tools / protoparse.h
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  */
8
9 struct parsed_proto;
10
11 struct parsed_type {
12         char *name;
13         unsigned int is_array:1;
14         unsigned int is_ptr:1;
15         unsigned int is_struct:1; // split for args
16         unsigned int is_retreg:1; // register to return to caller
17         unsigned int is_va_list:1;
18 };
19
20 struct parsed_proto_arg {
21         char *reg;
22         struct parsed_type type;
23         struct parsed_proto *fptr;
24         void *datap;
25 };
26
27 struct parsed_proto {
28         char name[256];
29         union {
30                 struct parsed_type ret_type;
31                 struct parsed_type type;
32         };
33         struct parsed_proto_arg arg[16];
34         int argc;
35         int argc_stack;
36         int argc_reg;
37         unsigned int is_func:1;
38         unsigned int is_stdcall:1;
39         unsigned int is_fastcall:1;
40         unsigned int is_vararg:1;     // vararg func
41         unsigned int is_fptr:1;
42         unsigned int is_noreturn:1;
43         unsigned int is_unresolved:1;
44         unsigned int is_userstack:1;
45         unsigned int is_include:1;    // not from top-level header
46         unsigned int is_osinc:1;      // OS/system library func
47         unsigned int is_cinc:1;       // crt library func
48         unsigned int is_arg:1;        // declared in some func arg
49         unsigned int has_structarg:1;
50         unsigned int has_retreg:1;
51 };
52
53 static const char *hdrfn;
54 static int hdrfline = 0;
55
56 static void pp_copy_arg(struct parsed_proto_arg *d,
57         const struct parsed_proto_arg *s);
58
59 static int b_pp_c_handler(char *proto, const char *fname,
60         int is_include, int is_osinc, int is_cinc);
61
62 static int do_protostrs(FILE *fhdr, const char *fname, int is_include)
63 {
64         const char *finc_name;
65         const char *hdrfn_saved;
66         char protostr[256];
67         char path[256];
68         char fname_inc[256];
69         int is_osinc;
70         int is_cinc;
71         FILE *finc;
72         int line = 0;
73         int ret;
74         char *p;
75
76         hdrfn_saved = hdrfn;
77         hdrfn = fname;
78
79         is_cinc = strstr(fname, "stdc.hlist") != NULL;
80         is_osinc = is_cinc || strstr(fname, "stdc.hlist") != NULL;
81
82         while (fgets(protostr, sizeof(protostr), fhdr))
83         {
84                 line++;
85                 if (strncmp(protostr, "//#include ", 11) == 0) {
86                         finc_name = protostr + 11;
87                         p = strpbrk(finc_name, "\r\n ");
88                         if (p != NULL)
89                                 *p = 0;
90
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");
101                         if (finc == NULL) {
102                                 printf("%s:%d: can't open '%s'\n",
103                                         fname_inc, line, finc_name);
104                                 continue;
105                         }
106                         ret = do_protostrs(finc, finc_name, 1);
107                         fclose(finc);
108                         if (ret < 0)
109                                 break;
110                         continue;
111                 }
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)
119                         continue;
120
121                 hdrfline = line;
122
123                 ret = b_pp_c_handler(protostr, hdrfn, is_include,
124                         is_osinc, is_cinc);
125                 if (ret < 0)
126                         break;
127         }
128
129         hdrfn = hdrfn_saved;
130
131         if (feof(fhdr))
132                 return 0;
133
134         return -1;
135 }
136
137 static int get_regparm(char *dst, size_t dlen, char *p, int *retreg)
138 {
139         int i = 0, o;
140
141         *retreg = 0;
142
143         if (*p != '<')
144                 return 0;
145
146         i++;
147         if (p[i] == '*') {
148                 *retreg = 1;
149                 i++;
150         }
151
152         for (o = 0; o < dlen; i++) {
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..
164 static const char *known_type_mod[] = {
165         "const",
166         "signed",
167         "unsigned",
168         "struct",
169         "enum",
170         "CONST",
171         "volatile",
172 };
173
174 static const char *known_ptr_types[] = {
175         "FARPROC",
176         "WNDPROC",
177         "LINECALLBACK",
178         "HACCEL",
179         "HANDLE",
180         "HBITMAP",
181         "HCALL",
182         "HCURSOR",
183         "HDC",
184         "HFONT",
185         "HGDIOBJ",
186         "HGLOBAL",
187         "HICON",
188         "HINSTANCE",
189         "HIMC", // DWORD in mingw, ptr in wine..
190         "HLINE",
191         "HLINEAPP",
192         "HLOCAL",
193         "HMODULE",
194         "HPALETTE",
195         "HRGN",
196         "HRSRC",
197         "HKEY",
198         "HMENU",
199         "HWAVEOUT",
200         "HWND",
201         "PBYTE",
202         "PCRITICAL_SECTION",
203         "PDWORD",
204         "PFILETIME",
205         "PLARGE_INTEGER",
206         "PHKEY",
207         "PLONG",
208         "PMEMORY_BASIC_INFORMATION",
209         "PUINT",
210         "PVOID",
211         "PCVOID",
212         "PWORD",
213         "DLGPROC",
214         "TIMERPROC",
215         "WNDENUMPROC",
216         "va_list",
217         "__VALIST",
218 };
219
220 static const char *ignored_keywords[] = {
221         "extern",
222         "WINBASEAPI",
223         "WINUSERAPI",
224         "WINGDIAPI",
225         "WINADVAPI",
226 };
227
228 // returns ptr to char after type ends
229 static int typecmp(const char *n, const char *t)
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)
237                         return *n - *t;
238         }
239
240         return 0;
241 }
242
243 static const char *skip_type_mod(const char *n)
244 {
245         int len;
246         int i;
247
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;
252                 if (!my_isblank(n[len]))
253                         continue;
254
255                 n += len;
256                 while (my_isblank(*n))
257                         n++;
258                 i = 0;
259         }
260
261         return n;
262 }
263
264 static 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]))
274                         continue;
275
276                 type->is_ptr = 1;
277                 break;
278         }
279
280         if (n[0] == 'L' && n[1] == 'P' && strncmp(n, "LPARAM", 6))
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);
301         if (IS(type->name, "__VALIST") || IS(type->name, "va_list"))
302                 type->is_va_list = 1;
303         if (IS(type->name, "VOID"))
304                 memcpy(type->name, "void", 4);
305
306         return ret;
307 }
308
309 /* args are always expanded to 32bit */
310 static 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
328 static 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
336 static int parse_protostr(char *protostr, struct parsed_proto *pp)
337 {
338         struct parsed_proto_arg *arg;
339         char regparm[16];
340         char buf[256];
341         char cconv[32];
342         int is_retreg;
343         int xarg = 0;
344         char *p, *p1;
345         int i, l;
346         int ret;
347
348         p = sskip(protostr);
349         if (p[0] == '/' && p[1] == '/') {
350                 printf("%s:%d: commented out?\n", hdrfn, hdrfline);
351                 p = sskip(p + 2);
352         }
353
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
361         if (!strncmp(p, "DECLSPEC_NORETURN ", 18)) {
362                 pp->is_noreturn = 1;
363                 p = sskip(p + 18);
364         }
365
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         }
371
372         ret = check_type(p, &pp->ret_type);
373         if (ret <= 0) {
374                 printf("%s:%d:%zd: unhandled return in '%s'\n",
375                         hdrfn, hdrfline, (p - protostr) + 1, protostr);
376                 return -1;
377         }
378         p = sskip(p + ret);
379
380         if (!strncmp(p, "noreturn ", 9)) {
381                 pp->is_noreturn = 1;
382                 p = sskip(p + 9);
383         }
384
385         if (!strchr(p, ')')) {
386                 p = next_idt(buf, sizeof(buf), p);
387                 p = sskip(p);
388                 if (buf[0] == 0) {
389                         printf("%s:%d:%zd: var name missing\n",
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;
398                         pp->ret_type.is_array = 1;
399                 }
400                 return p - protostr;
401         }
402
403         pp->is_func = 1;
404
405         if (*p == '(') {
406                 pp->is_fptr = 1;
407                 p = sskip(p + 1);
408         }
409
410         p = next_word(cconv, sizeof(cconv), p);
411         p = sskip(p);
412         if (cconv[0] == 0) {
413                 printf("%s:%d:%zd: cconv missing\n",
414                         hdrfn, hdrfline, (p - protostr) + 1);
415                 return -1;
416         }
417         if      (IS(cconv, "__cdecl"))
418                 pp->is_stdcall = 0;
419         else if (IS(cconv, "__stdcall"))
420                 pp->is_stdcall = 1;
421         else if (IS(cconv, "__fastcall")) {
422                 pp->is_fastcall = 1;
423                 pp->is_stdcall = 1; // sort of..
424         }
425         else if (IS(cconv, "__thiscall"))
426                 pp->is_stdcall = 1;
427         else if (IS(cconv, "__userpurge"))
428                 pp->is_stdcall = 1; // IDA
429         else if (IS(cconv, "__usercall"))
430                 pp->is_stdcall = 0; // IDA
431         else if (IS(cconv, "__userstack")) {
432                 pp->is_stdcall = 0; // custom
433                 pp->is_userstack = 1;
434         }
435         else if (IS(cconv, "WINAPI"))
436                 pp->is_stdcall = 1;
437         else {
438                 printf("%s:%d:%zd: unhandled cconv: '%s'\n",
439                         hdrfn, hdrfline, (p - protostr) + 1, cconv);
440                 return -1;
441         }
442
443         if (pp->is_fptr) {
444                 if (*p != '*') {
445                         printf("%s:%d:%zd: '*' expected\n",
446                                 hdrfn, hdrfline, (p - protostr) + 1);
447                         return -1;
448                 }
449                 p++;
450                 // XXX: skipping extra asterisks, for now
451                 while (*p == '*')
452                         p++;
453                 p = sskip(p);
454         }
455
456         p = next_idt(buf, sizeof(buf), p);
457         p = sskip(p);
458         if (buf[0] == 0) {
459                 //printf("%s:%d:%zd: func name missing\n",
460                 //      hdrfn, hdrfline, (p - protostr) + 1);
461                 //return -1;
462         }
463         strcpy(pp->name, buf);
464
465         ret = get_regparm(regparm, sizeof(regparm), p, &is_retreg);
466         if (ret > 0) {
467                 if (!IS(regparm, "eax") && !IS(regparm, "ax")
468                  && !IS(regparm, "al") && !IS(regparm, "edx:eax"))
469                 {
470                         printf("%s:%d:%zd: bad regparm: %s\n",
471                                 hdrfn, hdrfline, (p - protostr) + 1, regparm);
472                         return -1;
473                 }
474                 p += ret;
475                 p = sskip(p);
476         }
477
478         if (pp->is_fptr) {
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                 }
490                 if (*p != ')') {
491                         printf("%s:%d:%zd: ')' expected\n",
492                                 hdrfn, hdrfline, (p - protostr) + 1);
493                         return -1;
494                 }
495                 p = sskip(p + 1);
496         }
497
498         if (*p != '(') {
499                 printf("%s:%d:%zd: '(' expected, got '%c'\n",
500                                 hdrfn, hdrfline, (p - protostr) + 1, *p);
501                 return -1;
502         }
503         p++;
504
505         // check for x(void)
506         p = sskip(p);
507         if ((!strncmp(p, "void", 4) || !strncmp(p, "VOID", 4))
508            && *sskip(p + 4) == ')')
509                 p += 4;
510
511         while (1) {
512                 p = sskip(p);
513                 if (*p == ')') {
514                         p++;
515                         break;
516                 }
517                 if (xarg > 0) {
518                         if (*p != ',') {
519                                 printf("%s:%d:%zd: ',' expected\n",
520                                  hdrfn, hdrfline, (p - protostr) + 1);
521                                 return -1;
522                         }
523                         p = sskip(p + 1);
524                 }
525
526                 if (!strncmp(p, "...", 3)) {
527                         pp->is_vararg = 1;
528                         p = sskip(p + 3);
529                         if (*p == ')') {
530                                 p++;
531                                 break;
532                         }
533                         printf("%s:%d:%zd: ')' expected\n",
534                                 hdrfn, hdrfline, (p - protostr) + 1);
535                         return -1;
536                 }
537
538                 arg = &pp->arg[xarg];
539                 xarg++;
540
541                 p1 = p;
542                 ret = check_type(p, &arg->type);
543                 if (ret <= 0) {
544                         printf("%s:%d:%zd: unhandled type for arg%d\n",
545                                 hdrfn, hdrfline, (p - protostr) + 1, xarg);
546                         return -1;
547                 }
548                 p = sskip(p + ret);
549
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) {
555                                 printf("%s:%d:%zd: funcarg parse failed\n",
556                                         hdrfn, hdrfline, p1 - protostr);
557                                 return -1;
558                         }
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);
563                         // we'll treat it as void * for non-calls
564                         arg->type.name = strdup("void *");
565                         arg->type.is_ptr = 1;
566
567                         p = p1 + ret;
568                 }
569
570                 p = next_idt(buf, sizeof(buf), p);
571                 p = sskip(p);
572 #if 0
573                 if (buf[0] == 0) {
574                         printf("%s:%d:%zd: idt missing for arg%d\n",
575                                 hdrfn, hdrfline, (p - protostr) + 1, xarg);
576                         return -1;
577                 }
578 #endif
579                 arg->reg = NULL;
580
581                 ret = get_regparm(regparm, sizeof(regparm), p, &is_retreg);
582                 if (ret > 0) {
583                         p += ret;
584                         p = sskip(p);
585
586                         arg->reg = strdup(map_reg(regparm));
587                         arg->type.is_retreg = is_retreg;
588                         pp->has_retreg |= is_retreg;
589                 }
590
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
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                 }
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
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
656         return p - protostr;
657 }
658
659 static 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
665 static struct parsed_proto *pp_cache;
666 static int pp_cache_size;
667 static int pp_cache_alloc;
668
669 static int b_pp_c_handler(char *proto, const char *fname,
670         int is_include, int is_osinc, int is_cinc)
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
688         pp_cache[pp_cache_size].is_include = is_include;
689         pp_cache[pp_cache_size].is_osinc = is_osinc;
690         pp_cache[pp_cache_size].is_cinc = is_cinc;
691         pp_cache_size++;
692         return 0;
693 }
694
695 static void build_pp_cache(FILE *fhdr)
696 {
697         long pos;
698         int ret;
699
700         pos = ftell(fhdr);
701         rewind(fhdr);
702
703         ret = do_protostrs(fhdr, hdrfn, 0);
704         if (ret < 0)
705                 exit(1);
706
707         qsort(pp_cache, pp_cache_size, sizeof(pp_cache[0]), pp_name_cmp);
708         fseek(fhdr, pos, SEEK_SET);
709 }
710
711 static const struct parsed_proto *proto_parse(FILE *fhdr, const char *sym,
712         int quiet)
713 {
714         const struct parsed_proto *pp_ret;
715         struct parsed_proto pp_search;
716         char *p;
717
718         if (pp_cache == NULL)
719                 build_pp_cache(fhdr);
720
721         if (sym[0] == '_') // && strncmp(fname, "stdc", 4) == 0)
722                 sym++;
723
724         strcpy(pp_search.name, sym);
725         p = strchr(pp_search.name, '@');
726         if (p != NULL)
727                 *p = 0;
728
729         pp_ret = bsearch(&pp_search, pp_cache, pp_cache_size,
730                         sizeof(pp_cache[0]), pp_name_cmp);
731         if (pp_ret == NULL && !quiet)
732                 printf("%s: sym '%s' is missing\n", hdrfn, sym);
733
734         return pp_ret;
735 }
736
737 static 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
757 struct 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..
767         for (i = 0; i < pp_c->argc; i++)
768                 pp_copy_arg(&pp->arg[i], &pp_c->arg[i]);
769         if (pp_c->ret_type.name != NULL)
770                 pp->ret_type.name = strdup(pp_c->ret_type.name);
771
772         return pp;
773 }
774
775
776 static 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
799 static 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
821 static inline void proto_release(struct parsed_proto *pp)
822 {
823         int i;
824
825         for (i = 0; i < pp->argc; i++) {
826                 if (pp->arg[i].reg != NULL)
827                         free(pp->arg[i].reg);
828                 if (pp->arg[i].type.name != NULL)
829                         free(pp->arg[i].type.name);
830                 if (pp->arg[i].fptr != NULL)
831                         free(pp->arg[i].fptr);
832         }
833         if (pp->ret_type.name != NULL)
834                 free(pp->ret_type.name);
835         free(pp);
836 }