6 unsigned int is_array:1;
10 struct parsed_proto_arg {
12 struct parsed_type type;
13 struct parsed_proto *fptr;
20 struct parsed_type ret_type;
21 struct parsed_type type;
23 struct parsed_proto_arg arg[16];
27 unsigned int is_func:1;
28 unsigned int is_stdcall:1;
29 unsigned int is_vararg:1;
30 unsigned int is_fptr:1;
31 unsigned int is_noreturn:1;
34 static const char *hdrfn;
35 static int hdrfline = 0;
37 static int find_protostr(char *dst, size_t dlen, FILE *fhdr,
38 const char *fname, const char *sym_)
40 const char *sym = sym_;
41 const char *finc_name;
48 if (sym[0] == '_' && strncmp(fname, "stdc", 4) == 0)
54 while (fgets(dst, dlen, fhdr))
57 if (strncmp(dst, "//#include ", 11) == 0) {
59 p = strpbrk(finc_name, "\r\n ");
63 finc = fopen(finc_name, "r");
65 printf("%s:%d: can't open '%s'\n",
66 fname, line, finc_name);
69 ret = find_protostr(dst, dlen, finc,
76 if (strncmp(sskip(dst), "//", 2) == 0)
80 if (p != NULL && p > dst
81 && (my_isblank(p[-1]) || my_issep(p[-1]))
82 && (my_isblank(p[symlen]) || my_issep(p[symlen])))
90 p = dst + strlen(dst);
91 for (p--; p > dst && my_isblank(*p); --p)
97 static int get_regparm(char *dst, size_t dlen, char *p)
104 for (o = 0, i = 1; o < dlen; i++) {
116 static const char *known_type_mod[] = {
124 static const char *known_ptr_types[] = {
148 static const char *ignored_keywords[] = {
156 // returns ptr to char after type ends
157 static int typecmp(const char *n, const char *t)
159 for (; *t != 0; n++, t++) {
160 while (n[0] == ' ' && (n[1] == ' ' || n[1] == '*'))
162 while (t[0] == ' ' && (t[1] == ' ' || t[1] == '*'))
171 static const char *skip_type_mod(const char *n)
176 for (i = 0; i < ARRAY_SIZE(known_type_mod); i++) {
177 len = strlen(known_type_mod[i]);
178 if (strncmp(n, known_type_mod[i], len) != 0)
182 while (my_isblank(*n))
190 static int check_type(const char *name, struct parsed_type *type)
196 n = skip_type_mod(name);
198 for (i = 0; i < ARRAY_SIZE(known_ptr_types); i++) {
199 if (typecmp(n, known_ptr_types[i]))
206 if (n[0] == 'L' && n[1] == 'P')
209 // assume single word
210 while (!my_isblank(*n) && !my_issep(*n))
215 while (my_isblank(*n))
226 type->name = strndup(name, ret);
230 /* args are always expanded to 32bit */
231 static const char *map_reg(const char *reg)
233 const char *regs_f[] = { "eax", "ebx", "ecx", "edx", "esi", "edi" };
234 const char *regs_w[] = { "ax", "bx", "cx", "dx", "si", "di" };
235 const char *regs_b[] = { "al", "bl", "cl", "dl" };
238 for (i = 0; i < ARRAY_SIZE(regs_w); i++)
239 if (IS(reg, regs_w[i]))
242 for (i = 0; i < ARRAY_SIZE(regs_b); i++)
243 if (IS(reg, regs_b[i]))
249 static int parse_protostr(char *protostr, struct parsed_proto *pp)
251 struct parsed_proto_arg *arg;
261 if (p[0] == '/' && p[1] == '/') {
262 printf("%s:%d: commented out?\n", hdrfn, hdrfline);
266 // strip unneeded stuff
267 for (p1 = p; p1[0] != 0 && p1[1] != 0; p1++) {
268 if ((p1[0] == '/' && p1[1] == '*')
269 || (p1[0] == '*' && p1[1] == '/'))
273 if (!strncmp(p, "DECLSPEC_NORETURN ", 18)) {
278 for (i = 0; i < ARRAY_SIZE(ignored_keywords); i++) {
279 l = strlen(ignored_keywords[i]);
280 if (!strncmp(p, ignored_keywords[i], l) && my_isblank(p[l]))
281 p = sskip(p + l + 1);
284 ret = check_type(p, &pp->ret_type);
286 printf("%s:%d:%zd: unhandled return in '%s'\n",
287 hdrfn, hdrfline, (p - protostr) + 1, protostr);
292 if (!strchr(p, ')')) {
293 p = next_idt(buf, sizeof(buf), p);
296 printf("%s:%d:%zd: var name missing\n",
297 hdrfn, hdrfline, (p - protostr) + 1);
300 strcpy(pp->name, buf);
305 pp->ret_type.is_array = 1;
317 p = next_word(cconv, sizeof(cconv), p);
320 printf("%s:%d:%zd: cconv missing\n",
321 hdrfn, hdrfline, (p - protostr) + 1);
324 if (IS(cconv, "__cdecl"))
326 else if (IS(cconv, "__stdcall"))
328 else if (IS(cconv, "__fastcall"))
330 else if (IS(cconv, "__thiscall"))
332 else if (IS(cconv, "__userpurge"))
333 pp->is_stdcall = 1; // in all cases seen..
334 else if (IS(cconv, "__usercall"))
335 pp->is_stdcall = 0; // ..or is it?
336 else if (IS(cconv, "WINAPI"))
339 printf("%s:%d:%zd: unhandled cconv: '%s'\n",
340 hdrfn, hdrfline, (p - protostr) + 1, cconv);
346 printf("%s:%d:%zd: '*' expected\n",
347 hdrfn, hdrfline, (p - protostr) + 1);
353 p = next_idt(buf, sizeof(buf), p);
356 printf("%s:%d:%zd: func name missing\n",
357 hdrfn, hdrfline, (p - protostr) + 1);
360 strcpy(pp->name, buf);
362 ret = get_regparm(regparm, sizeof(regparm), p);
364 if (!IS(regparm, "eax") && !IS(regparm, "ax")
365 && !IS(regparm, "al"))
367 printf("%s:%d:%zd: bad regparm: %s\n",
368 hdrfn, hdrfline, (p - protostr) + 1, regparm);
377 printf("%s:%d:%zd: ')' expected\n",
378 hdrfn, hdrfline, (p - protostr) + 1);
385 printf("%s:%d:%zd: '(' expected, got '%c'\n",
386 hdrfn, hdrfline, (p - protostr) + 1, *p);
393 if ((!strncmp(p, "void", 4) || !strncmp(p, "VOID", 4))
394 && *sskip(p + 4) == ')')
406 if (!strncmp(p, "...", 3)) {
413 printf("%s:%d:%zd: ')' expected\n",
414 hdrfn, hdrfline, (p - protostr) + 1);
418 arg = &pp->arg[xarg];
422 ret = check_type(p, &arg->type);
424 printf("%s:%d:%zd: unhandled type for arg%d\n",
425 hdrfn, hdrfline, (p - protostr) + 1, xarg);
432 arg->fptr = calloc(1, sizeof(*arg->fptr));
433 ret = parse_protostr(p1, arg->fptr);
435 printf("%s:%d:%zd: funcarg parse failed\n",
436 hdrfn, hdrfline, p1 - protostr);
439 // we'll treat it as void * for non-calls
440 arg->type.name = "void *";
441 arg->type.is_ptr = 1;
446 p = next_idt(buf, sizeof(buf), p);
450 printf("%s:%d:%zd: idt missing for arg%d\n",
451 hdrfn, hdrfline, (p - protostr) + 1, xarg);
457 ret = get_regparm(regparm, sizeof(regparm), p);
462 arg->reg = strdup(map_reg(regparm));
466 if (xarg > 0 && (IS(cconv, "__fastcall") || IS(cconv, "__thiscall"))) {
467 if (pp->arg[0].reg != NULL) {
468 printf("%s:%d: %s with arg1 spec %s?\n",
469 hdrfn, hdrfline, cconv, pp->arg[0].reg);
471 pp->arg[0].reg = strdup("ecx");
474 if (xarg > 1 && IS(cconv, "__fastcall")) {
475 if (pp->arg[1].reg != NULL) {
476 printf("%s:%d: %s with arg2 spec %s?\n",
477 hdrfn, hdrfline, cconv, pp->arg[1].reg);
479 pp->arg[1].reg = strdup("edx");
482 if (pp->is_vararg && pp->is_stdcall) {
483 printf("%s:%d: vararg stdcall?\n", hdrfn, hdrfline);
489 for (i = 0; i < pp->argc; i++) {
490 if (pp->arg[i].reg == NULL)
499 static int proto_parse(FILE *fhdr, const char *sym, struct parsed_proto *pp)
504 memset(pp, 0, sizeof(*pp));
506 ret = find_protostr(protostr, sizeof(protostr), fhdr, hdrfn, sym);
508 printf("%s: sym '%s' is missing\n", hdrfn, sym);
512 return parse_protostr(protostr, pp) < 0 ? -1 : 0;
515 static void proto_release(struct parsed_proto *pp)
519 for (i = 0; i < pp->argc; i++) {
520 if (pp->arg[i].reg != NULL)
521 free(pp->arg[i].reg);
522 if (pp->arg[i].type.name != NULL)
523 free(pp->arg[i].type.name);
524 if (pp->arg[i].fptr != NULL)
525 free(pp->arg[i].fptr);
527 if (pp->ret_type.name != NULL)
528 free(pp->ret_type.name);