source: trunk/tools/wrc/wrc.c@ 21929

Last change on this file since 21929 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
Line 
1/*
2 *
3 * Copyright Martin von Loewis, 1994
4 * Copyrignt 1998 Bertho A. Stultiens (BS)
5 *
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.
9 *
10 * 08-Jun-1998 BS - Added -A option to generate autoregister code
11 * for winelib operation.
12 *
13 * 21-May-1998 BS - Removed the CPP option. Its internal now.
14 * - Added implementations for defines and includes
15 * on the commandline.
16 *
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.
22 *
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.
26 *
27 * 17-Apr-1998 BS - Added many new command-line options but took care
28 * that it would not break old scripts (sigh).
29 *
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..
33 *
34 */
35
36#include "config.h"
37
38#include <stdio.h>
39#include <stdlib.h>
40#ifndef __IBMC__
41#include <unistd.h>
42#endif
43#include <string.h>
44#include <assert.h>
45#include <ctype.h>
46#include <signal.h>
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
58static char usage[] =
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 "
65#ifdef WORDS_BIGENDIAN
66 "big"
67#else
68 "little"
69#endif
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"
84 " -M Use MASM syntax for the generated .s file instead of GAS\n"
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 ;
110
111char version_string[] = "Wine Resource Compiler Version " WRC_FULLVERSION "\n"
112 "Copyright 1998-2000 Bertho A. Stultiens\n"
113 " 1994 Martin von Loewis\n";
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/*
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
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
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
245/*
246 * Set when MASM syntax is requested (-M option)
247 */
248int masm_mode = 0;
249
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 */
254
255int line_number = 1; /* The current line */
256int char_number = 1; /* The current char pos within the line */
257
258char *cmdline; /* The entire commandline */
259time_t now; /* The time of start of wrc */
260
261resource_t *resource_top; /* The top of the parsed resources */
262
263#ifndef __GNUC__
264int getopt(int argc, char *const *argv, const char *optstring);
265#endif
266
267static void rm_tempfile(void);
268static void segvhandler(int sig);
269
270int main(int argc,char *argv[])
271{
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;
280
281 signal(SIGSEGV, segvhandler);
282
283 now = time(NULL);
284
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 }
299
300 while((optc = getopt(argc, argv, "a:AbB:cC:d:D:eEghH:I:l:LmMnNo:p:rstTVw:W")) != EOF)
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;
376 case 'M':
377 masm_mode = 1;
378 break;
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':
389#ifdef NEED_UNDERSCORE_PREFIX
390 prefix = (char *)xmalloc(strlen(optarg)+2);
391 prefix[0] = '_';
392 strcpy(prefix+1, optarg);
393#else
394 prefix = xstrdup(optarg);
395#endif
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 }
429
430 if(lose)
431 {
432 fprintf(stderr, usage);
433 return 1;
434 }
435
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 }
445
446 if(create_res)
447 {
448 if(constant)
449 {
450 warning("Option -c ignored with compile to .res\n");
451 constant = 0;
452 }
453
454 if(create_header)
455 {
456 warning("Option -[h|H] ignored with compile to .res\n");
457 create_header = 0;
458 }
459
460 if(indirect)
461 {
462 warning("Option -l ignored with compile to .res\n");
463 indirect = 0;
464 }
465
466 if(indirect_only)
467 {
468 warning("Option -L ignored with compile to .res\n");
469 indirect_only = 0;
470 }
471
472 if(global)
473 {
474 warning("Option -g ignored with compile to .res\n");
475 global = 0;
476 }
477
478 if(create_dir)
479 {
480 error("Option -r and -s cannot be used together\n");
481 }
482
483 if(binary)
484 {
485 error("Option -r and -b cannot be used together\n");
486 }
487 }
488
489 if(byteorder != WRC_BO_NATIVE)
490 {
491 if(binary)
492 error("Forced byteordering not supported for binary resources\n");
493 }
494
495 if(preprocess_only)
496 {
497 if(constant)
498 {
499 warning("Option -c ignored with preprocess only\n");
500 constant = 0;
501 }
502
503 if(create_header)
504 {
505 warning("Option -[h|H] ignored with preprocess only\n");
506 create_header = 0;
507 }
508
509 if(indirect)
510 {
511 warning("Option -l ignored with preprocess only\n");
512 indirect = 0;
513 }
514
515 if(indirect_only)
516 {
517 error("Option -E and -L cannot be used together\n");
518 }
519
520 if(global)
521 {
522 warning("Option -g ignored with preprocess only\n");
523 global = 0;
524 }
525
526 if(create_dir)
527 {
528 warning("Option -s ignored with preprocess only\n");
529 create_dir = 0;
530 }
531
532 if(binary)
533 {
534 error("Option -E and -b cannot be used together\n");
535 }
536
537 if(no_preprocess)
538 {
539 error("Option -E and -N cannot be used together\n");
540 }
541 }
542
543#if !defined(HAVE_WINE_CONSTRUCTOR)
544 if(auto_register)
545 {
546 warning("Autoregister code non-operable (HAVE_WINE_CONSTRUCTOR not defined)");
547 auto_register = 0;
548 }
549#endif
550
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 }
565
566 /* Kill io buffering when some kind of debuglevel is enabled */
567 if(debuglevel)
568 {
569 setbuf(stdout,0);
570 setbuf(stderr,0);
571 }
572
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;
577
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));
583
584 add_cmdline_define("RC_INVOKED=1");
585
586 if(win32)
587 {
588 add_cmdline_define("__WIN32__=1");
589 add_cmdline_define("__FLAT__=1");
590 }
591
592 add_special_define("__FILE__");
593 add_special_define("__LINE__");
594 add_special_define("__DATE__");
595 add_special_define("__TIME__");
596
597 /* Check if the user set a language, else set default */
598 if(!currentlanguage)
599 currentlanguage = new_language(0, 0);
600
601 /* Check for input file on command-line */
602 if(optind < argc)
603 {
604 input_name = argv[optind];
605 }
606
607 if(binary && !input_name)
608 {
609 error("Binary mode requires .res file as input\n");
610 }
611
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 }
618
619 if(!header_name && !create_res)
620 {
621 header_name = dup_basename(input_name, binary ? ".res" : ".rc");
622 strcat(header_name, ".h");
623 }
624
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 */
633
634 chat("Starting preprocess");
635
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 {
647 temp_name = xtempnam(NULL, NULL);
648 if(!(ppout = fopen(temp_name, "wb")))
649 error("Could not create a temp-file\n");
650
651 atexit(rm_tempfile);
652 }
653
654 real_name = input_name; /* Because it gets overwritten */
655
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 }
663
664 fprintf(ppout, "# 1 \"%s\" 1\n", input_name ? input_name : "");
665
666 ret = ppparse();
667
668 input_name = real_name;
669
670 if(input_name)
671 fclose(ppin);
672
673 fclose(ppout);
674
675 input_name = temp_name;
676
677 if(ret)
678 exit(1); /* Error during preprocess */
679
680 if(preprocess_only)
681 exit(0);
682 }
683
684 if(!binary)
685 {
686 /* Go from .rc to .res or .s */
687 chat("Starting parse");
688
689 if(!(yyin = fopen(input_name, "rb")))
690 error("Could not open %s for input\n", input_name);
691
692 ret = yyparse();
693
694 if(input_name)
695 fclose(yyin);
696
697 if(ret)
698 {
699 /* Error during parse */
700 exit(1);
701 }
702
703 if(debuglevel & DEBUGLEVEL_DUMP)
704 dump_resources(resource_top);
705
706 /* Convert the internal lists to binary data */
707 resources2res(resource_top);
708
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 }
727
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 }
745
746 return 0;
747}
748
749
750static void rm_tempfile(void)
751{
752 if(temp_name)
753 unlink(temp_name);
754}
755
756static void segvhandler(int sig)
757{
758 fprintf(stderr, "\n%s:%d: Oops, segment violation\n", input_name, line_number);
759 fflush(stdout);
760 fflush(stderr);
761 abort();
762}
763
764
765
Note: See TracBrowser for help on using the repository browser.