shell32: Add support of KF_REDIRECT_COPY_CONTENTS flag to redirection.
[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, pot)\n"
52         "   -P dir      Directory where to find po files\n"
53         "   -u          Inputfile is in unicode\n"
54         "   -U          Output unicode messagetable(s)\n"
55         "   -v          Show supported codepages and languages\n"
56         "   -V          Print version end exit\n"
57         "   -W          Enable pedantic warnings\n"
58         "Input is taken from stdin if no inputfile is specified.\n"
59         "Byteorder of unicode input is based upon the first couple of\n"
60         "bytes read, which should be 0x0000..0x00ff.\n"
61         ;
62
63 static const char version_string[] =
64         "Wine Message Compiler version " PACKAGE_VERSION "\n"
65         "Copyright 2000 Bertho A. Stultiens\n"
66         ;
67
68 /*
69  * The output byte-order of resources (set with -B)
70  */
71 int byteorder = WMC_BO_NATIVE;
72
73 /*
74  * Custom bit (bit 29) in output values must be set (-c option)
75  */
76 int custombit = 0;
77
78 /*
79  * Output decimal values (-d option)
80  */
81 int decimal = 0;
82
83 /*
84  * Enable pedantic warnings; check arg references (-W option)
85  */
86 int pedantic = 0;
87
88 /*
89  * Unicode input (-u option)
90  */
91 int unicodein = 0;
92
93 /*
94  * Unicode output (-U option)
95  */
96 int unicodeout = 0;
97
98 /*
99  * Inline the messagetables (don't write *.bin files; -i option)
100  */
101 int rcinline = 0;
102
103 /*
104  * Debugging flag (-D option)
105  */
106 static int dodebug = 0;
107
108 static char *po_dir;
109
110 char *output_name = NULL;       /* The name given by the -o option */
111 char *input_name = NULL;        /* The name given on the command-line */
112 char *header_name = NULL;       /* The name given by the -H option */
113
114 int line_number = 1;            /* The current line */
115 int char_number = 1;            /* The current char pos within the line */
116
117 char *cmdline;                  /* The entire commandline */
118 time_t now;                     /* The time of start of wmc */
119
120 int mcy_debug;
121
122 FILE *yyin;
123
124 static enum
125 {
126     FORMAT_RC,
127     FORMAT_RES,
128     FORMAT_POT
129 } output_format;
130
131 int getopt (int argc, char *const *argv, const char *optstring);
132 static void segvhandler(int sig);
133
134 static void cleanup_files(void)
135 {
136     if (output_name) unlink( output_name );
137     if (header_name) unlink( header_name );
138 }
139
140 static void exit_on_signal( int sig )
141 {
142     exit(1);  /* this will call the atexit functions */
143 }
144
145 int main(int argc,char *argv[])
146 {
147         extern char* optarg;
148         extern int   optind;
149         int optc;
150         int lose = 0;
151         int ret;
152         int i;
153         int cmdlen;
154
155         atexit( cleanup_files );
156         signal(SIGSEGV, segvhandler);
157         signal( SIGTERM, exit_on_signal );
158         signal( SIGINT, exit_on_signal );
159 #ifdef SIGHUP
160         signal( SIGHUP, exit_on_signal );
161 #endif
162
163         now = time(NULL);
164
165         /* First rebuild the commandline to put in destination */
166         /* Could be done through env[], but not all OS-es support it */
167         cmdlen = 4; /* for "wmc " */
168         for(i = 1; i < argc; i++)
169                 cmdlen += strlen(argv[i]) + 1;
170         cmdline = xmalloc(cmdlen);
171         strcpy(cmdline, "wmc ");
172         for(i = 1; i < argc; i++)
173         {
174                 strcat(cmdline, argv[i]);
175                 if(i < argc-1)
176                         strcat(cmdline, " ");
177         }
178
179         while((optc = getopt(argc, argv, "B:cdDhH:io:O:P:uUvVW")) != EOF)
180         {
181                 switch(optc)
182                 {
183                 case 'B':
184                         switch(optarg[0])
185                         {
186                         case 'n':
187                         case 'N':
188                                 byteorder = WMC_BO_NATIVE;
189                                 break;
190                         case 'l':
191                         case 'L':
192                                 byteorder = WMC_BO_LITTLE;
193                                 break;
194                         case 'b':
195                         case 'B':
196                                 byteorder = WMC_BO_BIG;
197                                 break;
198                         default:
199                                 fprintf(stderr, "Byteordering must be n[ative], l[ittle] or b[ig]\n");
200                                 lose++;
201                         }
202                         break;
203                 case 'c':
204                         custombit = 1;
205                         break;
206                 case 'd':
207                         decimal = 1;
208                         break;
209                 case 'D':
210                         dodebug = 1;
211                         break;
212                 case 'h':
213                         printf("%s", usage);
214                         exit(0);
215                         /* No return */
216                 case 'H':
217                         header_name = xstrdup(optarg);
218                         break;
219                 case 'i':
220                         rcinline = 1;
221                         break;
222                 case 'o':
223                         output_name = xstrdup(optarg);
224                         break;
225                 case 'O':
226                         if (!strcmp( optarg, "rc" )) output_format = FORMAT_RC;
227                         else if (!strcmp( optarg, "res" )) output_format = FORMAT_RES;
228                         else if (!strcmp( optarg, "pot" )) output_format = FORMAT_POT;
229                         else
230                         {
231                             fprintf(stderr, "Output format must be rc or res\n" );
232                             lose++;
233                         }
234                         break;
235                 case 'P':
236                         po_dir = xstrdup( optarg );
237                         break;
238                 case 'u':
239                         unicodein = 1;
240                         break;
241                 case 'U':
242                         unicodeout = 1;
243                         break;
244                 case 'v':
245                         show_languages();
246                         show_codepages();
247                         exit(0);
248                         /* No return */
249                 case 'V':
250                         printf(version_string);
251                         exit(0);
252                         /* No return */
253                 case 'W':
254                         pedantic = 1;
255                         break;
256                 default:
257                         lose++;
258                         break;
259                 }
260         }
261
262         if(lose)
263         {
264                 fprintf(stderr, "%s", usage);
265                 return 1;
266         }
267
268         mcy_debug = dodebug;
269         if(dodebug)
270         {
271                 setbuf(stdout, NULL);
272                 setbuf(stderr, NULL);
273         }
274
275         /* Check for input file on command-line */
276         if(optind < argc)
277         {
278                 input_name = argv[optind];
279         }
280
281         /* Generate appropriate outfile names */
282         if(!output_name)
283         {
284                 output_name = dup_basename(input_name, ".mc");
285                 strcat(output_name, ".rc");
286         }
287
288         if(!header_name)
289         {
290                 header_name = dup_basename(input_name, ".mc");
291                 strcat(header_name, ".h");
292         }
293
294         if(input_name)
295         {
296                 if(!(yyin = fopen(input_name, "rb")))
297                         error("Could not open %s for input\n", input_name);
298         }
299         else
300                 yyin = stdin;
301
302         ret = mcy_parse();
303
304         if(input_name)
305                 fclose(yyin);
306
307         if(ret)
308         {
309                 /* Error during parse */
310                 exit(1);
311         }
312
313 #ifdef WORDS_BIGENDIAN
314         byte_swapped = (byteorder == WMC_BO_LITTLE);
315 #else
316         byte_swapped = (byteorder == WMC_BO_BIG);
317 #endif
318
319         switch (output_format)
320         {
321         case FORMAT_RC:
322             write_h_file(header_name);
323             write_rc_file(output_name);
324             if(!rcinline)
325                 write_bin_files();
326             break;
327         case FORMAT_RES:
328             if (po_dir) add_translations( po_dir );
329             write_res_file( output_name );
330             break;
331         case FORMAT_POT:
332             write_pot_file( output_name );
333             break;
334         }
335         output_name = NULL;
336         header_name = NULL;
337         return 0;
338 }
339
340 static void segvhandler(int sig)
341 {
342         fprintf(stderr, "\n%s:%d: Oops, segment violation\n", input_name, line_number);
343         fflush(stdout);
344         fflush(stderr);
345         abort();
346 }