3 * Copyright Martin von Loewis, 1994
6 static char Copyright
[] = "Copyright Martin von Loewis, 1994";
11 #include <sys/fcntl.h>
12 #include <sys/types.h>
20 char usage
[]="winerc -dvc -p prefix -o outfile < infile \n";
22 /*might be overwritten by command line*/
23 char *prefix
="_Resource";
27 char hname
[256],sname
[256];
29 int main(int argc
,char *argv
[])
35 #if defined(__NetBSD__) || defined(__FreeBSD__)
36 while((optc
=getopt(argc
,argv
,"dp:vo:"))!=EOF
)
38 while((optc
=getopt(argc
,argv
,"dp:vo:",0))!=EOF
)
42 /* bison will print state transitions on stderr */
47 case 'p':prefix
=optarg
;break;
48 case 'c':constant
=1;break;
52 case 'o':set_out_file(optarg
);break;
53 default: lose
++;break;
55 if(lose
)return fprintf(stderr
,usage
),1;
56 if(!header
)header
=stdout
;
64 void set_out_file(char *prefix
)
66 sprintf(sname
,"%s.c",prefix
);
67 code
=fopen(sname
,"w");
68 sprintf(hname
,"%s.h",prefix
);
69 header
=fopen(hname
,"w");
73 /* SunOS' memcpy is wrong for overlapping arrays */
74 char *save_memcpy(char *d
,char* s
,int l
)
79 for(d
+=l
-1,s
+=l
-1;l
;l
--)*d
--=*s
--;
83 /*allow unaligned access*/
84 void put_WORD(unsigned char* p
,WORD w
)
90 void put_DWORD(unsigned char* p
,DWORD d
)
96 WORD
get_WORD(unsigned char* p
)
98 return *p
|(*(p
+1)<<8);
101 DWORD
get_DWORD(unsigned char* p
)
103 return get_WORD(p
)|(get_WORD(p
+2)<<16);
107 /*create a new gen_res, initial size 100*/
109 { gen_res
* ret
=malloc(sizeof(gen_res
)+100);
112 fprintf(stderr
,"Out of memory\n"),exit(1);
113 for(i
=0;i
<sizeof(gen_res
)+100;i
++)*((char*)ret
+i
)='\0';
122 gen_res
* grow(gen_res
* res
)
124 res
=realloc(res
,sizeof(gen_res
)+2*res
->space
);
126 fprintf(stderr
,"Out of memory\n"),exit(1);
127 if(!res
->g_prev
)g_start
=res
;
128 else res
->g_prev
->g_next
=res
;
129 if(res
->g_next
)res
->g_next
->g_prev
=res
;
130 res
->space
=2*res
->space
;
135 /* insert bytes at offset 0, increase num_entries */
136 gen_res
* insert_at_beginning(gen_res
* res
,char* entry
,int size
)
138 while(res
->size
+size
>res
->space
)res
=grow(res
);
139 save_memcpy(res
->res
+size
,res
->res
,res
->size
);
140 save_memcpy(res
->res
,entry
,size
);
146 /* insert length characters from bytes into res, starting at start */
147 gen_res
* insert_bytes(gen_res
* res
,char* bytes
,int start
,int length
)
149 while(res
->size
+length
>res
->space
)res
=grow(res
);
150 save_memcpy(res
->res
+start
+length
,res
->res
+start
,res
->size
-start
);
151 save_memcpy(res
->res
+start
,bytes
,length
);
156 /*delete len bytes from res, starting at start*/
157 gen_res
* delete_bytes(gen_res
* res
,int start
,int len
)
159 save_memcpy(res
->res
+start
,res
->res
+start
+len
,res
->size
-start
-len
);
164 /*create a new style*/
165 rc_style
*new_style()
167 rc_style
*ret
=malloc(sizeof(rc_style
));
168 /*initially, no bits have to be reset*/
170 /*initially, no bits are set*/
175 /* entries are inserted at the beginning, starting from the last one */
176 gen_res
* add_accelerator(int ev
, int id
, int flags
, gen_res
* prev
)
179 if(prev
->num_entries
==0)flags
|=0x80; /* last entry */
180 accel_entry
[0]=flags
;
181 put_WORD(accel_entry
+1,ev
);
182 put_WORD(accel_entry
+3,id
);
183 return insert_at_beginning(prev
,accel_entry
,5);
187 /* create an integer from the event, taking things as "^c" into account
188 add this as new entry */
189 gen_res
* add_string_accelerator(char *ev
, int id
, int flags
, gen_res
* prev
)
196 return add_accelerator(event
,id
,flags
,prev
);
199 /*is there a difference between ASCII and VIRTKEY accelerators? */
201 gen_res
* add_ascii_accelerator(int ev
, int id
, int flags
, gen_res
* prev
)
203 return add_accelerator(ev
,id
,flags
,prev
);
206 gen_res
* add_vk_accelerator(int ev
, int id
, int flags
, gen_res
* prev
)
208 return add_accelerator(ev
,id
,flags
,prev
);
211 /* create a new dialog header, set all items to 0 */
212 gen_res
* new_dialog()
213 { gen_res
* ret
=new_res();
214 ret
->size
=16; /*all strings "\0", no font*/
218 /* the STYLE option was specified */
219 gen_res
* dialog_style(rc_style
* style
, gen_res
* attr
)
221 /* default dialog styles? Do we need style->and? */
222 /* DS_SETFONT might have been specified before */
223 put_DWORD(attr
->res
,get_DWORD(attr
->res
)|style
->or);
227 /* menu name is at offset 13 */
228 int dialog_get_menu(gen_res
* attr
)
233 /* the class is after the menu name */
234 int dialog_get_class(gen_res
* attr
)
236 int offs
=dialog_get_menu(attr
);
237 while(attr
->res
[offs
])offs
++;
242 /* the caption is after the class */
243 int dialog_get_caption(gen_res
* attr
)
245 int offs
=dialog_get_class(attr
);
246 while(attr
->res
[offs
])offs
++;
251 /* the fontsize, if present, is after the caption, followed by the font name */
252 int dialog_get_fontsize(gen_res
* attr
)
254 int offs
=dialog_get_caption(attr
);
255 while(attr
->res
[offs
])offs
++;
261 /* the CAPTION option was specified */
262 gen_res
* dialog_caption(char* cap
, gen_res
*attr
)
264 /* we don't need the terminating 0 as it's already there */
265 return insert_bytes(attr
,cap
,dialog_get_caption(attr
),strlen(cap
));
269 /* the FONT option was specified, set the DS_SETFONT flag */
270 gen_res
* dialog_font(short size
,char* font
,gen_res
*attr
)
273 int offs
=dialog_get_fontsize(attr
);
274 put_DWORD(attr
->res
,get_DWORD(attr
->res
)|DS_SETFONT
);
275 put_WORD(c_size
,size
);
276 attr
=insert_bytes(attr
,c_size
,offs
,2);
278 /* as there is no font name by default, copy the '\0' */
279 return insert_bytes(attr
,font
,offs
,strlen(font
)+1);
282 gen_res
* dialog_class(char* cap
, gen_res
*attr
)
284 return insert_bytes(attr
,cap
,dialog_get_class(attr
),strlen(cap
));
287 gen_res
* dialog_menu(char* cap
, gen_res
*attr
)
289 return insert_bytes(attr
,cap
,dialog_get_menu(attr
),strlen(cap
));
292 /* set the dialogs id, position, extent, and style */
293 gen_res
* create_control_desc(int id
,int x
,int y
,int cx
, int cy
,rc_style
*style
)
294 { gen_res
* ret
=new_res();
295 int s
=WS_VISIBLE
|WS_CHILD
; /*defaults styles for any control*/
296 put_WORD(ret
->res
+0,x
);
297 put_WORD(ret
->res
+2,y
);
298 put_WORD(ret
->res
+4,cx
);
299 put_WORD(ret
->res
+6,cy
);
300 put_WORD(ret
->res
+8,id
);
301 if(style
)s
=(s
|style
->or)&style
->and;
302 put_DWORD(ret
->res
+10,s
);
303 ret
->size
=17; /*empty strings, unused byte*/
307 /* insert the control's label */
308 gen_res
* label_control_desc(char* label
,gen_res
* cd
)
311 if(cd
->res
[14]&0x80)offs
=15; /* one-character class */
313 for(offs
=14;cd
->res
[offs
];offs
++);
316 return insert_bytes(cd
,label
,offs
,strlen(label
));
319 /* a CONTROL was specified */
320 gen_res
* create_generic_control(char* label
,int id
,char* class,
321 rc_style
*style
,int x
,int y
,int cx
,int cy
)
323 gen_res
* ret
=new_res();
324 put_WORD(ret
->res
+0,x
);
325 put_WORD(ret
->res
+2,y
);
326 put_WORD(ret
->res
+4,cx
);
327 put_WORD(ret
->res
+6,cy
);
328 put_WORD(ret
->res
+8,id
);
329 put_DWORD(ret
->res
+10,style
->or);
331 ret
=insert_bytes(ret
,label
,15,strlen(label
));
332 /* is it a predefined class? */
334 if(!strcmp(class,"BUTTON"))cl
=CT_BUTTON
;
335 if(!strcmp(class,"EDIT"))cl
=CT_EDIT
;
336 if(!strcmp(class,"STATIC"))cl
=CT_STATIC
;
337 if(!strcmp(class,"LISTBOX"))cl
=CT_LISTBOX
;
338 if(!strcmp(class,"SCROLLBAR"))cl
=CT_SCROLLBAR
;
339 if(!strcmp(class,"COMBOBOX"))cl
=CT_COMBOBOX
;
340 if(cl
)ret
->res
[14]=cl
;
341 else ret
=insert_bytes(ret
,class,14,strlen(class));
345 /* insert cd into rest, set the type, add flags */
346 gen_res
* add_control(int type
,int flags
,gen_res
*cd
,gen_res
* rest
)
348 put_DWORD(cd
->res
+10,get_DWORD(cd
->res
+10)|flags
);
350 return insert_at_beginning(rest
,cd
->res
,cd
->size
);
353 /* an ICON control was specified, whf contains width, height, and flags */
354 gen_res
* add_icon(char* name
,int id
,int x
,int y
,gen_res
* whf
,gen_res
* rest
)
356 put_WORD(whf
->res
+0,x
);
357 put_WORD(whf
->res
+2,y
);
358 put_WORD(whf
->res
+8,id
);
359 whf
=label_control_desc(name
,whf
);
360 return add_control(CT_STATIC
,SS_ICON
,whf
,rest
);
363 /* insert the generic control into rest */
364 gen_res
* add_generic_control(gen_res
* ctl
, gen_res
* rest
)
366 return insert_at_beginning(rest
,ctl
->res
,ctl
->size
);
369 /* create a dialog resource by inserting the header into the controls.
370 Set position and extent */
371 gen_res
* make_dialog(gen_res
* header
,int x
,int y
,int cx
,int cy
,gen_res
* ctls
)
373 header
->res
[4]=ctls
->num_entries
;
375 put_WORD(header
->res
+5,x
);
376 put_WORD(header
->res
+7,y
);
377 put_WORD(header
->res
+9,cx
);
378 put_WORD(header
->res
+11,cy
);
379 return insert_bytes(header
,ctls
->res
,header
->size
,ctls
->size
);
382 /* create {0x15,0x16,0xFF} from '15 16 FF' */
383 gen_res
*hex_to_raw(char *hex
, gen_res
*rest
)
387 for(i
=0;*hex
!='\'';i
++)r2
[i
]=strtoul(hex
,&hex
,16);
388 return insert_bytes(rest
,r2
,0,i
);
391 /* create a bitmap resource */
392 gen_res
*make_bitmap(gen_res
* res
)
394 res
=delete_bytes(res
,0,14); /* skip bitmap file header*/
399 gen_res
*make_icon(gen_res
* res
)
405 gen_res
*make_cursor(gen_res
* res
)
411 /* load resource bytes from the file name */
412 gen_res
*load_file(char* name
)
416 int f
=open(name
,O_RDONLY
);
420 while(res
->space
<st
.st_size
)res
=grow(res
);
421 read(f
,res
->res
,st
.st_size
);
422 res
->size
=st
.st_size
;
427 /* insert a normal menu item into res, starting from the last item */
428 gen_res
*add_menuitem(char* name
,int id
,int flags
,gen_res
*res
)
431 if(res
->num_entries
==0)flags
|=MF_END
;
432 put_WORD(item
,flags
);
434 res
=insert_at_beginning(res
,name
,strlen(name
)+1);
435 res
=insert_bytes(res
,item
,0,4);
439 /* insert a popup item into res */
440 gen_res
*add_popup(char *name
,short flags
, gen_res
* body
, gen_res
*res
)
443 if(res
->num_entries
==0)flags
|=MF_END
;
444 put_WORD(c_flags
,flags
);
445 res
=insert_at_beginning(res
,body
->res
,body
->size
);
446 res
=insert_bytes(res
,name
,0,strlen(name
)+1);
447 res
=insert_bytes(res
,c_flags
,0,2);
451 /* prefix the menu header into res */
452 gen_res
*make_menu(gen_res
* res
)
454 static char header
[4]={0,0,0,0};
455 res
=insert_at_beginning(res
,header
,4);
460 /* link top-level resources */
461 gen_res
*add_resource(gen_res
* first
,gen_res
*rest
)
467 char *get_typename(gen_res
* t
)
470 case acc
:return "ACCELERATOR";
471 case bmp
:return "BITMAP";
472 case cur
:return "CURSOR";
473 case dlg
:return "DIALOG";
474 case fnt
:return "FONT";
475 case ico
:return "ICON";
476 case men
:return "MENU";
477 case rdt
:return "RCDATA";
478 case str
:return "STRINGTABLE";
479 default: return "UNKNOWN";
483 /* create strings like _Sysres_DIALOG_2 */
484 char *get_resource_name(gen_res
*it
)
486 static char buf
[1000];
488 sprintf(buf
,"%s_%s_%s",prefix
,get_typename(it
),it
->n
.s_name
);
490 sprintf(buf
,"%s_%s_%d",prefix
,get_typename(it
),it
->n
.i_name
);
494 #define ISCONSTANT constant?"const ":""
495 /* create the final output */
496 void create_output(gen_res
* top
)
499 fprintf(header
,"/*\t\t%s\n * This File is automatically generated."
500 " Do not edit\n */\n#include \"resource.h\"\n",hname
);
501 fprintf(code
,"/*\t\t%s\n * This File is automatically generated."
502 " Do not edit\n */\n",sname
);
503 /* declare the resources */
504 for(it
=top
;it
;it
=it
->next
)
505 fprintf(header
,"extern %sunsigned char %s[];\n",ISCONSTANT
,
506 get_resource_name(it
));
507 fprintf(header
,"extern %sstruct ResourceTable %sTable[];\n",
510 fprintf(code
,"#include \"prototypes.h\"\n#include \"%s\"\n",hname
);
512 /* print the resource table (0 terminated) */
513 fprintf(code
,"\n%sstruct ResourceTable %sTable[]={\n",ISCONSTANT
,prefix
);
514 for(it
=top
;it
;it
=it
->next
)
517 {case acc
:type
=NE_RSCTYPE_ACCELERATOR
;break;
518 case bmp
:type
=NE_RSCTYPE_BITMAP
;break;
519 case cur
:type
=NE_RSCTYPE_CURSOR
;break;
520 case dlg
:type
=NE_RSCTYPE_DIALOG
;break;
521 case fnt
:type
=NE_RSCTYPE_FONT
;break;
522 case ico
:type
=NE_RSCTYPE_ICON
;break;
523 case men
:type
=NE_RSCTYPE_MENU
;break;
524 case rdt
:type
=NE_RSCTYPE_RCDATA
;break;
525 case str
:type
=NE_RSCTYPE_STRING
;break;
526 default:fprintf(stderr
,"Unknown restype\n");type
=-1;break;
529 fprintf(code
,"{0,%d,\"%s\",%s,%d},\n",
530 type
,it
->n
.s_name
,get_resource_name(it
),it
->size
);
532 fprintf(code
,"{%d,%d,\"@%d\",%s,%d},\n",
533 it
->n
.i_name
,type
,it
->n
.i_name
,get_resource_name(it
),
536 fprintf(code
,"{0,0,0,0}};\n\n");
538 /* print the resources */
539 for(it
=top
;it
;it
=it
->next
)
541 fprintf(code
,"%sunsigned char %s[]={\n",
542 ISCONSTANT
,get_resource_name(it
));
543 for(i
=0;i
<it
->size
-1;i
++)
545 fprintf(code
,"%#4x,",it
->res
[i
]);
546 if((i
&7)==7)fputc('\n',code
);
548 fprintf(code
,"%#4x};\n",it
->res
[i
]);
554 fprintf(stderr
,"Fonts not supported\n");
559 fprintf(stderr
,"RCData not supported\n");
564 fprintf(stderr
,"IntToRaw not supported\n");
567 /* translate "Hello,\\tworld!\\10" to "Hello,\tworld!\n" */
568 char *parse_c_string(char *in
)
570 char *out
=malloc(strlen(in
)-1);
573 for(it
=out
,in
++;*in
;in
++)
576 {case 't':*it
++='\t';break;
577 case 'r':*it
++='\r';break;
578 case 'n':*it
++='\n';break;
579 case 'a':*it
++='\a';break;
581 memset(tmp
,0,5);/*make sure it doesn't use more than 4 chars*/
583 *it
++=strtoul(tmp
,&tend
,0);
586 case '1':case '2':case '3':case '4':case '5':
587 case '6':case '7':case '8':case '9':
590 *it
++=strtoul(tmp
,&tend
,10);
596 *it
++=strtoul(tmp
,&tend
,16);