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