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