Removed resource.h.
[wine] / tools / wrc / wrc.c
1 /*
2  *
3  * Copyright  Martin von Loewis, 1994
4  * Copyrignt 1998 Bertho A. Stultiens (BS)
5  *
6  * 20-Jun-1998 BS       - Added -L option to prevent case conversion
7  *                        of embedded filenames.
8  *
9  * 08-Jun-1998 BS       - Added -A option to generate autoregister code
10  *                        for winelib operation.
11  *
12  * 21-May-1998 BS       - Removed the CPP option. Its internal now.
13  *                      - Added implementations for defines and includes
14  *                        on the commandline.
15  *
16  * 30-Apr-1998 BS       - The options now contain nearly the entire alphabet.
17  *                        Seems to be a sign for too much freedom. I implemeted
18  *                        most of them as a user choice possibility for things
19  *                        that I do not know what to put there by default.
20  *                      - -l and -L options are now known as -t and -T.
21  *
22  * 23-Apr-1998 BS       - Finally gave up on backward compatibility on the
23  *                        commandline (after a blessing from the newsgroup).
24  *                        So, I changed the lot.
25  *
26  * 17-Apr-1998 BS       - Added many new command-line options but took care
27  *                        that it would not break old scripts (sigh).
28  *
29  * 16-Apr-1998 BS       - There is not much left of the original source...
30  *                        I had to rewrite most of it because the parser
31  *                        changed completely with all the types etc..
32  *
33  */
34
35 #include "config.h"
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <assert.h>
41 #include <ctype.h>
42
43 #include "wrc.h"
44 #include "utils.h"
45 #include "writeres.h"
46 #include "readres.h"
47 #include "dumpres.h"
48 #include "genres.h"
49 #include "newstruc.h"
50 #include "preproc.h"
51 #include "parser.h"
52
53 char usage[] = "Usage: wrc [options...] [infile[.rc|.res]]\n"
54         "   -a n        Alignment of resource (win16 only, default is 4)\n"
55         "   -A          Auto register resources (only with gcc 2.7 and better)\n"
56         "   -b          Create a C array from a binary .res file\n"
57         "   -c          Add 'const' prefix to C constants\n"
58         "   -C cp       Set the resource's codepage to cp (default is 0)\n"
59         "   -d n        Set debug level to 'n'\n"
60         "   -D id[=val] Define preprocessor identifier id=val\n"
61         "   -e          Disable recognition of win32 keywords in 16bit compile\n"
62         "   -g          Add symbols to the global c namespace\n"
63         "   -h          Also generate a .h file\n"
64         "   -H file     Same as -h but written to file\n"
65         "   -I path     Set include search dir to path (multiple -I allowed)\n"
66         "   -l lan      Set default language to lan (default is neutral {0})\n"
67         "   -L          Leave case of embedded filenames as is\n"
68         "   -n          Do not generate .s file\n"
69         "   -o file     Output to file (default is infile.[res|s|h]\n"
70         "   -p prefix   Give a prefix for the generated names\n"
71         "   -r          Create binary .res file (compile only)\n"
72         "   -s          Add structure with win32/16 (PE/NE) resource directory\n"
73         "   -t          Generate indirect loadable resource tables\n"
74         "   -T          Generate only indirect loadable resources tables\n"
75         "   -V          Print version end exit\n"
76         "   -w 16|32    Select win16 or win32 output (default is win32)\n"
77         "   -W          Enable pedantic warnings\n"
78         "Input is taken from stdin if no sourcefile specified.\n"
79         "Debug level 'n' is a bitmask with following meaning:\n"
80         "    * 0x01 Tell which resource is parsed (verbose mode)\n"
81         "    * 0x02 Dump internal structures\n"
82         "    * 0x04 Create a parser trace (yydebug=1)\n"
83         "The -o option only applies to the final destination file, which is\n"
84         "in case of normal compile a .s file. You must use the '-H header.h'\n"
85         "option to override the header-filename.\n"
86         "If no input filename is given and the output name is not overridden\n"
87         "with -o and/or -H, then the output is written to \"wrc.tab.[sh]\"\n"
88         ;
89
90 char version_string[] = "Wine Resource Compiler Version " WRC_FULLVERSION "\n"
91                         "Copyright 1998,1999 Bertho A. Stultiens\n"
92                         "          1994 Martin von Loewis\n";
93
94 /*
95  * Default prefix for resource names used in the C array.
96  * Option '-p name' sets it to 'name'
97  */
98 #ifdef NEED_UNDERSCORE_PREFIX
99 char *prefix = "__Resource";
100 #else
101 char *prefix = "_Resource";
102 #endif
103
104 /*
105  * Set if compiling in 32bit mode (default).
106  */
107 int win32 = 1;
108
109 /*
110  * Set when generated C variables should be prefixed with 'const'
111  */
112 int constant = 0;
113
114 /*
115  * Create a .res file from the source and exit (-r option).
116  */
117 int create_res = 0;
118
119 /*
120  * debuglevel == DEBUGLEVEL_NONE        Don't bother
121  * debuglevel & DEBUGLEVEL_CHAT         Say whats done
122  * debuglevel & DEBUGLEVEL_DUMP         Dump internal structures
123  * debuglevel & DEBUGLEVEL_TRACE        Create parser trace
124  */
125 int debuglevel = DEBUGLEVEL_NONE;
126
127 /*
128  * Recognize win32 keywords if set (-w 32 enforces this),
129  * otherwise set with -e option.
130  */
131 int extensions = 1;
132
133 /*
134  * Set when creating C array from .res file (-b option).
135  */
136 int binary = 0;
137
138 /*
139  * Set when an additional C-header is to be created in compile (-h option).
140  */
141 int create_header = 0;
142
143 /*
144  * Set when the NE/PE resource directory should be dumped into
145  * the output file.
146  */
147 int create_dir = 0;
148
149 /*
150  * Set when all symbols should be added to the global namespace (-g option)
151  */
152 int global = 0;
153
154 /*
155  * Set when indirect loadable resource tables should be created (-t)
156  */
157 int indirect = 0;
158
159 /*
160  * Set when _only_ indirect loadable resource tables should be created (-T)
161  */
162 int indirect_only = 0;
163
164 /*
165  * NE segment resource aligment (-a option)
166  */
167 int alignment = 4;
168 int alignment_pwr;
169
170 /*
171  * Cleared when the assembly file must be suppressed (-n option)
172  */
173 int create_s = 1;
174
175 /*
176  * Language setting for resources (-l option)
177  */
178 language_t *currentlanguage = NULL;
179
180 /*
181  * The codepage to write in win32 PE resource segment (-C option)
182  */
183 DWORD codepage = 0;
184
185 /*
186  * Set when extra warnings should be generated (-W option)
187  */
188 int pedantic = 0;
189
190 /*
191  * Set when autoregister code must be added to the output (-A option)
192  */
193 int auto_register = 0;
194
195 /*
196  * Set when the case of embedded filenames should not be converted
197  * to lower case (-L option)
198  */
199 int leave_case = 0;
200
201 char *output_name;              /* The name given by the -o option */
202 char *input_name;               /* The name given on the command-line */
203 char *header_name;              /* The name given by the -H option */
204
205 char *cmdline;                  /* The entire commandline */
206
207 resource_t *resource_top;       /* The top of the parsed resources */
208
209 int getopt (int argc, char *const *argv, const char *optstring);
210
211 int main(int argc,char *argv[])
212 {
213         extern char* optarg;
214         extern int   optind;
215         int optc;
216         int lose = 0;
217         int ret;
218         int a;
219         int i;
220         int cmdlen;
221
222         /* First rebuild the commandline to put in destination */
223         /* Could be done through env[], but not all OS-es support it */
224         cmdlen = 4; /* for "wrc " */
225         for(i = 1; i < argc; i++)
226                 cmdlen += strlen(argv[i]) + 1;
227         cmdline = (char *)xmalloc(cmdlen);
228         strcpy(cmdline, "wrc ");
229         for(i = 1; i < argc; i++)
230         {
231                 strcat(cmdline, argv[i]);
232                 if(i < argc-1)
233                         strcat(cmdline, " ");
234         }
235
236         while((optc = getopt(argc, argv, "a:AbcC:d:D:eghH:I:l:Lno:p:rstTVw:W")) != EOF)
237         {
238                 switch(optc)
239                 {
240                 case 'a':
241                         alignment = atoi(optarg);
242                         break;
243                 case 'A':
244                         auto_register = 1;
245                         break;
246                 case 'b':
247                         binary = 1;
248                         break;
249                 case 'c':
250                         constant = 1;
251                         break;
252                 case 'C':
253                         codepage = strtol(optarg, NULL, 0);
254                         break;
255                 case 'd':
256                         debuglevel = strtol(optarg, NULL, 0);
257                         break;
258                 case 'D':
259                         add_cmdline_define(optarg);
260                         break;
261                 case 'e':
262                         extensions = 0;
263                         break;
264                 case 'g':
265                         global = 1;
266                         break;
267                 case 'H':
268                         header_name = strdup(optarg);
269                         /* Fall through */
270                 case 'h':
271                         create_header = 1;
272                         break;
273                 case 'I':
274                         add_include_path(optarg);
275                         break;
276                 case 'l':
277                         {
278                                 int lan;
279                                 lan = strtol(optarg, NULL, 0);
280                                 currentlanguage = new_language(PRIMARYLANGID(lan), SUBLANGID(lan));
281                         }
282                         break;
283                 case 'L':
284                         leave_case = 1;
285                         break;
286                 case 'n':
287                         create_s = 0;
288                         break;
289                 case 'o':
290                         output_name = strdup(optarg);
291                         break;
292                 case 'p':
293 #ifdef NEED_UNDERSCORE_PREFIX
294                         prefix = (char *)xmalloc(strlen(optarg)+2);
295                         prefix[0] = '_';
296                         strcpy(prefix+1, optarg);
297 #else
298                         prefix = xstrdup(optarg);
299 #endif
300                         break;
301                 case 'r':
302                         create_res = 1;
303                         break;
304                 case 's':
305                         create_dir = 1;
306                         break;
307                 case 'T':
308                         indirect_only = 1;
309                         /* Fall through */
310                 case 't':
311                         indirect = 1;
312                         break;
313                 case 'V':
314                         printf(version_string);
315                         exit(0);
316                         break;
317                 case 'w':
318                         if(!strcmp(optarg, "16"))
319                                 win32 = 0;
320                         else if(!strcmp(optarg, "32"))
321                                 win32 = 1;
322                         else
323                                 lose++;
324                         break;
325                 case 'W':
326                         pedantic = 1;
327                         break;
328                 default:
329                         lose++;
330                         break;
331                 }
332         }
333
334         if(lose)
335         {
336                 fprintf(stderr, usage);
337                 return 1;
338         }
339
340         /* Check the command line options for invalid combinations */
341         if(win32)
342         {
343                 if(!extensions)
344                 {
345                         warning("Option -e ignored with 32bit compile\n");
346                         extensions = 1;
347                 }
348         }
349
350         if(create_res)
351         {
352                 if(constant)
353                 {
354                         warning("Option -c ignored with compile to .res\n");
355                         constant = 0;
356                 }
357
358                 if(create_header)
359                 {
360                         warning("Option -[h|H] ignored with compile to .res\n");
361                         create_header = 0;
362                 }
363
364                 if(indirect)
365                 {
366                         warning("Option -l ignored with compile to .res\n");
367                         indirect = 0;
368                 }
369
370                 if(indirect_only)
371                 {
372                         warning("Option -L ignored with compile to .res\n");
373                         indirect_only = 0;
374                 }
375
376                 if(global)
377                 {
378                         warning("Option -g ignored with compile to .res\n");
379                         global = 0;
380                 }
381
382                 if(create_dir)
383                 {
384                         error("Option -r and -s cannot be used together\n");
385                 }
386
387                 if(binary)
388                 {
389                         error("Option -r and -b cannot be used together\n");
390                 }
391         }
392
393         /* Set alignment power */
394         a = alignment;
395         for(alignment_pwr = 0; alignment_pwr < 10 && a > 1; alignment_pwr++)
396         {
397                 a >>= 1;
398         }
399         if(a != 1)
400         {
401                 error("Alignment must be between 1 and 1024");
402         }
403         if((1 << alignment_pwr) != alignment)
404         {
405                 error("Alignment must be a power of 2");
406         }
407
408         /* Kill io buffering when some kind of debuglevel is enabled */
409         if(debuglevel)
410         {
411                 setbuf(stdout,0);
412                 setbuf(stderr,0);
413         }
414
415         yydebug = debuglevel & DEBUGLEVEL_TRACE ? 1 : 0;
416
417         /* Set the default defined stuff */
418         add_cmdline_define("RC_INVOKED=1");
419         add_cmdline_define("__WRC__=1");
420         if(win32)
421         {
422                 add_cmdline_define("__WIN32__=1");
423                 add_cmdline_define("__FLAT__=1");
424         }
425
426         /* Check if the user set a language, else set default */
427         if(!currentlanguage)
428                 currentlanguage = new_language(0, 0);
429
430         /* Check for input file on command-line */
431         if(optind < argc)
432         {
433                 input_name = argv[optind];
434                 yyin = fopen(input_name, "rb");
435                 if(!yyin)
436                 {
437                         error("Could not open %s\n", input_name);
438                 }
439         }
440         else
441         {
442                 yyin = stdin;
443         }
444
445         if(binary && !input_name)
446         {
447                 error("Binary mode requires .res file as input");
448         }
449
450         if(!output_name)
451         {
452                 output_name = dup_basename(input_name, binary ? ".res" : ".rc");
453                 strcat(output_name, create_res ? ".res" : ".s");
454         }
455
456         if(!header_name && !create_res)
457         {
458                 header_name = dup_basename(input_name, binary ? ".res" : ".rc");
459                 strcat(header_name, ".h");
460         }
461
462         if(!binary)
463         {
464                 /* Go from .rc to .res or .s */
465                 chat("Starting parse");
466                 ret = yyparse();
467
468                 if(input_name)
469                         fclose(yyin);
470
471                 if(ret)
472                 {
473                         /* Error during parse */
474                         exit(1);
475                 }
476
477                 if(debuglevel & DEBUGLEVEL_DUMP)
478                         dump_resources(resource_top);
479
480                 /* Convert the internal lists to binary data */
481                 resources2res(resource_top);
482
483                 if(create_res)
484                 {
485                         chat("Writing .res-file");
486                         write_resfile(output_name, resource_top);
487                 }
488                 else
489                 {
490                         if(create_s)
491                         {
492                                 chat("Writing .s-file");
493                                 write_s_file(output_name, resource_top);
494                         }
495                         if(create_header)
496                         {
497                                 chat("Writing .h-file");
498                                 write_h_file(header_name, resource_top);
499                         }
500                 }
501
502         }
503         else
504         {
505                 /* Go from .res to .s */
506                 chat("Reading .res-file");
507                 resource_top = read_resfile(input_name);
508                 if(create_s)
509                 {
510                         chat("Writing .s-file");
511                         write_s_file(output_name, resource_top);
512                 }
513                 if(create_header)
514                 {
515                         chat("Writing .h-file");
516                         write_h_file(header_name, resource_top);
517                 }
518         }
519
520         return 0;
521 }
522
523
524
525