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