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