Release 941122
[wine/multimedia.git] / rc / winerc.c
blobb20ca32e6ebac75e4369204aa405696b32bbf81d
1 /*
3 * Copyright Martin von Loewis, 1994
5 */
7 static char Copyright[] = "Copyright Martin von Loewis, 1994";
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <sys/stat.h>
12 #include <sys/fcntl.h>
13 #include <sys/types.h>
14 #include <windows.h>
15 #include <neexe.h>
16 #include "rc.h"
17 #include "rc.tab.h"
19 char usage[]="winerc -dvc -p prefix -o outfile < infile \n";
21 /*might be overwritten by command line*/
22 char *prefix="_Resource";
23 int verbose,constant;
24 gen_res* g_start;
25 FILE *header,*code;
26 char hname[256],sname[256];
28 main(int argc,char *argv[])
30 extern int yydebug;
31 extern char* optarg;
32 int optc,lose,ret;
33 lose=0;
34 #if defined(__NetBSD__) || defined(__FreeBSD__)
35 while((optc=getopt(argc,argv,"dp:vo:"))!=EOF)
36 #else
37 while((optc=getopt(argc,argv,"dp:vo:",0))!=EOF)
38 #endif
39 switch(optc)
41 /* bison will print state transitions on stderr */
42 case 'd':yydebug=1;
43 setbuf(stdout,0);
44 setbuf(stderr,0);
45 break;
46 case 'p':prefix=optarg;break;
47 case 'c':constant=1;break;
48 case 'v':verbose=1;
49 setbuf(stderr,0);
50 break;
51 case 'o':set_out_file(optarg);break;
52 default: lose++;break;
54 if(lose)return fprintf(stderr,usage),1;
55 if(!header)header=stdout;
56 if(!code)code=stdout;
57 ret=yyparse();
58 fclose(header);
59 fclose(code);
60 return ret;
63 void set_out_file(char *prefix)
65 sprintf(sname,"%s.c",prefix);
66 code=fopen(sname,"w");
67 sprintf(hname,"%s.h",prefix);
68 header=fopen(hname,"w");
72 /* SunOS' memcpy is wrong for overlapping arrays */
73 char *save_memcpy(char *d,char* s,int l)
75 if(d<s)
76 for(;l;l--)*d++=*s++;
77 else
78 for(d+=l-1,s+=l-1;l;l--)*d--=*s--;
79 return d;
82 /*allow unaligned access*/
83 void put_WORD(unsigned char* p,WORD w)
85 *p=w&0xFF;
86 *(p+1)=w>>8;
89 void put_DWORD(unsigned char* p,DWORD d)
91 put_WORD(p,d&0xFFFF);
92 put_WORD(p+2,d>>16);
95 WORD get_WORD(unsigned char* p)
97 return *p|(*(p+1)<<8);
100 DWORD get_DWORD(unsigned char* p)
102 return get_WORD(p)|(get_WORD(p+2)<<16);
106 /*create a new gen_res, initial size 100*/
107 gen_res *new_res()
108 { gen_res* ret=malloc(sizeof(gen_res)+100);
109 int i;
110 if(!ret)
111 fprintf(stderr,"Out of memory\n"),exit(1);
112 for(i=0;i<sizeof(gen_res)+100;i++)*((char*)ret+i)='\0';
113 ret->g_next=g_start;
114 ret->g_prev=0;
115 g_start=ret;
116 ret->space=100;
117 return ret;
120 /*double the space*/
121 gen_res* grow(gen_res* res)
123 res=realloc(res,sizeof(gen_res)+2*res->space);
124 if(!res)
125 fprintf(stderr,"Out of memory\n"),exit(1);
126 if(!res->g_prev)g_start=res;
127 else res->g_prev->g_next=res;
128 if(res->g_next)res->g_next->g_prev=res;
129 res->space=2*res->space;
130 return res;
134 /* insert bytes at offset 0, increase num_entries */
135 gen_res* insert_at_beginning(gen_res* res,char* entry,int size)
137 while(res->size+size>res->space)res=grow(res);
138 save_memcpy(res->res+size,res->res,res->size);
139 save_memcpy(res->res,entry,size);
140 res->size+=size;
141 res->num_entries++;
142 return res;
145 /* insert length characters from bytes into res, starting at start */
146 gen_res* insert_bytes(gen_res* res,char* bytes,int start,int length)
148 while(res->size+length>res->space)res=grow(res);
149 save_memcpy(res->res+start+length,res->res+start,res->size-start);
150 save_memcpy(res->res+start,bytes,length);
151 res->size+=length;
152 return res;
155 /*delete len bytes from res, starting at start*/
156 gen_res* delete_bytes(gen_res* res,int start,int len)
158 save_memcpy(res->res+start,res->res+start+len,res->size-start-len);
159 res->size-=len;
160 return res;
163 /*create a new style*/
164 rc_style *new_style()
166 rc_style *ret=malloc(sizeof(rc_style));
167 /*initially, no bits have to be reset*/
168 ret->and=-1;
169 /*initially, no bits are set*/
170 ret->or=0;
171 return ret;
174 /* entries are inserted at the beginning, starting from the last one */
175 gen_res* add_accelerator(int ev, int id, int flags, gen_res* prev)
177 char accel_entry[5];
178 if(prev->num_entries==0)flags|=0x80; /* last entry */
179 accel_entry[0]=flags;
180 put_WORD(accel_entry+1,ev);
181 put_WORD(accel_entry+3,id);
182 return insert_at_beginning(prev,accel_entry,5);
186 /* create an integer from the event, taking things as "^c" into account
187 add this as new entry */
188 gen_res* add_string_accelerator(char *ev, int id, int flags, gen_res* prev)
190 int event;
191 if(*ev=='^')
192 event=ev[1]-'a';
193 else
194 event=ev[0];
195 return add_accelerator(event,id,flags,prev);
198 /*is there a difference between ASCII and VIRTKEY accelerators? */
200 gen_res* add_ascii_accelerator(int ev, int id, int flags, gen_res* prev)
202 return add_accelerator(ev,id,flags,prev);
205 gen_res* add_vk_accelerator(int ev, int id, int flags, gen_res* prev)
207 return add_accelerator(ev,id,flags,prev);
210 /* create a new dialog header, set all items to 0 */
211 gen_res* new_dialog()
212 { gen_res* ret=new_res();
213 ret->size=16; /*all strings "\0", no font*/
214 return ret;
217 /* the STYLE option was specified */
218 gen_res* dialog_style(rc_style* style, gen_res* attr)
220 /* default dialog styles? Do we need style->and? */
221 /* DS_SETFONT might have been specified before */
222 put_DWORD(attr->res,get_DWORD(attr->res)|style->or);
223 return attr;
226 /* menu name is at offset 13 */
227 int dialog_get_menu(gen_res* attr)
229 return 13;
232 /* the class is after the menu name */
233 int dialog_get_class(gen_res* attr)
235 int offs=dialog_get_menu(attr);
236 while(attr->res[offs])offs++;
237 offs++;
238 return offs;
241 /* the caption is after the class */
242 int dialog_get_caption(gen_res* attr)
244 int offs=dialog_get_class(attr);
245 while(attr->res[offs])offs++;
246 offs++;
247 return offs;
250 /* the fontsize, if present, is after the caption, followed by the font name */
251 int dialog_get_fontsize(gen_res* attr)
253 int offs=dialog_get_caption(attr);
254 while(attr->res[offs])offs++;
255 offs++;
256 return offs;
260 /* the CAPTION option was specified */
261 gen_res* dialog_caption(char* cap, gen_res*attr)
263 /* we don't need the terminating 0 as it's already there */
264 return insert_bytes(attr,cap,dialog_get_caption(attr),strlen(cap));
268 /* the FONT option was specified, set the DS_SETFONT flag */
269 gen_res* dialog_font(short size,char* font,gen_res *attr)
271 char c_size[2];
272 int offs=dialog_get_fontsize(attr);
273 put_DWORD(attr->res,get_DWORD(attr->res)|DS_SETFONT);
274 put_WORD(c_size,size);
275 attr=insert_bytes(attr,c_size,offs,2);
276 offs+=2;
277 /* as there is no font name by default, copy the '\0' */
278 return insert_bytes(attr,font,offs,strlen(font)+1);
281 gen_res* dialog_class(char* cap, gen_res*attr)
283 return insert_bytes(attr,cap,dialog_get_class(attr),strlen(cap));
286 gen_res* dialog_menu(char* cap, gen_res*attr)
288 return insert_bytes(attr,cap,dialog_get_menu(attr),strlen(cap));
291 /* set the dialogs id, position, extent, and style */
292 gen_res* create_control_desc(int id,int x,int y,int cx, int cy,rc_style *style)
293 { gen_res* ret=new_res();
294 int s=WS_VISIBLE|WS_CHILD; /*defaults styles for any control*/
295 put_WORD(ret->res+0,x);
296 put_WORD(ret->res+2,y);
297 put_WORD(ret->res+4,cx);
298 put_WORD(ret->res+6,cy);
299 put_WORD(ret->res+8,id);
300 if(style)s=(s|style->or)&style->and;
301 put_DWORD(ret->res+10,s);
302 ret->size=17; /*empty strings, unused byte*/
303 return ret;
306 /* insert the control's label */
307 gen_res* label_control_desc(char* label,gen_res* cd)
309 int offs;
310 if(cd->res[14]&0x80)offs=15; /* one-character class */
311 else {
312 for(offs=14;cd->res[offs];offs++);
313 offs++;
315 return insert_bytes(cd,label,offs,strlen(label));
318 /* a CONTROL was specified */
319 gen_res* create_generic_control(char* label,int id,char* class,
320 rc_style*style,int x,int y,int cx,int cy)
321 { char cl;
322 gen_res* ret=new_res();
323 put_WORD(ret->res+0,x);
324 put_WORD(ret->res+2,y);
325 put_WORD(ret->res+4,cx);
326 put_WORD(ret->res+6,cy);
327 put_WORD(ret->res+8,id);
328 put_DWORD(ret->res+10,style->or);
329 ret->size=17;
330 ret=insert_bytes(ret,label,15,strlen(label));
331 /* is it a predefined class? */
332 cl=0;
333 if(!strcmp(class,"BUTTON"))cl=CT_BUTTON;
334 if(!strcmp(class,"EDIT"))cl=CT_EDIT;
335 if(!strcmp(class,"STATIC"))cl=CT_STATIC;
336 if(!strcmp(class,"LISTBOX"))cl=CT_LISTBOX;
337 if(!strcmp(class,"SCROLLBAR"))cl=CT_SCROLLBAR;
338 if(!strcmp(class,"COMBOBOX"))cl=CT_COMBOBOX;
339 if(cl)ret->res[14]=cl;
340 else ret=insert_bytes(ret,class,14,strlen(class));
341 return ret;
344 /* insert cd into rest, set the type, add flags */
345 gen_res* add_control(int type,int flags,gen_res*cd,gen_res* rest)
347 put_DWORD(cd->res+10,get_DWORD(cd->res+10)|flags);
348 cd->res[14]=type;
349 return insert_at_beginning(rest,cd->res,cd->size);
352 /* an ICON control was specified, whf contains width, height, and flags */
353 gen_res* add_icon(char* name,int id,int x,int y,gen_res* whf,gen_res* rest)
355 put_WORD(whf->res+0,x);
356 put_WORD(whf->res+2,y);
357 put_WORD(whf->res+8,id);
358 whf=label_control_desc(name,whf);
359 return add_control(CT_STATIC,SS_ICON,whf,rest);
362 /* insert the generic control into rest */
363 gen_res* add_generic_control(gen_res* ctl, gen_res* rest)
365 return insert_at_beginning(rest,ctl->res,ctl->size);
368 /* create a dialog resource by inserting the header into the controls.
369 Set position and extent */
370 gen_res* make_dialog(gen_res* header,int x,int y,int cx,int cy,gen_res* ctls)
372 header->res[4]=ctls->num_entries;
373 header->type=dlg;
374 put_WORD(header->res+5,x);
375 put_WORD(header->res+7,y);
376 put_WORD(header->res+9,cx);
377 put_WORD(header->res+11,cy);
378 return insert_bytes(header,ctls->res,header->size,ctls->size);
381 /* create {0x15,0x16,0xFF} from '15 16 FF' */
382 gen_res *hex_to_raw(char *hex, gen_res*rest)
384 char r2[16];
385 int i;
386 for(i=0;*hex!='\'';i++)r2[i]=strtoul(hex,&hex,16);
387 return insert_bytes(rest,r2,0,i);
390 /* create a bitmap resource */
391 gen_res *make_bitmap(gen_res* res)
393 res=delete_bytes(res,0,14); /* skip bitmap file header*/
394 res->type=bmp;
395 return res;
398 gen_res *make_icon(gen_res* res)
400 res->type=ico;
401 return res;
404 gen_res *make_cursor(gen_res* res)
406 res->type=cur;
407 return res;
410 /* load resource bytes from the file name */
411 gen_res *load_file(char* name)
413 gen_res *res;
414 struct stat st;
415 int f=open(name,O_RDONLY);
416 if(!f)perror(name);
417 fstat(f,&st);
418 res=new_res();
419 while(res->space<st.st_size)res=grow(res);
420 read(f,res->res,st.st_size);
421 res->size=st.st_size;
422 close(f);
423 return res;
426 /* insert a normal menu item into res, starting from the last item */
427 gen_res *add_menuitem(char* name,int id,int flags,gen_res *res)
429 char item[4];
430 if(res->num_entries==0)flags|=MF_END;
431 put_WORD(item,flags);
432 put_WORD(item+2,id);
433 res=insert_at_beginning(res,name,strlen(name)+1);
434 res=insert_bytes(res,item,0,4);
435 return res;
438 /* insert a popup item into res */
439 gen_res *add_popup(char *name,short flags, gen_res* body, gen_res*res)
441 char c_flags[2];
442 if(res->num_entries==0)flags|=MF_END;
443 put_WORD(c_flags,flags);
444 res=insert_at_beginning(res,body->res,body->size);
445 res=insert_bytes(res,name,0,strlen(name)+1);
446 res=insert_bytes(res,c_flags,0,2);
447 return res;
450 /* prefix the menu header into res */
451 gen_res *make_menu(gen_res* res)
453 static char header[4]={0,0,0,0};
454 res=insert_at_beginning(res,header,4);
455 res->type=men;
456 return res;
459 /* link top-level resources */
460 gen_res *add_resource(gen_res* first,gen_res *rest)
462 first->next=rest;
463 return first;
466 char *get_typename(gen_res* t)
468 switch(t->type){
469 case acc:return "ACCELERATOR";
470 case bmp:return "BITMAP";
471 case cur:return "CURSOR";
472 case dlg:return "DIALOG";
473 case fnt:return "FONT";
474 case ico:return "ICON";
475 case men:return "MENU";
476 case rdt:return "RCDATA";
477 case str:return "STRINGTABLE";
478 default: return "UNKNOWN";
482 /* create strings like _Sysres_DIALOG_2 */
483 char *get_resource_name(gen_res*it)
485 static char buf[1000];
486 if(it->n_type)
487 sprintf(buf,"%s_%s_%s",prefix,get_typename(it),it->n.s_name);
488 else
489 sprintf(buf,"%s_%s_%d",prefix,get_typename(it),it->n.i_name);
490 return buf;
493 #define ISCONSTANT constant?"const ":""
494 /* create the final output */
495 void create_output(gen_res* top)
497 gen_res *it;
498 fprintf(header,"/*\t\t%s\n * This File is automatically generated."
499 " Do not edit\n */\n#include \"resource.h\"\n",hname);
500 fprintf(code,"/*\t\t%s\n * This File is automatically generated."
501 " Do not edit\n */\n",sname);
502 /* declare the resources */
503 for(it=top;it;it=it->next)
504 fprintf(header,"extern %sunsigned char %s[];\n",ISCONSTANT,
505 get_resource_name(it));
506 fprintf(header,"extern %sstruct ResourceTable %sTable[];\n",
507 ISCONSTANT,prefix);
509 fprintf(code,"#include \"prototypes.h\"\n#include \"%s\"\n",hname);
511 /* print the resource table (0 terminated) */
512 fprintf(code,"\n%sstruct ResourceTable %sTable[]={\n",ISCONSTANT,prefix);
513 for(it=top;it;it=it->next)
514 { int type;
515 switch(it->type)
516 {case acc:type=NE_RSCTYPE_ACCELERATOR;break;
517 case bmp:type=NE_RSCTYPE_BITMAP;break;
518 case cur:type=NE_RSCTYPE_CURSOR;break;
519 case dlg:type=NE_RSCTYPE_DIALOG;break;
520 case fnt:type=NE_RSCTYPE_FONT;break;
521 case ico:type=NE_RSCTYPE_ICON;break;
522 case men:type=NE_RSCTYPE_MENU;break;
523 case rdt:type=NE_RSCTYPE_RCDATA;break;
524 case str:type=NE_RSCTYPE_STRING;break;
525 default:fprintf(stderr,"Unknown restype\n");type=-1;break;
527 if(it->n_type)
528 fprintf(code,"{0,%d,\"%s\",%s,%d},\n",
529 type,it->n.s_name,get_resource_name(it),it->size);
530 else
531 fprintf(code,"{%d,%d,\"@%d\",%s,%d},\n",
532 it->n.i_name,type,it->n.i_name,get_resource_name(it),
533 it->size);
535 fprintf(code,"{0,0,0,0}};\n\n");
537 /* print the resources */
538 for(it=top;it;it=it->next)
539 { int i;
540 fprintf(code,"%sunsigned char %s[]={\n",
541 ISCONSTANT,get_resource_name(it));
542 for(i=0;i<it->size-1;i++)
544 fprintf(code,"%#4x,",it->res[i]);
545 if((i&7)==7)fputc('\n',code);
547 fprintf(code,"%#4x};\n",it->res[i]);
551 void make_font()
553 fprintf(stderr,"Fonts not supported\n");
556 void make_raw()
558 fprintf(stderr,"RCData not supported\n");
561 void int_to_raw()
563 fprintf(stderr,"IntToRaw not supported\n");
566 /* translate "Hello,\\tworld!\\10" to "Hello,\tworld!\n" */
567 char *parse_c_string(char *in)
569 char *out=malloc(strlen(in)-1);
570 char *it;
571 char tmp[5],*tend;
572 for(it=out,in++;*in;in++)
573 if(*in=='\\')
574 switch(*++in)
575 {case 't':*it++='\t';break;
576 case 'r':*it++='\r';break;
577 case 'n':*it++='\n';break;
578 case 'a':*it++='\a';break;
579 case '0':
580 memset(tmp,0,5);/*make sure it doesn't use more than 4 chars*/
581 memcpy(tmp,in,4);
582 *it++=strtoul(tmp,&tend,0);
583 in+=tend-tmp-1;
584 break;
585 case '1':case '2':case '3':case '4':case '5':
586 case '6':case '7':case '8':case '9':
587 memset(tmp,0,5);
588 memcpy(tmp,in,3);
589 *it++=strtoul(tmp,&tend,10);
590 in+=tend-tmp-1;
591 break;
592 case 'x':
593 memset(tmp,0,5);
594 memcpy(tmp,++in,2);
595 *it++=strtoul(tmp,&tend,16);
596 in+=tend-tmp-1;
597 break;
598 default:*it++=*in;
600 else
601 *it++=*in;
602 *(it-1)='\0';
603 return out;