starting data converter tool
[ia32rtools.git] / tools / cvt_data.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include "my_assert.h"
7 #include "my_str.h"
8
9 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
10 #define IS(w, y) !strcmp(w, y)
11 #define IS_START(w, y) !strncmp(w, y, strlen(y))
12
13 #include "protoparse.h"
14
15 static const char *asmfn;
16 static int asmln;
17 static FILE *g_fhdr;
18
19 enum dx_type {
20   DXT_UNSPEC,
21   DXT_BYTE,
22   DXT_WORD,
23   DXT_DWORD,
24   DXT_QUAD,
25   DXT_TEN,
26 };
27
28 #define aerr(fmt, ...) do { \
29         printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
30   fcloseall(); \
31         exit(1); \
32 } while (0)
33
34 #include "masm_tools.h"
35
36 static char *next_word_s(char *w, size_t wsize, char *s)
37 {
38   int quote = 0;
39         size_t i;
40
41         s = sskip(s);
42
43         for (i = 0; i < wsize - 1; i++) {
44     if (s[i] == '\'')
45       quote ^= 1;
46                 if (s[i] == 0 || (!quote && (my_isblank(s[i]) || s[i] == ',')))
47                         break;
48                 w[i] = s[i];
49         }
50         w[i] = 0;
51
52         if (s[i] != 0 && !my_isblank(s[i]) && s[i] != ',')
53                 printf("warning: '%s' truncated\n", w);
54
55         return s + i;
56 }
57
58 static void next_section(FILE *fasm, char *name)
59 {
60   char words[2][256];
61   char line[256];
62   int wordc;
63   char *p;
64
65   name[0] = 0;
66
67   while (fgets(line, sizeof(line), fasm))
68   {
69     wordc = 0;
70     asmln++;
71
72     p = sskip(line);
73     if (*p == 0)
74       continue;
75
76     if (*p == ';') {
77       while (strlen(line) == sizeof(line) - 1) {
78         // one of those long comment lines..
79         if (!fgets(line, sizeof(line), fasm))
80           break;
81       }
82       continue;
83     }
84
85     for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
86       p = sskip(next_word(words[wordc], sizeof(words[0]), p));
87       if (*p == 0 || *p == ';') {
88         wordc++;
89         break;
90       }
91     }
92
93     if (wordc < 2)
94       continue;
95
96     if (!IS(words[1], "segment"))
97       continue;
98
99     strcpy(name, words[0]);
100     break;
101   }
102 }
103
104 static enum dx_type parse_dx_directive(const char *name)
105 {
106   if (IS(name, "dd"))
107     return DXT_DWORD;
108   if (IS(name, "dw"))
109     return DXT_WORD;
110   if (IS(name, "db"))
111     return DXT_BYTE;
112   if (IS(name, "dq"))
113     return DXT_QUAD;
114   if (IS(name, "dt"))
115     return DXT_TEN;
116
117   return DXT_UNSPEC;
118 }
119
120 static const char *type_name(enum dx_type type)
121 {
122   switch (type) {
123   case DXT_BYTE:
124     return ".byte";
125   case DXT_WORD:
126     return ".word";
127   case DXT_DWORD:
128     return ".long";
129   case DXT_QUAD:
130     return ".quad";
131   case DXT_TEN:
132     return ".tfloat";
133   case DXT_UNSPEC:
134     break;
135   }
136   return "<bad>";
137 }
138
139 static int type_size(enum dx_type type)
140 {
141   switch (type) {
142   case DXT_BYTE:
143     return 1;
144   case DXT_WORD:
145     return 2;
146   case DXT_DWORD:
147     return 4;
148   case DXT_QUAD:
149     return 8;
150   case DXT_TEN:
151     return 10;
152   case DXT_UNSPEC:
153     break;
154   }
155   return -1;
156 }
157
158 static char *escape_string(char *s)
159 {
160   char buf[256];
161   char *t = buf;
162
163   for (; *s != 0; s++) {
164     if (*s == '"') {
165       strcpy(t, "\\22");
166       t += strlen(t);
167       continue;
168     }
169     if (*s == '\\') {
170       strcpy(t, "\\\\");
171       t += strlen(t);
172       continue;
173     }
174     *t++ = *s;
175   }
176   *t = *s;
177   return strcpy(s, buf);
178 }
179
180 int main(int argc, char *argv[])
181 {
182   FILE *fout, *fasm;
183   char words[20][256];
184   //int sep_after[20];
185   char word[256];
186   char line[256];
187   char comment[256];
188   unsigned long val;
189   unsigned long cnt;
190   const char *sym;
191   enum dx_type type;
192   int is_label;
193   int wordc;
194   int first;
195   int arg_out;
196   int arg = 1;
197   int len;
198   int w;
199   char *p;
200   char *p2;
201
202   if (argc != 4) {
203     printf("usage:\n%s <.s> <.asm> <hdrf>\n",
204       argv[0]);
205     return 1;
206   }
207
208   arg_out = arg++;
209
210   asmfn = argv[arg++];
211   fasm = fopen(asmfn, "r");
212   my_assert_not(fasm, NULL);
213
214   hdrfn = argv[arg++];
215   g_fhdr = fopen(hdrfn, "r");
216   my_assert_not(g_fhdr, NULL);
217
218   fout = fopen(argv[arg_out], "w");
219   my_assert_not(fout, NULL);
220
221   comment[0] = 0;
222
223   while (!feof(fasm)) {
224     next_section(fasm, line);
225     if (IS(line + 1, "text"))
226       continue;
227
228     if (IS(line + 1, "rdata"))
229       fprintf(fout, "\n.section .rodata\n");
230     else if (IS(line + 1, "data"))
231       fprintf(fout, "\n.data\n");
232     else
233       aerr("unhandled section: '%s'\n", line);
234
235     fprintf(fout, ".align 4\n");
236
237     while (fgets(line, sizeof(line), fasm))
238     {
239       sym = NULL;
240       asmln++;
241
242       p = sskip(line);
243       if (*p == 0 || *p == ';')
244         continue;
245
246       for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
247         //sep_after[wordc] = 0;
248         p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
249         if (*p == 0 || *p == ';') {
250           wordc++;
251           break;
252         }
253         if (*p == ',') {
254           //sep_after[wordc] = 1;
255           p = sskip(p + 1);
256         }
257       }
258
259       if (wordc == 2 && IS(words[1], "ends"))
260         break;
261       if (wordc < 2)
262         aerr("unhandled: '%s'\n", words[0]);
263
264       // don't cares
265       if (IS(words[0], "assume"))
266         continue;
267
268       if (IS(words[0], "align")) {
269         val = parse_number(words[1]);
270         fprintf(fout, "\t\t  .align %ld", val);
271         goto fin;
272       }
273
274       w = 1;
275       type = parse_dx_directive(words[0]);
276       if (type == DXT_UNSPEC) {
277         type = parse_dx_directive(words[1]);
278         sym = words[0];
279         w = 2;
280       }
281       if (type == DXT_UNSPEC)
282         aerr("unhandled decl: '%s %s'\n", words[0], words[1]);
283
284       if (sym != NULL) {
285         len = strlen(sym);
286         fprintf(fout, "_%s:", sym);
287
288         len += 2;
289         if (len < 8)
290           fprintf(fout, "\t");
291         if (len < 16)
292           fprintf(fout, "\t");
293         if (len <= 16)
294           fprintf(fout, "  ");
295         else
296           fprintf(fout, " ");
297       }
298       else {
299         fprintf(fout, "\t\t  ");
300       }
301
302       if (type == DXT_BYTE && words[w][0] == '\'') {
303         // string; use asciz for most common case
304         if (w == wordc - 2 && IS(words[w + 1], "0")) {
305           fprintf(fout, ".asciz \"");
306           wordc--;
307         }
308         else
309           fprintf(fout, ".ascii \"");
310
311         for (; w < wordc; w++) {
312           if (words[w][0] == '\'') {
313             p = words[w] + 1;
314             p2 = strchr(p, '\'');
315             if (p2 == NULL)
316               aerr("unterminated string? '%s'\n", p);
317             memcpy(word, p, p2 - p);
318             word[p2 - p] = 0;
319             fprintf(fout, "%s", escape_string(word));
320           }
321           else {
322             val = parse_number(words[w]);
323             if (val & ~0xff)
324               aerr("bad string trailing byte?\n");
325             fprintf(fout, "\\x%02lx", val);
326           }
327         }
328         fprintf(fout, "\"");
329         goto fin;
330       }
331
332       if (w == wordc - 2) {
333         if (IS_START(words[w + 1], "dup(")) {
334           cnt = parse_number(words[w]);
335           p = words[w + 1] + 4;
336           p2 = strchr(p, ')');
337           if (p2 == NULL)
338             aerr("bad dup?\n");
339           memmove(word, p, p2 - p);
340           word[p2 - p] = 0;
341           val = parse_number(word);
342
343           fprintf(fout, ".fill 0x%02lx,%d,0x%02lx",
344             cnt, type_size(type), val);
345           goto fin;
346         }
347       }
348
349       if (type == DXT_DWORD && words[w][0] == '\''
350         && words[w][5] == '\'' && strlen(words[w]) == 6)
351       {
352         if (w != wordc - 1)
353           aerr("TODO\n");
354
355         p = words[w];
356         val = (p[1] << 24) | (p[2] << 16) | (p[3] << 8) | p[4];
357         fprintf(fout, ".long 0x%lx", val);
358         snprintf(comment, sizeof(comment), "%s", words[w]);
359         goto fin;
360       }
361
362       if ((type == DXT_QUAD || type == DXT_TEN)
363           && strchr(words[w], '.'))
364       {
365         if (w != wordc - 1)
366           aerr("TODO\n");
367
368         fprintf(fout, type == DXT_TEN ? ".tfloat " : ".double ");
369         fprintf(fout, "%s", words[w]);
370         goto fin;
371       }
372
373       first = 1;
374       fprintf(fout, "%s ", type_name(type));
375       for (; w < wordc; w++)
376       {
377         if (!first)
378           fprintf(fout, ", ");
379
380         is_label = 0;
381         if (w >= wordc - 2 && IS(words[w], "offset")) {
382           is_label = 1;
383           w++;
384         }
385         else if (type == DXT_DWORD
386                  && !('0' <= words[w][0] && words[w][0] <= '9'))
387         {
388           // assume label
389           is_label = 1;
390         }
391
392         if (is_label) {
393           p = words[w];
394           if (IS_START(p, "loc_") || strchr(p, '?') || strchr(p, '@'))
395           {
396             fprintf(fout, "0");
397             snprintf(comment, sizeof(comment), "%s", words[w + 1]);
398             goto fin;
399           }
400           fprintf(fout, "_%s", p);
401         }
402         else {
403           val = parse_number(words[w]);
404           if (val < 10)
405             fprintf(fout, "%ld", val);
406           else
407             fprintf(fout, "0x%lx", val);
408         }
409
410         first = 0;
411       }
412
413 fin:
414       if (comment[0] != 0) {
415         fprintf(fout, "\t\t# %s", comment);
416         comment[0] = 0;
417       }
418       fprintf(fout, "\n");
419       (void)proto_parse;
420     }
421   }
422
423   fclose(fout);
424   fclose(fasm);
425   fclose(g_fhdr);
426
427   return 0;
428 }
429
430 // vim:ts=2:shiftwidth=2:expandtab