Release 970629
[wine] / rc / winerc.c
1 /*
2  *
3  * Copyright  Martin von Loewis, 1994
4  *
5  */
6
7 #include <ctype.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <sys/stat.h>
11 #include <sys/fcntl.h>
12 #include <sys/types.h>
13 #include <unistd.h>
14 #include <string.h>
15 #include "windows.h"
16 #include "parser.h"
17
18 char usage[]="winerc -bdvc -p prefix -o outfile < infile \n"
19         "   -b            Create a C array from a binary .res file\n"
20         "   -c            Add 'const' prefix to C constants\n"
21         "   -d            Output debugging information\n"
22         "   -p prefix     Give a prefix for the generated names\n"
23         "   -v            Show each resource as it is processed\n"
24         "   -o file       Output to file.c and file.h\n"
25         "   -w 16|32      Select win16 or win32 output\n";
26
27 /*might be overwritten by command line*/
28 char *prefix="_Resource";
29 int win32=1;
30 int verbose,constant;
31 gen_res* g_start;
32 FILE *header,*code;
33 char hname[256],sname[256];
34
35 int transform_binary_file(void);
36 int yyparse(void);
37
38 static void *xmalloc (size_t size)
39 {
40     void *res;
41
42     res = malloc (size ? size : 1);
43     if (res == NULL)
44     {
45         fprintf (stderr, "Virtual memory exhausted.\n");
46         exit (1);
47     }
48     return res;
49 }
50
51
52 int main(int argc,char *argv[])
53 {  
54         extern int yydebug;
55         extern char* optarg;
56         int optc,lose,ret,binary;
57         lose=binary=0;
58         while((optc=getopt(argc,argv,"bcdp:vo:w:"))!=EOF)
59                 switch(optc)
60                 {
61                         /* bison will print state transitions on stderr */
62                         case 'b':binary=1;
63                                          break;
64                         case 'd':yydebug=1;
65                                          setbuf(stdout,0);
66                                          setbuf(stderr,0);
67                                         break;
68                         case 'p':prefix=strdup(optarg); break;
69                         case 'c':constant=1;break;
70                         case 'v':verbose=1;
71                                          setbuf(stderr,0);
72                                         break;
73                         case 'o':set_out_file(optarg);break;
74                         case 'w':if(!strcmp(optarg,"16"))win32=0;
75                                  else if(!strcmp(optarg,"32"))win32=1;
76                                  else lose++;
77                                  break;
78                         default: lose++;break;
79                 }
80         if(lose)return fprintf(stderr,usage),1;
81         if(!header)header=stdout;
82         if(!code)code=stdout;
83         if(binary)
84                 ret=transform_binary_file();
85         else
86                 ret=yyparse();
87         fclose(header);
88         fclose(code);
89         return ret;
90 }
91
92 void set_out_file(char *prefix)
93 {
94         sprintf(sname,"%s.c",prefix);
95         code=fopen(sname,"w");
96         sprintf(hname,"%s.h",prefix);
97         header=fopen(hname,"w");
98 }
99
100 int transform_binary_file()
101 {
102         int i,c;
103         fprintf(header,"#define APPLICATION_HAS_RESOURCES 1\n");
104         fprintf(code,"char _Application_resources[]={");
105         for(i=0;;i++)
106         {
107                 c=getchar();
108                 if(c==-1)break;
109                 if(i%16==0)fputc('\n',code);
110                 fprintf(code,"%3d,",c);
111         }
112         fprintf(code,"\n  0};\nint _Application_resources_size=%d;\n",i);
113         return 0;
114 }
115
116 /* SunOS' memcpy is wrong for overlapping arrays */
117 char *save_memcpy(char *d,char* s,int l)
118 {
119         if(d<s)
120                 for(;l;l--)*d++=*s++;
121         else
122                 for(d+=l-1,s+=l-1;l;l--)*d--=*s--;
123         return d;
124 }
125
126 /*allow unaligned access*/
127 void put_WORD(unsigned char* p,WORD w)
128 {
129         *p=w&0xFF;
130         *(p+1)=w>>8;
131 }
132
133 void put_DWORD(unsigned char* p,DWORD d)
134 {
135         put_WORD(p,d&0xFFFF);
136         put_WORD(p+2,d>>16);
137 }
138
139 WORD get_WORD(unsigned char* p)
140 {
141         return *p|(*(p+1)<<8);
142 }
143
144 DWORD get_DWORD(unsigned char* p)
145 {
146         return get_WORD(p)|(get_WORD(p+2)<<16);
147 }
148
149
150 /*create a new gen_res, initial size 100*/
151 gen_res *new_res()
152 {       gen_res* ret=xmalloc(sizeof(gen_res)+100);
153         int i;
154         for(i=0;i<sizeof(gen_res)+100;i++)*((char*)ret+i)='\0';
155         ret->g_next=g_start;
156         ret->g_prev=0;
157         g_start=ret;
158         ret->space=100;
159         return ret;
160 }
161
162 /*double the space*/
163 gen_res* grow(gen_res* res)
164 {
165         res=realloc(res,sizeof(gen_res)+2*res->space);
166         if(!res)
167                 fprintf(stderr,"Out of memory\n"),exit(1);
168         if(!res->g_prev)g_start=res;
169         else res->g_prev->g_next=res;
170         if(res->g_next)res->g_next->g_prev=res;
171         res->space=2*res->space;
172         return res;
173 }
174
175
176 /* insert bytes at offset 0, increase num_entries */
177 gen_res* insert_at_beginning(gen_res* res,char* entry,int size)
178 {
179         while(res->size+size>res->space)res=grow(res);
180         save_memcpy(res->res+size,res->res,res->size);
181         save_memcpy(res->res,entry,size);
182         res->size+=size;
183         res->num_entries++;
184         return res;
185 }
186
187 /* insert length characters from bytes into res, starting at start */
188 gen_res* insert_bytes(gen_res* res,char* bytes,int start,int length)
189 {
190         while(res->size+length>res->space)res=grow(res);
191         save_memcpy(res->res+start+length,res->res+start,res->size-start);
192         save_memcpy(res->res+start,bytes,length);
193         res->size+=length;
194         return res;
195 }
196
197 /* insert string into res, starting at start */
198 gen_res* insert_string(gen_res* res,unsigned char* string,int start,int terminating0)
199 {
200         unsigned char* p;
201         int lengthA = strlen(string) + (terminating0 ? 1 : 0);
202         int length = (win32 ? 2 : 1) * lengthA; 
203         while(res->size+length>res->space)res=grow(res);
204         save_memcpy(res->res+start+length,res->res+start,res->size-start);
205         p=res->res+start;
206         while(lengthA--)
207                 if (win32)
208                 {
209                         put_WORD(p, *string++);
210                         p+=2;
211                 }
212                 else
213                         *p++=*string++;
214         res->size+=length;
215         return res;
216 }
217
218 /* insert string at offset 0, increase num_entries */
219 gen_res* insert_string_at_beginning(gen_res* res,char* entry,int terminating0)
220 {
221         res=insert_string(res,entry,0,terminating0);
222         res->num_entries++;
223         return res;
224 }
225
226 /*delete len bytes from res, starting at start*/
227 gen_res* delete_bytes(gen_res* res,int start,int len)
228 {
229         save_memcpy(res->res+start,res->res+start+len,res->size-start-len);
230         res->size-=len;
231         return res;
232 }
233
234 /*create a new style*/
235 rc_style *new_style()
236 {
237         rc_style *ret=xmalloc(sizeof(rc_style));
238         /*initially, no bits have to be reset*/
239         ret->and=-1;
240         /*initially, no bits are set*/
241         ret->or=WS_CHILD | WS_VISIBLE;
242         return ret;
243 }
244
245 /* entries are inserted at the beginning, starting from the last one */
246 gen_res* add_accelerator(int ev, int id, int flags, gen_res* prev)
247 {
248         char accel_entry[5];
249         if(prev->num_entries==0)flags|=0x80; /* last entry */
250         accel_entry[0]=flags;
251         put_WORD(accel_entry+1,ev);
252         put_WORD(accel_entry+3,id);
253         return insert_at_beginning(prev,accel_entry,5);
254 }
255
256
257 /* create an integer from the event, taking things as "^c" into account
258    add this as new entry */
259 gen_res* add_string_accelerator(char *ev, int id, int flags, gen_res* prev)
260 {
261         int event;
262         if(*ev=='^')
263                 event=ev[1]-'a';
264         else
265                 event=ev[0];
266         return add_accelerator(event,id,flags,prev);
267 }
268
269 /*is there a difference between ASCII and VIRTKEY accelerators? */
270
271 gen_res* add_ascii_accelerator(int ev, int id, int flags, gen_res* prev)
272 {
273         return add_accelerator(ev,id,flags,prev);
274 }
275
276 gen_res* add_vk_accelerator(int ev, int id, int flags, gen_res* prev)
277 {
278         return add_accelerator(ev,id,flags,prev);
279 }
280
281 /* create a new dialog header, set all items to 0 */
282 gen_res* new_dialog()
283 {       gen_res* ret=new_res();
284         ret->size=win32?24:16; /*all strings "\0", no font*/
285         return ret;
286 }
287
288 /* the STYLE option was specified */
289 gen_res* dialog_style(rc_style* style, gen_res* attr)
290 {
291         /* default dialog styles? Do we need style->and? */
292         /* DS_SETFONT might have been specified before */
293         put_DWORD(attr->res,get_DWORD(attr->res)|style->or);
294         return attr;
295 }
296
297 /* menu name is at offset 13 (win32: 18) */
298 int dialog_get_menu(gen_res* attr)
299 {
300         return win32?18:13;
301 }
302
303 /* the class is after the menu name */
304 int dialog_get_class(gen_res* attr)
305 {
306         int offs=dialog_get_menu(attr);
307         while(attr->res[offs]||(win32&&attr->res[offs+1]))offs+=win32?2:1;
308         offs+=win32?2:1;
309         return offs;
310 }
311
312 /* the caption is after the class */
313 int dialog_get_caption(gen_res* attr)
314 {
315         int offs=dialog_get_class(attr);
316         while(attr->res[offs]||(win32&&attr->res[offs+1]))offs+=win32?2:1;
317         offs+=win32?2:1;
318         return offs;
319 }
320
321 /* the fontsize, if present, is after the caption, followed by the font name */
322 int dialog_get_fontsize(gen_res* attr)
323 {
324         int offs=dialog_get_caption(attr);
325         while(attr->res[offs]||(win32&&attr->res[offs+1]))offs+=win32?2:1;
326         offs+=win32?2:1;
327         return offs;
328 }
329
330
331 /* the CAPTION option was specified */
332 gen_res* dialog_caption(char* cap, gen_res*attr)
333 {
334         /* we don't need the terminating 0 as it's already there */
335         return insert_string(attr,cap,dialog_get_caption(attr),0);
336 }
337
338
339 /* the FONT option was specified, set the DS_SETFONT flag */
340 gen_res* dialog_font(short size,char* font,gen_res *attr)
341 {
342         char c_size[2];
343         int offs=dialog_get_fontsize(attr);
344         put_DWORD(attr->res,get_DWORD(attr->res)|DS_SETFONT);
345         put_WORD(c_size,size);
346         attr=insert_bytes(attr,c_size,offs,2);
347         offs+=2;
348         /* as there is no font name by default, copy the '\0' */
349         return insert_string(attr,font,offs,1);
350 }
351
352 gen_res* dialog_class(char* cap, gen_res*attr)
353 {
354         return insert_string(attr,cap,dialog_get_class(attr),0);
355 }
356
357 gen_res* dialog_menu_id(short nr, gen_res*attr)
358 {
359         char c_nr[2];
360         int offs=dialog_get_menu(attr);
361         attr->res[offs] = 0xff;
362         if (win32) attr->res[offs+1] = 0xff;
363         put_WORD(c_nr,nr);
364         return insert_bytes(attr,c_nr,offs+(win32?2:1),2);
365 }
366 gen_res* dialog_menu_str(char* cap, gen_res*attr)
367 {
368         return insert_string(attr,cap,dialog_get_menu(attr),0);
369 }
370
371 /* set the dialogs id, position, extent, and style */
372 gen_res* create_control_desc(int id,int x,int y,int cx, int cy,rc_style *style)
373 {       gen_res* ret=new_res();
374         int s=WS_VISIBLE|WS_CHILD; /*defaults styles for any control*/
375         if(win32)
376         {
377                 if(style)s=(s|style->or)&style->and;
378                 put_DWORD(ret->res+0,s);
379                 /* FIXME */
380                 /* put_WORD(ret->res+4, exStyle); */
381                 put_WORD(ret->res+8,x);
382                 put_WORD(ret->res+10,y);
383                 put_WORD(ret->res+12,cx);
384                 put_WORD(ret->res+14,cy);
385                 put_WORD(ret->res+16,id);
386                 ret->size=24; /*empty strings, unused byte*/
387         }
388         else
389         {
390                 put_WORD(ret->res+0,x);
391                 put_WORD(ret->res+2,y);
392                 put_WORD(ret->res+4,cx);
393                 put_WORD(ret->res+6,cy);
394                 put_WORD(ret->res+8,id);
395                 if(style)s=(s|style->or)&style->and;
396                 put_DWORD(ret->res+10,s);
397                 ret->size=17; /*empty strings, unused byte*/
398         }
399         return ret;
400 }
401
402 /* insert the control's label */
403 gen_res* label_control_desc(char* label,gen_res* cd)
404 {
405         int offs;
406         if(win32) {
407                 if(get_WORD(cd->res+18)==0xffff)offs=20; /* one-character class */
408                 else {
409                         for(offs=18;get_WORD(cd->res+offs);offs+=2);
410                         offs+=2;
411                 }
412         }
413         else {
414                 if(cd->res[14]&0x80)offs=15; /* one-character class */
415                 else {
416                         for(offs=14;cd->res[offs];offs++);
417                         offs++;
418                 }
419         }
420         return insert_string(cd,label,offs,0);
421 }
422
423 /* a CONTROL was specified */
424 gen_res* create_generic_control(char* label,int id,char* class,
425         rc_style*style,int x,int y,int cx,int cy)
426 {       gen_res* ret=new_res();
427         int s=WS_VISIBLE|WS_CHILD; /*default styles for any control*/
428         if(style)s=(s|style->or)&style->and;
429         if(win32)
430         {
431                 WORD cl;
432                 put_DWORD(ret->res+0,s);
433                 /* FIXME */
434                 /* put_DWORD(ret->res+4,exstyle->or); */
435                 put_WORD(ret->res+8,x);
436                 put_WORD(ret->res+10,y);
437                 put_WORD(ret->res+12,cx);
438                 put_WORD(ret->res+14,cy);
439                 put_WORD(ret->res+16,id);
440                 ret->size=24;
441                 ret=insert_string(ret,label,20,0);
442                 /* is it a predefined class? */
443                 cl=0;
444                 if(!strcasecmp(class,"BUTTON"))cl=CT_BUTTON;
445                 if(!strcasecmp(class,"EDIT"))cl=CT_EDIT;
446                 if(!strcasecmp(class,"STATIC"))cl=CT_STATIC;
447                 if(!strcasecmp(class,"LISTBOX"))cl=CT_LISTBOX;
448                 if(!strcasecmp(class,"SCROLLBAR"))cl=CT_SCROLLBAR;
449                 if(!strcasecmp(class,"COMBOBOX"))cl=CT_COMBOBOX;
450                 if(cl) {
451                         char ffff[2]={0xff, 0xff};
452                         ret=insert_bytes(ret,ffff,18,2);
453                         put_WORD(ret->res+20,cl);
454                 }
455                 else ret=insert_string(ret,class,18,0);
456         }
457         else
458         {
459                 char cl;
460                 put_WORD(ret->res+0,x);
461                 put_WORD(ret->res+2,y);
462                 put_WORD(ret->res+4,cx);
463                 put_WORD(ret->res+6,cy);
464                 put_WORD(ret->res+8,id);
465                 put_DWORD(ret->res+10,s);
466                 ret->size=17;
467                 ret=insert_string(ret,label,15,0);
468                 /* is it a predefined class? */
469                 cl=0;
470                 if(!strcasecmp(class,"BUTTON"))cl=CT_BUTTON;
471                 if(!strcasecmp(class,"EDIT"))cl=CT_EDIT;
472                 if(!strcasecmp(class,"STATIC"))cl=CT_STATIC;
473                 if(!strcasecmp(class,"LISTBOX"))cl=CT_LISTBOX;
474                 if(!strcasecmp(class,"SCROLLBAR"))cl=CT_SCROLLBAR;
475                 if(!strcasecmp(class,"COMBOBOX"))cl=CT_COMBOBOX;
476                 if(cl)ret->res[14]=cl;
477                 else ret=insert_string(ret,class,14,0);
478         }
479         return ret;
480 }
481
482 /* insert cd into rest, set the type, add flags */
483 gen_res* add_control(int type,int flags,gen_res*cd,gen_res* rest)
484 {
485         char zeros[4]={0,0,0,0};
486         if(win32)
487         {
488                 char ffff[2]={0xff, 0xff};
489                 put_DWORD(cd->res+0,get_DWORD(cd->res+0)|flags);
490                 cd=insert_bytes(cd,ffff,18,2);
491                 put_WORD(cd->res+20,type);
492         }
493         else
494         {
495                 put_DWORD(cd->res+10,get_DWORD(cd->res+10)|flags);
496                 cd->res[14]=type;
497         }
498         /* WIN32: First control is on dword boundary */
499         if(win32 && cd->size%4)
500                 cd=insert_bytes(cd,zeros,cd->size,4-cd->size%4);
501         return insert_at_beginning(rest,cd->res,cd->size);
502 }
503
504 /* an ICON control was specified, whf contains width, height, and flags */
505 gen_res* add_icon(char* name,int id,int x,int y,gen_res* whf,gen_res* rest)
506 {
507     if (win32)
508     {
509         put_WORD(whf->res+8,x);
510         put_WORD(whf->res+10,y);
511         put_WORD(whf->res+16,id);
512     }
513     else
514     {
515         put_WORD(whf->res+0,x);
516         put_WORD(whf->res+2,y);
517         put_WORD(whf->res+8,id);
518     }
519         whf=label_control_desc(name,whf);
520         return add_control(CT_STATIC,SS_ICON,whf,rest);
521 }
522
523 /* insert the generic control into rest */
524 gen_res* add_generic_control(gen_res* ctl, gen_res* rest)
525 {
526         char zeros[4]={0,0,0,0};
527         /* WIN32: Control is on dword boundary */
528         if(win32 && ctl->size%4)
529                 ctl=insert_bytes(ctl,zeros,ctl->size,4-ctl->size%4);
530         return insert_at_beginning(rest,ctl->res,ctl->size);
531 }
532
533 /* create a dialog resource by inserting the header into the controls.
534    Set position and extent */
535 gen_res* make_dialog(gen_res* header,int x,int y,int cx,int cy,gen_res* ctls)
536 {
537         char zeros[4]={0,0,0,0};
538         if(win32)
539         {
540                 put_WORD(header->res+8, ctls->num_entries);
541                 header->type=dlg;
542                 put_WORD(header->res+10,x);
543                 put_WORD(header->res+12,y);
544                 put_WORD(header->res+14,cx);
545                 put_WORD(header->res+16,cy);
546         }
547         else
548         {
549                 header->res[4]=ctls->num_entries;
550                 header->type=dlg;
551                 put_WORD(header->res+5,x);
552                 put_WORD(header->res+7,y);
553                 put_WORD(header->res+9,cx);
554                 put_WORD(header->res+11,cy);
555         }
556         /* WIN32: First control is on dword boundary */
557         if(win32 && header->size%4)
558                 header=insert_bytes(header,zeros,header->size,4-header->size%4);
559         return insert_bytes(header,ctls->res,header->size,ctls->size);
560 }
561
562 /* create {0x15,0x16,0xFF} from '15 16 FF' */
563 gen_res *hex_to_raw(char *hex, gen_res*rest)
564 {
565         char r2[16];
566     int i;
567         for(i=0;*hex!='\'';i++)r2[i]=strtoul(hex,&hex,16);
568         return insert_bytes(rest,r2,0,i);
569 }
570
571 /* create a bitmap resource */
572 gen_res *make_bitmap(gen_res* res)
573 {
574         res=delete_bytes(res,0,14); /* skip bitmap file header*/
575         res->type=bmp;
576         return res;
577 }
578
579 gen_res *make_icon(gen_res* res)
580 {
581         res->type=ico;
582         return res;
583 }
584
585 gen_res *make_cursor(gen_res* res)
586 {
587         res->type=cur;
588         return res;
589 }
590
591 /* load resource bytes from the file name */
592 gen_res *load_file(char* name)
593 {
594         gen_res *res;
595         struct stat st;
596         int f=open(name,O_RDONLY);
597         if(f<0)
598         {
599           perror(name);
600           exit(1);
601         }
602         fstat(f,&st);
603         res=new_res();
604         while(res->space<st.st_size)res=grow(res);
605         read(f,res->res,st.st_size);
606         res->size=st.st_size;
607         close(f);
608         return res;
609 }
610
611 /* insert a normal menu item into res, starting from the last item */
612 gen_res *add_menuitem(char* name,int id,int flags,gen_res *res)
613 {
614         char item[4];
615         if(res->num_entries==0)flags|=MF_END;
616         put_WORD(item,flags);
617         put_WORD(item+2,id);
618         res=insert_string_at_beginning(res,name,1);
619         res=insert_bytes(res,item,0,4);
620         return res;
621 }
622
623 /* insert a popup item into res */
624 gen_res *add_popup(char *name,short flags, gen_res* body, gen_res*res)
625 {
626         char c_flags[2];
627         flags|=MF_POPUP;
628         if(res->num_entries==0)flags|=MF_END;
629         put_WORD(c_flags,flags);
630         res=insert_at_beginning(res,body->res,body->size);
631         res=insert_string(res,name,0,1);
632         res=insert_bytes(res,c_flags,0,2);
633         return res;
634 }
635
636 /* prefix the menu header into res */
637 gen_res *make_menu(gen_res* res)
638 {
639         static char header[4]={0,0,0,0};
640         res=insert_at_beginning(res,header,4);
641         res->type=men;
642         return res;
643 }
644
645 /* link top-level resources */
646 gen_res *add_resource(gen_res* first,gen_res *rest)
647 {
648     if(first)
649     {
650         first->next=rest;
651         return first;
652     }
653     else
654         return rest;
655 }
656
657 typedef struct str_tbl_elm{
658         int group;
659         struct str_tbl_elm *next;
660         char* strings[16];
661 } str_tbl_elm;
662
663 str_tbl_elm* string_table=NULL; /* sorted by group */
664
665 void add_str_tbl_elm(int id,char* str)
666 {
667   int group=(id>>4)+1;
668   int idx=id & 0x000f;
669
670   str_tbl_elm** elm=&string_table;
671   while(*elm && (*elm)->group<group) elm=&(*elm)->next;
672   if(!*elm || (*elm)->group!=group)
673   {
674     int i;
675     str_tbl_elm* new=xmalloc(sizeof(str_tbl_elm));
676     for(i=0; i<16; i++) new->strings[i] = NULL;
677     new->group=group;
678     new->next=*elm;
679     *elm=new;
680   }
681   (*elm)->strings[idx]=str;
682 }
683
684 gen_res* add_string_table(gen_res* t)
685 {
686   str_tbl_elm* ste;
687   int size,i;
688   gen_res* res;
689   unsigned char* p;
690   unsigned char* q;
691
692   if(!string_table) return t;
693   for(ste=string_table; ste; ste=ste->next)
694   {
695     for(size=0,i=0; i<16; i++)
696       size += (win32 ? 2 : 1) * (ste->strings[i] ? strlen(ste->strings[i])+1 : 1);
697     res=new_res();
698     while(res->space<size)res=grow(res);
699     res->type=str;
700     res->n.i_name=ste->group;
701     res->n_type=0;
702     res->size=size;
703     if (win32)
704       for(p=res->res,i=0; i<16; i++)
705         if((q=ste->strings[i])==NULL)
706         {
707           put_WORD(p, 0);
708           p+=2;
709         }
710         else
711         {
712           put_WORD(p, strlen(q));
713           p+=2;
714           while(*q)
715           {
716             put_WORD(p, *q++);
717             p+=2;
718           }
719         }
720     else
721       for(p=res->res,i=0; i<16; i++)
722         if((q=ste->strings[i])==NULL)
723           *p++ = 0;
724         else
725         {
726           *p++ = strlen(q);
727           while(*q) *p++ = *q++;
728         }
729     t=add_resource(res,t);
730   }
731   return t;
732 }
733
734 char *get_typename(gen_res* t)
735 {
736         switch(t->type){
737         case acc:return "ACCELERATOR";
738         case bmp:return "BITMAP";
739         case cur:return "CURSOR";
740         case dlg:return "DIALOG";
741         case fnt:return "FONT";
742         case ico:return "ICON";
743         case men:return "MENU";
744         case rdt:return "RCDATA";
745         case str:return "STRINGTABLE";
746         default: return "UNKNOWN";
747         }
748 }
749
750 /* create strings like _Sysres_DIALOG_2 */
751 char *get_resource_name(gen_res*it)
752 {
753         static char buf[1000];
754         if(it->n_type)
755                 sprintf(buf,"%s_%s_%s",prefix,get_typename(it),it->n.s_name);
756         else
757                 sprintf(buf,"%s_%s_%d",prefix,get_typename(it),it->n.i_name);
758         return buf;
759 }
760
761 #define ISCONSTANT      (constant ? "const " : "")
762
763 /* create the final output */
764 void create_output(gen_res* top)
765 {
766     gen_res *it;
767
768     top=add_string_table(top);
769
770     fprintf( header, "/* %s\n"
771                      " * This file is automatically generated. Do not edit!\n"
772                      " */\n\n"
773                      "#include \"resource.h\"\n", hname );
774
775     /* Declare the resources */
776
777     for (it=top;it;it=it->next)
778         fprintf( header,"extern %sstruct resource %s;\n",
779                  ISCONSTANT, get_resource_name(it) );
780     fprintf( header,"\nextern %sstruct resource * %s%s_Table[];\n",
781              ISCONSTANT, ISCONSTANT, prefix );
782
783     /* Print the resources bytes */
784
785     fprintf( code, "/* %s\n"
786                    " * This file is automatically generated. Do not edit!\n"
787                    " */\n\n"
788                    "#include \"%s\"\n", sname, hname );
789
790     for(it=top;it;it=it->next)
791     {
792         int i;
793         fprintf( code, "static %sunsigned char %s__bytes[]%s = {\n",
794                  ISCONSTANT, get_resource_name(it),
795                  win32?"\n__attribute__ ((aligned (4)))":"");
796         for (i=0;i<it->size-1;i++)
797         {
798             fprintf(code,"0x%02x, ",it->res[i]);
799             if ((i&7)==7)fputc('\n',code);
800         }
801         fprintf(code,"0x%02x };\n\n",it->res[i]);
802     }
803
804     /* Print the resources names */
805
806     if (win32)
807         for(it=top;it;it=it->next)
808         {
809             int i;
810             char s_buffer[20], *s_name=s_buffer;
811             if(it->n_type) s_name=it->n.s_name;
812             else sprintf(s_name,"@%d",it->n.i_name);
813             fprintf( code, "static %sunsigned char %s__name[] = {\n",
814                      ISCONSTANT, get_resource_name(it) );
815             for (i=0;*s_name;i++,s_name++)
816               {
817                 fprintf(code,"0x%02x, 0x00, ",*s_name);
818                 if ((i&3)==3)fputc('\n',code);
819               }
820             fprintf(code,"0x00, 0x00};\n\n");
821         }
822
823     /* Print the resources */
824     for (it=top;it;it=it->next)
825     {
826         int type;
827         switch(it->type)
828         {
829         case acc:type=(int)RT_ACCELERATOR;break;
830         case bmp:type=(int)RT_BITMAP;break;
831         case cur:type=(int)RT_CURSOR;break;
832         case dlg:type=(int)RT_DIALOG;break;
833         case fnt:type=(int)RT_FONT;break;
834         case ico:type=(int)RT_ICON;break;
835         case men:type=(int)RT_MENU;break;
836         case rdt:type=(int)RT_RCDATA;break;
837         case str:type=(int)RT_STRING;break;
838         default:fprintf(stderr,"Unknown restype\n");type=-1;break;
839         }
840         if(win32)
841         {
842             if(it->n_type)
843                 fprintf(code,"%sstruct resource %s = {0,%d,%s__name,%s__bytes,%d};\n",
844                         ISCONSTANT, get_resource_name(it), type, get_resource_name(it),
845                         get_resource_name(it), it->size );
846             else
847                 fprintf(code,"%sstruct resource %s = {%d,%d,%s__name,%s__bytes,%d};\n",
848                         ISCONSTANT, get_resource_name(it), it->n.i_name, type,
849                         get_resource_name(it), get_resource_name(it), it->size );
850         }
851         else
852         {
853             if(it->n_type)
854                 fprintf(code,"%sstruct resource %s = {0,%d,\"%s\",%s__bytes,%d};\n",
855                         ISCONSTANT, get_resource_name(it), type, it->n.s_name,
856                         get_resource_name(it), it->size );
857             else
858                 fprintf(code,"%sstruct resource %s = {%d,%d,\"@%d\",%s__bytes,%d};\n",
859                         ISCONSTANT, get_resource_name(it), it->n.i_name, type,
860                         it->n.i_name, get_resource_name(it), it->size );
861         }
862     }
863
864     /* Print the resource table (NULL terminated) */
865
866     fprintf(code,"\n%sstruct resource * %s%s_Table[] = {\n",
867             ISCONSTANT, ISCONSTANT, prefix);
868     for (it=top;it;it=it->next)
869         fprintf( code, "  &%s,\n", get_resource_name(it) );
870     fprintf( code, "  0\n};\n" );
871
872         /* Perform autoregistration */
873         fprintf( code, 
874                 "#ifdef WINELIB\n"
875                 "static void DoIt() WINE_CONSTRUCTOR;\n"
876                 "static void DoIt()\n"
877                 "{\n"
878                 "\tLIBRES_RegisterResources(%s_Table);\n"
879                 "}\n\n"
880                 "#ifndef HAVE_WINE_CONSTRUCTOR\n"
881                 "void LIBWINE_Register_%s(){\n"
882                 "\tDoIt();\n"
883                 "}\n"
884                 "#endif\n"
885                 "#endif /*WINELIB*/\n"
886                 ,prefix,prefix);
887 }
888
889 gen_res* make_font(gen_res* res)
890 {
891         fprintf(stderr,"Fonts not supported\n");
892         return NULL;
893 }
894
895 gen_res* make_raw(gen_res* res)
896 {
897         fprintf(stderr,"RCData not supported\n");
898         return NULL;
899 }
900
901 gen_res* int_to_raw(int i,gen_res* res)
902 {
903         fprintf(stderr,"IntToRaw not supported\n");
904         return NULL;
905 }
906
907 /* translate "Hello,\\tworld!\\10" to "Hello,\tworld!\n" */
908 char *parse_c_string(char *in)
909 {
910         char *out=xmalloc(strlen(in)-1);
911         char *it;
912         char tmp[5],*tend;
913         for(it=out,in++;*in;in++)
914         if(*in=='\\')
915                 switch(*++in)
916                 {case 't':*it++='\t';break;
917                  case 'r':*it++='\r';break;
918                  case 'n':*it++='\n';break;
919                  case 'a':*it++='\a';break;
920                  case '0':
921                         memset(tmp,0,5);/*make sure it doesn't use more than 4 chars*/
922                         memcpy(tmp,in,4);
923                         *it++=strtoul(tmp,&tend,0);
924                         in+=tend-tmp-1;
925                         break;
926                  case '1':case '2':case '3':case '4':case '5':
927                  case '6':case '7':case '8':case '9':
928                         memset(tmp,0,5);
929                         memcpy(tmp,in,3);
930                         *it++=strtoul(tmp,&tend,10);
931                         in+=tend-tmp-1;
932                         break;
933                  case 'x':
934                         memset(tmp,0,5);
935                         memcpy(tmp,++in,2);
936                         *it++=strtoul(tmp,&tend,16);
937                         in+=tend-tmp-1;
938                         break;
939                  default:*it++=*in;
940                 }
941         else
942                 *it++=*in;
943         *(it-1)='\0';
944         return out;
945 }