source: trunk/tools/wrc/wrc.c

Last change on this file was 21929, checked in by dmik, 14 years ago

Replace tmpnam() with tempnam().

The former in EMX returns paths relative to the current
directory while it should be relative to %TMP%.

r21928 also does that.

File size: 19.4 KB
RevLine 
[882]1/*
2 *
3 * Copyright Martin von Loewis, 1994
4 * Copyrignt 1998 Bertho A. Stultiens (BS)
5 *
[6113]6 * 30-Apr-2000 BS - Integrated a new preprocessor (-E and -N)
7 * 20-Jun-1998 BS - Added -L option to prevent case conversion
8 * of embedded filenames.
[882]9 *
[6113]10 * 08-Jun-1998 BS - Added -A option to generate autoregister code
11 * for winelib operation.
[882]12 *
[6113]13 * 21-May-1998 BS - Removed the CPP option. Its internal now.
14 * - Added implementations for defines and includes
15 * on the commandline.
[882]16 *
[6113]17 * 30-Apr-1998 BS - The options now contain nearly the entire alphabet.
18 * Seems to be a sign for too much freedom. I implemeted
19 * most of them as a user choice possibility for things
20 * that I do not know what to put there by default.
21 * - -l and -L options are now known as -t and -T.
[882]22 *
[6113]23 * 23-Apr-1998 BS - Finally gave up on backward compatibility on the
24 * commandline (after a blessing from the newsgroup).
25 * So, I changed the lot.
[882]26 *
[6113]27 * 17-Apr-1998 BS - Added many new command-line options but took care
28 * that it would not break old scripts (sigh).
[882]29 *
[6113]30 * 16-Apr-1998 BS - There is not much left of the original source...
31 * I had to rewrite most of it because the parser
32 * changed completely with all the types etc..
[882]33 *
34 */
35
36#include "config.h"
37
38#include <stdio.h>
39#include <stdlib.h>
[6113]40#ifndef __IBMC__
[5523]41#include <unistd.h>
[6113]42#endif
[882]43#include <string.h>
44#include <assert.h>
45#include <ctype.h>
[5523]46#include <signal.h>
[882]47
48#include "wrc.h"
49#include "utils.h"
50#include "writeres.h"
51#include "readres.h"
52#include "dumpres.h"
53#include "genres.h"
54#include "newstruc.h"
55#include "preproc.h"
56#include "parser.h"
57
[5523]58static char usage[] =
[6113]59 "Usage: wrc [options...] [infile[.rc|.res]]\n"
60 " -a n Alignment of resource (win16 only, default is 4)\n"
61 " -A Auto register resources (only with gcc 2.7 and better)\n"
62 " -b Create an assembly array from a binary .res file\n"
63 " -B x Set output byte-order x={n[ative], l[ittle], b[ig]}\n"
64 " (win32 only; default is n[ative] which equals "
[5523]65#ifdef WORDS_BIGENDIAN
[6113]66 "big"
[5523]67#else
[6113]68 "little"
[5523]69#endif
[6113]70 "-endian)\n"
71 " -c Add 'const' prefix to C constants\n"
72 " -C cp Set the resource's codepage to cp (default is 0)\n"
73 " -d n Set debug level to 'n'\n"
74 " -D id[=val] Define preprocessor identifier id=val\n"
75 " -e Disable recognition of win32 keywords in 16bit compile\n"
76 " -E Preprocess only\n"
77 " -g Add symbols to the global c namespace\n"
78 " -h Also generate a .h file\n"
79 " -H file Same as -h but written to file\n"
80 " -I path Set include search dir to path (multiple -I allowed)\n"
81 " -l lan Set default language to lan (default is neutral {0, 0})\n"
82 " -L Leave case of embedded filenames as is\n"
83 " -m Do not remap numerical resource IDs\n"
[21589]84 " -M Use MASM syntax for the generated .s file instead of GAS\n"
[6113]85 " -n Do not generate .s file\n"
86 " -N Do not preprocess input\n"
87 " -o file Output to file (default is infile.[res|s|h]\n"
88 " -p prefix Give a prefix for the generated names\n"
89 " -r Create binary .res file (compile only)\n"
90 " -s Add structure with win32/16 (PE/NE) resource directory\n"
91 " -t Generate indirect loadable resource tables\n"
92 " -T Generate only indirect loadable resources tables\n"
93 " -V Print version end exit\n"
94 " -w 16|32 Select win16 or win32 output (default is win32)\n"
95 " -W Enable pedantic warnings\n"
96 "Input is taken from stdin if no sourcefile specified.\n"
97 "Debug level 'n' is a bitmask with following meaning:\n"
98 " * 0x01 Tell which resource is parsed (verbose mode)\n"
99 " * 0x02 Dump internal structures\n"
100 " * 0x04 Create a parser trace (yydebug=1)\n"
101 " * 0x08 Preprocessor messages\n"
102 " * 0x10 Preprocessor lex messages\n"
103 " * 0x20 Preprocessor yacc trace\n"
104 "The -o option only applies to the final destination file, which is\n"
105 "in case of normal compile a .s file. You must use the '-H header.h'\n"
106 "option to override the header-filename.\n"
107 "If no input filename is given and the output name is not overridden\n"
108 "with -o and/or -H, then the output is written to \"wrc.tab.[sh]\"\n"
109 ;
[882]110
111char version_string[] = "Wine Resource Compiler Version " WRC_FULLVERSION "\n"
[6113]112 "Copyright 1998-2000 Bertho A. Stultiens\n"
113 " 1994 Martin von Loewis\n";
[882]114
115/*
116 * Default prefix for resource names used in the C array.
117 * Option '-p name' sets it to 'name'
118 */
119#ifdef NEED_UNDERSCORE_PREFIX
120char *prefix = "__Resource";
121#else
122char *prefix = "_Resource";
123#endif
124
125/*
126 * Set if compiling in 32bit mode (default).
127 */
128int win32 = 1;
129
130/*
131 * Set when generated C variables should be prefixed with 'const'
132 */
133int constant = 0;
134
135/*
136 * Create a .res file from the source and exit (-r option).
137 */
138int create_res = 0;
139
140/*
[6113]141 * debuglevel == DEBUGLEVEL_NONE Don't bother
142 * debuglevel & DEBUGLEVEL_CHAT Say whats done
143 * debuglevel & DEBUGLEVEL_DUMP Dump internal structures
144 * debuglevel & DEBUGLEVEL_TRACE Create parser trace
145 * debuglevel & DEBUGLEVEL_PPMSG Preprocessor messages
146 * debuglevel & DEBUGLEVEL_PPLEX Preprocessor lex trace
147 * debuglevel & DEBUGLEVEL_PPTRACE Preprocessor yacc trace
[882]148 */
149int debuglevel = DEBUGLEVEL_NONE;
150
151/*
152 * Recognize win32 keywords if set (-w 32 enforces this),
153 * otherwise set with -e option.
154 */
155int extensions = 1;
156
157/*
158 * Set when creating C array from .res file (-b option).
159 */
160int binary = 0;
161
162/*
163 * Set when an additional C-header is to be created in compile (-h option).
164 */
165int create_header = 0;
166
167/*
168 * Set when the NE/PE resource directory should be dumped into
169 * the output file.
170 */
171int create_dir = 0;
172
173/*
174 * Set when all symbols should be added to the global namespace (-g option)
175 */
176int global = 0;
177
178/*
179 * Set when indirect loadable resource tables should be created (-t)
180 */
181int indirect = 0;
182
183/*
184 * Set when _only_ indirect loadable resource tables should be created (-T)
185 */
186int indirect_only = 0;
187
188/*
189 * NE segment resource aligment (-a option)
190 */
191int alignment = 4;
192int alignment_pwr;
193
194/*
195 * Cleared when the assembly file must be suppressed (-n option)
196 */
197int create_s = 1;
198
199/*
200 * Language setting for resources (-l option)
201 */
202language_t *currentlanguage = NULL;
203
204/*
205 * The codepage to write in win32 PE resource segment (-C option)
206 */
207DWORD codepage = 0;
208
209/*
210 * Set when extra warnings should be generated (-W option)
211 */
212int pedantic = 0;
213
214/*
215 * Set when autoregister code must be added to the output (-A option)
216 */
217int auto_register = 0;
218
219/*
220 * Set when the case of embedded filenames should not be converted
221 * to lower case (-L option)
222 */
223int leave_case = 0;
224
[5523]225/*
226 * The output byte-order of resources (set with -B)
227 */
228int byteorder = WRC_BO_NATIVE;
229
230/*
231 * Set when _only_ to run the preprocessor (-E option)
232 */
233int preprocess_only = 0;
234
235/*
236 * Set when _not_ to run the preprocessor (-N option)
237 */
238int no_preprocess = 0;
239
240/*
241 * Cleared when _not_ to remap resource types (-m option)
242 */
243int remap = 1;
244
[21589]245/*
246 * Set when MASM syntax is requested (-M option)
247 */
248int masm_mode = 0;
249
[6113]250char *output_name; /* The name given by the -o option */
251char *input_name; /* The name given on the command-line */
252char *header_name; /* The name given by the -H option */
253char *temp_name; /* Temporary file for preprocess pipe */
[882]254
[6113]255int line_number = 1; /* The current line */
256int char_number = 1; /* The current char pos within the line */
[5523]257
[6113]258char *cmdline; /* The entire commandline */
259time_t now; /* The time of start of wrc */
[882]260
[6113]261resource_t *resource_top; /* The top of the parsed resources */
[882]262
[21916]263#ifndef __GNUC__
264int getopt(int argc, char *const *argv, const char *optstring);
[5523]265#endif
[882]266
[5523]267static void rm_tempfile(void);
268static void segvhandler(int sig);
269
[882]270int main(int argc,char *argv[])
271{
[6113]272 extern char* optarg;
273 extern int optind;
274 int optc;
275 int lose = 0;
276 int ret;
277 int a;
278 int i;
279 int cmdlen;
[882]280
[6113]281 signal(SIGSEGV, segvhandler);
[5523]282
[6113]283 now = time(NULL);
[5523]284
[6113]285 /* First rebuild the commandline to put in destination */
286 /* Could be done through env[], but not all OS-es support it */
287 //cmdlen = 4; /* for "wrc " */ //hi guys! can't you count?
288 cmdlen = 5; /* for "wrc " */
289 for(i = 1; i < argc; i++)
290 cmdlen += strlen(argv[i]) + 1;
291 cmdline = (char *)xmalloc(cmdlen);
292 strcpy(cmdline, "wrc ");
293 for(i = 1; i < argc; i++)
294 {
295 strcat(cmdline, argv[i]);
296 if(i < argc-1)
297 strcat(cmdline, " ");
298 }
[882]299
[21589]300 while((optc = getopt(argc, argv, "a:AbB:cC:d:D:eEghH:I:l:LmMnNo:p:rstTVw:W")) != EOF)
[6113]301 {
302 switch(optc)
303 {
304 case 'a':
305 alignment = atoi(optarg);
306 break;
307 case 'A':
308 auto_register = 1;
309 break;
310 case 'b':
311 binary = 1;
312 break;
313 case 'B':
314 switch(optarg[0])
315 {
316 case 'n':
317 case 'N':
318 byteorder = WRC_BO_NATIVE;
319 break;
320 case 'l':
321 case 'L':
322 byteorder = WRC_BO_LITTLE;
323 break;
324 case 'b':
325 case 'B':
326 byteorder = WRC_BO_BIG;
327 break;
328 default:
329 fprintf(stderr, "Byteordering must be n[ative], l[ittle] or b[ig]\n");
330 lose++;
331 }
332 break;
333 case 'c':
334 constant = 1;
335 break;
336 case 'C':
337 codepage = strtol(optarg, NULL, 0);
338 break;
339 case 'd':
340 debuglevel = strtol(optarg, NULL, 0);
341 break;
342 case 'D':
343 add_cmdline_define(optarg);
344 break;
345 case 'e':
346 extensions = 0;
347 break;
348 case 'E':
349 preprocess_only = 1;
350 break;
351 case 'g':
352 global = 1;
353 break;
354 case 'H':
355 header_name = strdup(optarg);
356 /* Fall through */
357 case 'h':
358 create_header = 1;
359 break;
360 case 'I':
361 add_include_path(optarg);
362 break;
363 case 'l':
364 {
365 int lan;
366 lan = strtol(optarg, NULL, 0);
367 currentlanguage = new_language(PRIMARYLANGID(lan), SUBLANGID(lan));
368 }
369 break;
370 case 'L':
371 leave_case = 1;
372 break;
373 case 'm':
374 remap = 0;
375 break;
[21589]376 case 'M':
377 masm_mode = 1;
378 break;
[6113]379 case 'n':
380 create_s = 0;
381 break;
382 case 'N':
383 no_preprocess = 1;
384 break;
385 case 'o':
386 output_name = strdup(optarg);
387 break;
388 case 'p':
[882]389#ifdef NEED_UNDERSCORE_PREFIX
[6113]390 prefix = (char *)xmalloc(strlen(optarg)+2);
391 prefix[0] = '_';
392 strcpy(prefix+1, optarg);
[882]393#else
[6113]394 prefix = xstrdup(optarg);
[882]395#endif
[6113]396 break;
397 case 'r':
398 create_res = 1;
399 break;
400 case 's':
401 create_dir = 1;
402 break;
403 case 'T':
404 indirect_only = 1;
405 /* Fall through */
406 case 't':
407 indirect = 1;
408 break;
409 case 'V':
410 printf(version_string);
411 exit(0);
412 break;
413 case 'w':
414 if(!strcmp(optarg, "16"))
415 win32 = 0;
416 else if(!strcmp(optarg, "32"))
417 win32 = 1;
418 else
419 lose++;
420 break;
421 case 'W':
422 pedantic = 1;
423 break;
424 default:
425 lose++;
426 break;
427 }
428 }
[882]429
[6113]430 if(lose)
431 {
432 fprintf(stderr, usage);
433 return 1;
434 }
[882]435
[6113]436 /* Check the command line options for invalid combinations */
437 if(win32)
438 {
439 if(!extensions)
440 {
441 warning("Option -e ignored with 32bit compile\n");
442 extensions = 1;
443 }
444 }
[882]445
[6113]446 if(create_res)
447 {
448 if(constant)
449 {
450 warning("Option -c ignored with compile to .res\n");
451 constant = 0;
452 }
[882]453
[6113]454 if(create_header)
455 {
456 warning("Option -[h|H] ignored with compile to .res\n");
457 create_header = 0;
458 }
[882]459
[6113]460 if(indirect)
461 {
462 warning("Option -l ignored with compile to .res\n");
463 indirect = 0;
464 }
[882]465
[6113]466 if(indirect_only)
467 {
468 warning("Option -L ignored with compile to .res\n");
469 indirect_only = 0;
470 }
[882]471
[6113]472 if(global)
473 {
474 warning("Option -g ignored with compile to .res\n");
475 global = 0;
476 }
[882]477
[6113]478 if(create_dir)
479 {
480 error("Option -r and -s cannot be used together\n");
481 }
[882]482
[6113]483 if(binary)
484 {
485 error("Option -r and -b cannot be used together\n");
486 }
487 }
[882]488
[6113]489 if(byteorder != WRC_BO_NATIVE)
490 {
491 if(binary)
492 error("Forced byteordering not supported for binary resources\n");
493 }
[5523]494
[6113]495 if(preprocess_only)
496 {
497 if(constant)
498 {
499 warning("Option -c ignored with preprocess only\n");
500 constant = 0;
501 }
[5523]502
[6113]503 if(create_header)
504 {
505 warning("Option -[h|H] ignored with preprocess only\n");
506 create_header = 0;
507 }
[5523]508
[6113]509 if(indirect)
510 {
511 warning("Option -l ignored with preprocess only\n");
512 indirect = 0;
513 }
[5523]514
[6113]515 if(indirect_only)
516 {
517 error("Option -E and -L cannot be used together\n");
518 }
[5523]519
[6113]520 if(global)
521 {
522 warning("Option -g ignored with preprocess only\n");
523 global = 0;
524 }
[5523]525
[6113]526 if(create_dir)
527 {
528 warning("Option -s ignored with preprocess only\n");
529 create_dir = 0;
530 }
[5523]531
[6113]532 if(binary)
533 {
534 error("Option -E and -b cannot be used together\n");
535 }
[5523]536
[6113]537 if(no_preprocess)
538 {
539 error("Option -E and -N cannot be used together\n");
540 }
541 }
[5523]542
543#if !defined(HAVE_WINE_CONSTRUCTOR)
[6113]544 if(auto_register)
545 {
546 warning("Autoregister code non-operable (HAVE_WINE_CONSTRUCTOR not defined)");
547 auto_register = 0;
548 }
[5523]549#endif
550
[6113]551 /* Set alignment power */
552 a = alignment;
553 for(alignment_pwr = 0; alignment_pwr < 10 && a > 1; alignment_pwr++)
554 {
555 a >>= 1;
556 }
557 if(a != 1)
558 {
559 error("Alignment must be between 1 and 1024");
560 }
561 if((1 << alignment_pwr) != alignment)
562 {
563 error("Alignment must be a power of 2");
564 }
[882]565
[6113]566 /* Kill io buffering when some kind of debuglevel is enabled */
567 if(debuglevel)
568 {
569 setbuf(stdout,0);
570 setbuf(stderr,0);
571 }
[882]572
[6113]573 yydebug = debuglevel & DEBUGLEVEL_TRACE ? 1 : 0;
574 yy_flex_debug = debuglevel & DEBUGLEVEL_TRACE ? 1 : 0;
575 ppdebug = debuglevel & DEBUGLEVEL_PPTRACE ? 1 : 0;
576 pp_flex_debug = debuglevel & DEBUGLEVEL_PPLEX ? 1 : 0;
[882]577
[6113]578 /* Set the default defined stuff */
579 add_cmdline_define("__WRC__=" WRC_EXP_STRINGIZE(WRC_MAJOR_VERSION));
580 add_cmdline_define("__WRC_MINOR__=" WRC_EXP_STRINGIZE(WRC_MINOR_VERSION));
581 add_cmdline_define("__WRC_MICRO__=" WRC_EXP_STRINGIZE(WRC_MICRO_VERSION));
582 add_cmdline_define("__WRC_PATCH__=" WRC_EXP_STRINGIZE(WRC_MICRO_VERSION));
[5523]583
[6113]584 add_cmdline_define("RC_INVOKED=1");
[5523]585
[6113]586 if(win32)
587 {
588 add_cmdline_define("__WIN32__=1");
589 add_cmdline_define("__FLAT__=1");
590 }
[882]591
[6113]592 add_special_define("__FILE__");
593 add_special_define("__LINE__");
594 add_special_define("__DATE__");
595 add_special_define("__TIME__");
[5523]596
[6113]597 /* Check if the user set a language, else set default */
598 if(!currentlanguage)
599 currentlanguage = new_language(0, 0);
[882]600
[6113]601 /* Check for input file on command-line */
602 if(optind < argc)
603 {
604 input_name = argv[optind];
605 }
[882]606
[6113]607 if(binary && !input_name)
608 {
609 error("Binary mode requires .res file as input\n");
610 }
[882]611
[6113]612 /* Generate appropriate outfile names */
613 if(!output_name && !preprocess_only)
614 {
615 output_name = dup_basename(input_name, binary ? ".res" : ".rc");
616 strcat(output_name, create_res ? ".res" : ".s");
617 }
[882]618
[6113]619 if(!header_name && !create_res)
620 {
621 header_name = dup_basename(input_name, binary ? ".res" : ".rc");
622 strcat(header_name, ".h");
623 }
[882]624
[6113]625 /* Run the preprocessor on the input */
626 if(!no_preprocess && !binary)
627 {
628 char *real_name;
629 /*
630 * Preprocess the input to a temp-file, or stdout if
631 * no output was given.
632 */
[5523]633
[6113]634 chat("Starting preprocess");
[5523]635
[6113]636 if(preprocess_only && !output_name)
637 {
638 ppout = stdout;
639 }
640 else if(preprocess_only && output_name)
641 {
642 if(!(ppout = fopen(output_name, "wb")))
643 error("Could not open %s for writing\n", output_name);
644 }
645 else
646 {
[21929]647 temp_name = xtempnam(NULL, NULL);
[6113]648 if(!(ppout = fopen(temp_name, "wb")))
649 error("Could not create a temp-file\n");
[5523]650
[6113]651 atexit(rm_tempfile);
652 }
[5523]653
[6113]654 real_name = input_name; /* Because it gets overwritten */
[5523]655
[6113]656 if(!input_name)
657 ppin = stdin;
658 else
659 {
660 if(!(ppin = fopen(input_name, "rb")))
661 error("Could not open %s\n", input_name);
662 }
[5523]663
[6113]664 fprintf(ppout, "# 1 \"%s\" 1\n", input_name ? input_name : "");
[5523]665
[6113]666 ret = ppparse();
[5523]667
[6113]668 input_name = real_name;
[5523]669
[6113]670 if(input_name)
671 fclose(ppin);
[5523]672
[6113]673 fclose(ppout);
[5523]674
[6113]675 input_name = temp_name;
[5523]676
[6113]677 if(ret)
678 exit(1); /* Error during preprocess */
[5523]679
[6113]680 if(preprocess_only)
681 exit(0);
682 }
[5523]683
[6113]684 if(!binary)
685 {
686 /* Go from .rc to .res or .s */
687 chat("Starting parse");
[5523]688
[6113]689 if(!(yyin = fopen(input_name, "rb")))
690 error("Could not open %s for input\n", input_name);
[5523]691
[6113]692 ret = yyparse();
[882]693
[6113]694 if(input_name)
695 fclose(yyin);
[882]696
[6113]697 if(ret)
698 {
699 /* Error during parse */
700 exit(1);
701 }
[882]702
[6113]703 if(debuglevel & DEBUGLEVEL_DUMP)
704 dump_resources(resource_top);
[882]705
[6113]706 /* Convert the internal lists to binary data */
707 resources2res(resource_top);
[882]708
[6113]709 if(create_res)
710 {
711 chat("Writing .res-file");
712 write_resfile(output_name, resource_top);
713 }
714 else
715 {
716 if(create_s)
717 {
718 chat("Writing .s-file");
719 write_s_file(output_name, resource_top);
720 }
721 if(create_header)
722 {
723 chat("Writing .h-file");
724 write_h_file(header_name, resource_top);
725 }
726 }
[882]727
[6113]728 }
729 else
730 {
731 /* Go from .res to .s */
732 chat("Reading .res-file");
733 resource_top = read_resfile(input_name);
734 if(create_s)
735 {
736 chat("Writing .s-file");
737 write_s_file(output_name, resource_top);
738 }
739 if(create_header)
740 {
741 chat("Writing .h-file");
742 write_h_file(header_name, resource_top);
743 }
744 }
[882]745
[6113]746 return 0;
[882]747}
748
749
[5523]750static void rm_tempfile(void)
751{
[6113]752 if(temp_name)
753 unlink(temp_name);
[5523]754}
[882]755
[5523]756static void segvhandler(int sig)
757{
[6113]758 fprintf(stderr, "\n%s:%d: Oops, segment violation\n", input_name, line_number);
759 fflush(stdout);
760 fflush(stderr);
761 abort();
[5523]762}
[882]763
[6113]764
765
Note: See TracBrowser for help on using the repository browser.