fix some 32bit-host issues
[ia32rtools.git] / tools / protoparse.h
CommitLineData
c36e914d 1
39b168b8 2struct parsed_proto;
3
4struct parsed_proto_arg {
5 char *reg;
64c59faf 6 char *type;
39b168b8 7 struct parsed_proto *fptr;
8 void *datap;
9};
10
c36e914d 11struct parsed_proto {
39b168b8 12 char name[256];
64c59faf 13 char *ret_type;
39b168b8 14 struct parsed_proto_arg arg[16];
c36e914d 15 int argc;
16 int argc_stack;
17 int argc_reg;
06c5d854 18 unsigned int is_func:1;
39b168b8 19 unsigned int is_stdcall:1;
7ba45c34 20 unsigned int is_vararg:1;
39b168b8 21 unsigned int is_fptr:1;
06c5d854 22 unsigned int is_array:1;
c36e914d 23};
24
25static const char *hdrfn;
26static int hdrfline = 0;
27
39b168b8 28static int find_protostr(char *dst, size_t dlen, FILE *fhdr,
29 const char *fname, const char *sym_)
c36e914d 30{
39b168b8 31 const char *sym = sym_;
06c5d854 32 const char *finc_name;
39b168b8 33 FILE *finc;
34 int symlen;
c36e914d 35 int line = 0;
39b168b8 36 int ret;
c36e914d 37 char *p;
38
39b168b8 39 if (sym[0] == '_' && strncmp(fname, "stdc", 4) == 0)
40 sym++;
41 symlen = strlen(sym);
42
c36e914d 43 rewind(fhdr);
44
45 while (fgets(dst, dlen, fhdr))
46 {
47 line++;
06c5d854 48 if (strncmp(dst, "//#include ", 11) == 0) {
49 finc_name = dst + 11;
50 p = strpbrk(finc_name, "\r\n ");
39b168b8 51 if (p != NULL)
52 *p = 0;
53
06c5d854 54 finc = fopen(finc_name, "r");
39b168b8 55 if (finc == NULL) {
56 printf("%s:%d: can't open '%s'\n",
06c5d854 57 fname, line, finc_name);
39b168b8 58 continue;
59 }
60 ret = find_protostr(dst, dlen, finc,
06c5d854 61 finc_name, sym_);
39b168b8 62 fclose(finc);
63 if (ret == 0)
64 break;
65 continue;
66 }
06c5d854 67 if (strncmp(sskip(dst), "//", 2) == 0)
68 continue;
39b168b8 69
70 p = strstr(dst, sym);
06c5d854 71 if (p != NULL && p > dst
72 && (my_isblank(p[-1]) || my_issep(p[-1]))
39b168b8 73 && (my_isblank(p[symlen]) || my_issep(p[symlen])))
c36e914d 74 break;
75 }
76 hdrfline = line;
77
78 if (feof(fhdr))
79 return -1;
80
81 p = dst + strlen(dst);
82 for (p--; p > dst && my_isblank(*p); --p)
83 *p = 0;
84
85 return 0;
86}
87
88static int get_regparm(char *dst, size_t dlen, char *p)
89{
90 int i, o;
91
92 if (*p != '<')
93 return 0;
94
95 for (o = 0, i = 1; o < dlen; i++) {
96 if (p[i] == 0)
97 return 0;
98 if (p[i] == '>')
99 break;
100 dst[o++] = p[i];
101 }
102 dst[o] = 0;
103 return i + 1;
104}
105
106// hmh..
64c59faf 107static const char *known_type_mod[] = {
108 "const",
109 "signed",
110 "unsigned",
111};
112
c36e914d 113static const char *known_types[] = {
c36e914d 114 "void *",
115 "char *",
116 "FILE *",
f3d05b09 117 "int *",
64c59faf 118 "__int8 *",
119 "__int16 *",
c36e914d 120 "char",
121 "__int8",
122 "__int16",
64c59faf 123 "__int32",
c36e914d 124 "int",
125 "bool",
126 "void",
127 "BYTE",
128 "WORD",
64c59faf 129 "BOOL",
c36e914d 130 "DWORD",
91977a1c 131 "_DWORD",
c36e914d 132 "HMODULE",
133 "HANDLE",
134 "HWND",
64c59faf 135 "LANGID",
c36e914d 136 "LPCSTR",
137 "size_t",
138};
139
64c59faf 140// returns ptr to char after type ends
141static const char *typecmp(const char *n, const char *t)
39b168b8 142{
143 for (; *t != 0; n++, t++) {
144 while (n[0] == ' ' && (n[1] == ' ' || n[1] == '*'))
145 n++;
146 while (t[0] == ' ' && (t[1] == ' ' || t[1] == '*'))
147 t++;
148 if (*n != *t)
64c59faf 149 return NULL;
39b168b8 150 }
151
64c59faf 152 return n;
39b168b8 153}
154
64c59faf 155static char *check_type(const char *name, int *len_out)
c36e914d 156{
64c59faf 157 const char *n = name, *n1;
158 int len;
39b168b8 159 int i;
c36e914d 160
64c59faf 161 *len_out = 0;
162
163 for (i = 0; i < ARRAY_SIZE(known_type_mod); i++) {
164 len = strlen(known_type_mod[i]);
165 if (strncmp(n, known_type_mod[i], len) != 0)
166 continue;
167
168 n += len;
169 while (my_isblank(*n))
170 n++;
171 i = 0;
172 }
173
c36e914d 174 for (i = 0; i < ARRAY_SIZE(known_types); i++) {
64c59faf 175 n1 = typecmp(n, known_types[i]);
176 if (n1 == NULL)
177 continue;
178
179 *len_out = n1 - name;
180 return strndup(name, *len_out);
c36e914d 181 }
182
183 return NULL;
184}
185
186/* args are always expanded to 32bit */
187static const char *map_reg(const char *reg)
188{
189 const char *regs_f[] = { "eax", "ebx", "ecx", "edx", "esi", "edi" };
190 const char *regs_w[] = { "ax", "bx", "cx", "dx", "si", "di" };
191 const char *regs_b[] = { "al", "bl", "cl", "dl" };
192 int i;
193
194 for (i = 0; i < ARRAY_SIZE(regs_w); i++)
195 if (IS(reg, regs_w[i]))
196 return regs_f[i];
197
198 for (i = 0; i < ARRAY_SIZE(regs_b); i++)
199 if (IS(reg, regs_b[i]))
200 return regs_f[i];
201
202 return reg;
203}
204
205static int parse_protostr(char *protostr, struct parsed_proto *pp)
206{
39b168b8 207 struct parsed_proto_arg *arg;
c36e914d 208 char regparm[16];
209 char buf[256];
210 char cconv[32];
64c59faf 211 char *kt;
c36e914d 212 int xarg = 0;
39b168b8 213 char *p, *p1;
c36e914d 214 int ret;
c36e914d 215 int i;
216
06c5d854 217 p = sskip(protostr);
c36e914d 218 if (p[0] == '/' && p[1] == '/') {
06c5d854 219 printf("%s:%d: commented out?\n", hdrfn, hdrfline);
c36e914d 220 p = sskip(p + 2);
221 }
222
06c5d854 223 // strip unneeded stuff
224 for (p1 = p; p1[0] != 0 && p1[1] != 0; p1++) {
225 if ((p1[0] == '/' && p1[1] == '*')
226 || (p1[0] == '*' && p1[1] == '/'))
227 p1[0] = p1[1] = ' ';
228 }
229
230 if (strncmp(p, "extern ", 7) == 0)
231 p = sskip(p + 7);
64c59faf 232 if (strncmp(p, "WINBASEAPI ", 11) == 0)
233 p = sskip(p + 11);
06c5d854 234
64c59faf 235 kt = check_type(p, &ret);
c36e914d 236 if (kt == NULL) {
63df67be 237 printf("%s:%d:%zd: unhandled return in '%s'\n",
c36e914d 238 hdrfn, hdrfline, (p - protostr) + 1, protostr);
39b168b8 239 return -1;
c36e914d 240 }
241 pp->ret_type = kt;
64c59faf 242 p = sskip(p + ret);
c36e914d 243
06c5d854 244 if (!strchr(p, ')')) {
245 p = next_idt(buf, sizeof(buf), p);
246 p = sskip(p);
247 if (buf[0] == 0) {
63df67be 248 printf("%s:%d:%zd: var name missing\n",
06c5d854 249 hdrfn, hdrfline, (p - protostr) + 1);
250 return -1;
251 }
252 strcpy(pp->name, buf);
253
254 p1 = strchr(p, ']');
255 if (p1 != NULL) {
256 p = p1 + 1;
257 pp->is_array = 1;
258 }
259 return p - protostr;
260 }
261
262 pp->is_func = 1;
263
39b168b8 264 if (*p == '(') {
265 pp->is_fptr = 1;
266 p = sskip(p + 1);
267 }
268
c36e914d 269 p = next_word(cconv, sizeof(cconv), p);
270 p = sskip(p);
271 if (cconv[0] == 0) {
63df67be 272 printf("%s:%d:%zd: cconv missing\n",
c36e914d 273 hdrfn, hdrfline, (p - protostr) + 1);
39b168b8 274 return -1;
c36e914d 275 }
276 if (IS(cconv, "__cdecl"))
277 pp->is_stdcall = 0;
278 else if (IS(cconv, "__stdcall"))
279 pp->is_stdcall = 1;
280 else if (IS(cconv, "__fastcall"))
281 pp->is_stdcall = 1;
282 else if (IS(cconv, "__thiscall"))
283 pp->is_stdcall = 1;
284 else if (IS(cconv, "__userpurge"))
285 pp->is_stdcall = 1; // in all cases seen..
286 else if (IS(cconv, "__usercall"))
287 pp->is_stdcall = 0; // ..or is it?
64c59faf 288 else if (IS(cconv, "WINAPI"))
289 pp->is_stdcall = 1;
c36e914d 290 else {
63df67be 291 printf("%s:%d:%zd: unhandled cconv: '%s'\n",
c36e914d 292 hdrfn, hdrfline, (p - protostr) + 1, cconv);
39b168b8 293 return -1;
294 }
295
296 if (pp->is_fptr) {
297 if (*p != '*') {
63df67be 298 printf("%s:%d:%zd: '*' expected\n",
39b168b8 299 hdrfn, hdrfline, (p - protostr) + 1);
300 return -1;
301 }
302 p = sskip(p + 1);
c36e914d 303 }
304
305 p = next_idt(buf, sizeof(buf), p);
306 p = sskip(p);
307 if (buf[0] == 0) {
63df67be 308 printf("%s:%d:%zd: func name missing\n",
39b168b8 309 hdrfn, hdrfline, (p - protostr) + 1);
310 return -1;
c36e914d 311 }
39b168b8 312 strcpy(pp->name, buf);
c36e914d 313
314 ret = get_regparm(regparm, sizeof(regparm), p);
315 if (ret > 0) {
316 if (!IS(regparm, "eax") && !IS(regparm, "ax")
317 && !IS(regparm, "al"))
318 {
63df67be 319 printf("%s:%d:%zd: bad regparm: %s\n",
c36e914d 320 hdrfn, hdrfline, (p - protostr) + 1, regparm);
39b168b8 321 return -1;
c36e914d 322 }
323 p += ret;
324 p = sskip(p);
325 }
326
39b168b8 327 if (pp->is_fptr) {
328 if (*p != ')') {
63df67be 329 printf("%s:%d:%zd: ')' expected\n",
39b168b8 330 hdrfn, hdrfline, (p - protostr) + 1);
331 return -1;
332 }
333 p = sskip(p + 1);
334 }
335
c36e914d 336 if (*p != '(') {
63df67be 337 printf("%s:%d:%zd: '(' expected, got '%c'\n",
c36e914d 338 hdrfn, hdrfline, (p - protostr) + 1, *p);
39b168b8 339 return -1;
c36e914d 340 }
341 p++;
342
39b168b8 343 // check for x(void)
344 p = sskip(p);
06c5d854 345 if ((!strncmp(p, "void", 4) || !strncmp(p, "VOID", 4))
346 && *sskip(p + 4) == ')')
39b168b8 347 p += 4;
348
c36e914d 349 while (1) {
350 p = sskip(p);
39b168b8 351 if (*p == ')') {
352 p++;
c36e914d 353 break;
39b168b8 354 }
c36e914d 355 if (*p == ',')
356 p = sskip(p + 1);
357
7ba45c34 358 if (!strncmp(p, "...", 3)) {
359 pp->is_vararg = 1;
360 p = sskip(p + 3);
361 if (*p == ')') {
362 p++;
363 break;
364 }
63df67be 365 printf("%s:%d:%zd: ')' expected\n",
7ba45c34 366 hdrfn, hdrfline, (p - protostr) + 1);
367 return -1;
368 }
369
39b168b8 370 arg = &pp->arg[xarg];
c36e914d 371 xarg++;
372
39b168b8 373 p1 = p;
64c59faf 374 kt = check_type(p, &ret);
c36e914d 375 if (kt == NULL) {
63df67be 376 printf("%s:%d:%zd: unhandled type for arg%d\n",
c36e914d 377 hdrfn, hdrfline, (p - protostr) + 1, xarg);
39b168b8 378 return -1;
c36e914d 379 }
39b168b8 380 arg->type = kt;
64c59faf 381 p = sskip(p + ret);
c36e914d 382
39b168b8 383 if (*p == '(') {
384 // func ptr
385 arg->fptr = calloc(1, sizeof(*arg->fptr));
386 ret = parse_protostr(p1, arg->fptr);
387 if (ret < 0) {
63df67be 388 printf("%s:%d:%zd: funcarg parse failed\n",
39b168b8 389 hdrfn, hdrfline, p1 - protostr);
390 return -1;
391 }
392 // we'll treat it as void * for non-calls
393 arg->type = "void *";
394
395 p = p1 + ret;
396 }
397
c36e914d 398 p = next_idt(buf, sizeof(buf), p);
399 p = sskip(p);
400#if 0
401 if (buf[0] == 0) {
63df67be 402 printf("%s:%d:%zd: idt missing for arg%d\n",
c36e914d 403 hdrfn, hdrfline, (p - protostr) + 1, xarg);
39b168b8 404 return -1;
c36e914d 405 }
406#endif
39b168b8 407 arg->reg = NULL;
c36e914d 408
409 ret = get_regparm(regparm, sizeof(regparm), p);
410 if (ret > 0) {
411 p += ret;
412 p = sskip(p);
413
39b168b8 414 arg->reg = strdup(map_reg(regparm));
c36e914d 415 }
416 }
417
418 if (xarg > 0 && (IS(cconv, "__fastcall") || IS(cconv, "__thiscall"))) {
419 if (pp->arg[0].reg != NULL) {
420 printf("%s:%d: %s with arg1 spec %s?\n",
421 hdrfn, hdrfline, cconv, pp->arg[0].reg);
422 }
423 pp->arg[0].reg = strdup("ecx");
424 }
425
426 if (xarg > 1 && IS(cconv, "__fastcall")) {
427 if (pp->arg[1].reg != NULL) {
428 printf("%s:%d: %s with arg2 spec %s?\n",
429 hdrfn, hdrfline, cconv, pp->arg[1].reg);
430 }
431 pp->arg[1].reg = strdup("edx");
432 }
433
7ba45c34 434 if (pp->is_vararg && pp->is_stdcall) {
435 printf("%s:%d: vararg stdcall?\n", hdrfn, hdrfline);
436 return -1;
437 }
438
c36e914d 439 pp->argc = xarg;
440
441 for (i = 0; i < pp->argc; i++) {
442 if (pp->arg[i].reg == NULL)
443 pp->argc_stack++;
444 else
445 pp->argc_reg++;
446 }
447
39b168b8 448 return p - protostr;
c36e914d 449}
450
451static int proto_parse(FILE *fhdr, const char *sym, struct parsed_proto *pp)
452{
453 char protostr[256];
454 int ret;
455
456 memset(pp, 0, sizeof(*pp));
457
39b168b8 458 ret = find_protostr(protostr, sizeof(protostr), fhdr, hdrfn, sym);
c36e914d 459 if (ret != 0) {
460 printf("%s: sym '%s' is missing\n", hdrfn, sym);
461 return ret;
462 }
463
39b168b8 464 return parse_protostr(protostr, pp) < 0 ? -1 : 0;
c36e914d 465}
466
467static void proto_release(struct parsed_proto *pp)
468{
469 int i;
470
471 for (i = 0; i < pp->argc; i++) {
39b168b8 472 if (pp->arg[i].reg != NULL)
c36e914d 473 free(pp->arg[i].reg);
64c59faf 474 if (pp->arg[i].type != NULL)
475 free(pp->arg[i].type);
39b168b8 476 if (pp->arg[i].fptr != NULL)
477 free(pp->arg[i].fptr);
c36e914d 478 }
64c59faf 479 if (pp->ret_type != NULL)
480 free(pp->ret_type);
c36e914d 481}