wmc: Add support for creating resource and plain binary files.
[wine] / tools / wmc / wmc.c
1 /*
2  * Wine Message Compiler main program
3  *
4  * Copyright 2000 Bertho A. Stultiens (BS)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <signal.h>
28
29 #include "wmc.h"
30 #include "utils.h"
31 #include "lang.h"
32 #include "write.h"
33
34 static const char usage[] =
35         "Usage: wmc [options...] [inputfile.mc]\n"
36         "   -B x        Set output byte-order x={n[ative], l[ittle], b[ig]}\n"
37         "               (default is n[ative] which equals "
38 #ifdef WORDS_BIGENDIAN
39         "big"
40 #else
41         "little"
42 #endif
43         "-endian)\n"
44         "   -c          Set 'custom-bit' in values\n"
45         "   -d          Use decimal values in output\n"
46         "   -D          Set debug flag\n"
47         "   -h          This message\n"
48         "   -H file     Write headerfile to file (default is inputfile.h)\n"
49         "   -i          Inline messagetable(s)\n"
50         "   -o file     Output to file (default is inputfile.rc)\n"
51         "   -O fmt      Set output format (rc, res)\n"
52         "   -u          Inputfile is in unicode\n"
53         "   -U          Output unicode messagetable(s)\n"
54         "   -v          Show supported codepages and languages\n"
55         "   -V          Print version end exit\n"
56         "   -W          Enable pedantic warnings\n"
57         "Input is taken from stdin if no inputfile is specified.\n"
58         "Byteorder of unicode input is based upon the first couple of\n"
59         "bytes read, which should be 0x0000..0x00ff.\n"
60         ;
61
62 static const char version_string[] =
63         "Wine Message Compiler version " PACKAGE_VERSION "\n"
64         "Copyright 2000 Bertho A. Stultiens\n"
65         ;
66
67 /*
68  * The output byte-order of resources (set with -B)
69  */
70 int byteorder = WMC_BO_NATIVE;
71
72 /*
73  * Custom bit (bit 29) in output values must be set (-c option)
74  */
75 int custombit = 0;
76
77 /*
78  * Output decimal values (-d option)
79  */
80 int decimal = 0;
81
82 /*
83  * Enable pedantic warnings; check arg references (-W option)
84  */
85 int pedantic = 0;
86
87 /*
88  * Unicode input (-u option)
89  */
90 int unicodein = 0;
91
92 /*
93  * Unicode output (-U option)
94  */
95 int unicodeout = 0;
96
97 /*
98  * Inline the messagetables (don't write *.bin files; -i option)
99  */
100 int rcinline = 0;
101
102 /*
103  * Debugging flag (-D option)
104  */
105 static int dodebug = 0;
106
107 char *output_name = NULL;       /* The name given by the -o option */
108 char *input_name = NULL;        /* The name given on the command-line */
109 char *header_name = NULL;       /* The name given by the -H option */
110
111 int line_number = 1;            /* The current line */
112 int char_number = 1;            /* The current char pos within the line */
113
114 char *cmdline;                  /* The entire commandline */
115 time_t now;                     /* The time of start of wmc */
116
117 int mcy_debug;
118
119 FILE *yyin;
120
121 static enum
122 {
123     FORMAT_RC,
124     FORMAT_RES
125 } output_format;
126
127 int getopt (int argc, char *const *argv, const char *optstring);
128 static void segvhandler(int sig);
129
130 static void cleanup_files(void)
131 {
132     if (output_name) unlink( output_name );
133     if (header_name) unlink( header_name );
134 }
135
136 static void exit_on_signal( int sig )
137 {
138     exit(1);  /* this will call the atexit functions */
139 }
140
141 int main(int argc,char *argv[])
142 {
143         extern char* optarg;
144         extern int   optind;
145         int optc;
146         int lose = 0;
147         int ret;
148         int i;
149         int cmdlen;
150
151         atexit( cleanup_files );
152         signal(SIGSEGV, segvhandler);
153         signal( SIGTERM, exit_on_signal );
154         signal( SIGINT, exit_on_signal );
155 #ifdef SIGHUP
156         signal( SIGHUP, exit_on_signal );
157 #endif
158
159         now = time(NULL);
160
161         /* First rebuild the commandline to put in destination */
162         /* Could be done through env[], but not all OS-es support it */
163         cmdlen = 4; /* for "wmc " */
164         for(i = 1; i < argc; i++)
165                 cmdlen += strlen(argv[i]) + 1;
166         cmdline = xmalloc(cmdlen);
167         strcpy(cmdline, "wmc ");
168         for(i = 1; i < argc; i++)
169         {
170                 strcat(cmdline, argv[i]);
171                 if(i < argc-1)
172                         strcat(cmdline, " ");
173         }
174
175         while((optc = getopt(argc, argv, "B:cdDhH:io:O:p:uUvVW")) != EOF)
176         {
177                 switch(optc)
178                 {
179                 case 'B':
180                         switch(optarg[0])
181                         {
182                         case 'n':
183                         case 'N':
184                                 byteorder = WMC_BO_NATIVE;
185                                 break;
186                         case 'l':
187                         case 'L':
188                                 byteorder = WMC_BO_LITTLE;
189                                 break;
190                         case 'b':
191                         case 'B':
192                                 byteorder = WMC_BO_BIG;
193                                 break;
194                         default:
195                                 fprintf(stderr, "Byteordering must be n[ative], l[ittle] or b[ig]\n");
196                                 lose++;
197                         }
198                         break;
199                 case 'c':
200                         custombit = 1;
201                         break;
202                 case 'd':
203                         decimal = 1;
204                         break;
205                 case 'D':
206                         dodebug = 1;
207                         break;
208                 case 'h':
209                         printf("%s", usage);
210                         exit(0);
211                         /* No return */
212                 case 'H':
213                         header_name = xstrdup(optarg);
214                         break;
215                 case 'i':
216                         rcinline = 1;
217                         break;
218                 case 'o':
219                         output_name = xstrdup(optarg);
220                         break;
221                 case 'O':
222                         if (!strcmp( optarg, "rc" )) output_format = FORMAT_RC;
223                         else if (!strcmp( optarg, "res" )) output_format = FORMAT_RES;
224                         else
225                         {
226                             fprintf(stderr, "Output format must be rc or res\n" );
227                             lose++;
228                         }
229                         break;
230                 case 'u':
231                         unicodein = 1;
232                         break;
233                 case 'U':
234                         unicodeout = 1;
235                         break;
236                 case 'v':
237                         show_languages();
238                         show_codepages();
239                         exit(0);
240                         /* No return */
241                 case 'V':
242                         printf(version_string);
243                         exit(0);
244                         /* No return */
245                 case 'W':
246                         pedantic = 1;
247                         break;
248                 default:
249                         lose++;
250                         break;
251                 }
252         }
253
254         if(lose)
255         {
256                 fprintf(stderr, "%s", usage);
257                 return 1;
258         }
259
260         mcy_debug = dodebug;
261         if(dodebug)
262         {
263                 setbuf(stdout, NULL);
264                 setbuf(stderr, NULL);
265         }
266
267         /* Check for input file on command-line */
268         if(optind < argc)
269         {
270                 input_name = argv[optind];
271         }
272
273         /* Generate appropriate outfile names */
274         if(!output_name)
275         {
276                 output_name = dup_basename(input_name, ".mc");
277                 strcat(output_name, ".rc");
278         }
279
280         if(!header_name)
281         {
282                 header_name = dup_basename(input_name, ".mc");
283                 strcat(header_name, ".h");
284         }
285
286         if(input_name)
287         {
288                 if(!(yyin = fopen(input_name, "rb")))
289                         error("Could not open %s for input\n", input_name);
290         }
291         else
292                 yyin = stdin;
293
294         ret = mcy_parse();
295
296         if(input_name)
297                 fclose(yyin);
298
299         if(ret)
300         {
301                 /* Error during parse */
302                 exit(1);
303         }
304
305 #ifdef WORDS_BIGENDIAN
306         byte_swapped = (byteorder == WMC_BO_LITTLE);
307 #else
308         byte_swapped = (byteorder == WMC_BO_BIG);
309 #endif
310
311         switch (output_format)
312         {
313         case FORMAT_RC:
314             write_h_file(header_name);
315             write_rc_file(output_name);
316             if(!rcinline)
317                 write_bin_files();
318             break;
319         case FORMAT_RES:
320             write_res_file( output_name );
321             break;
322         }
323         output_name = NULL;
324         header_name = NULL;
325         return 0;
326 }
327
328 static void segvhandler(int sig)
329 {
330         fprintf(stderr, "\n%s:%d: Oops, segment violation\n", input_name, line_number);
331         fflush(stdout);
332         fflush(stderr);
333         abort();
334 }