wmc: Add support for generating a po template file.
[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         "   -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     FORMAT_POT
126 } output_format;
127
128 int getopt (int argc, char *const *argv, const char *optstring);
129 static void segvhandler(int sig);
130
131 static void cleanup_files(void)
132 {
133     if (output_name) unlink( output_name );
134     if (header_name) unlink( header_name );
135 }
136
137 static void exit_on_signal( int sig )
138 {
139     exit(1);  /* this will call the atexit functions */
140 }
141
142 int main(int argc,char *argv[])
143 {
144         extern char* optarg;
145         extern int   optind;
146         int optc;
147         int lose = 0;
148         int ret;
149         int i;
150         int cmdlen;
151
152         atexit( cleanup_files );
153         signal(SIGSEGV, segvhandler);
154         signal( SIGTERM, exit_on_signal );
155         signal( SIGINT, exit_on_signal );
156 #ifdef SIGHUP
157         signal( SIGHUP, exit_on_signal );
158 #endif
159
160         now = time(NULL);
161
162         /* First rebuild the commandline to put in destination */
163         /* Could be done through env[], but not all OS-es support it */
164         cmdlen = 4; /* for "wmc " */
165         for(i = 1; i < argc; i++)
166                 cmdlen += strlen(argv[i]) + 1;
167         cmdline = xmalloc(cmdlen);
168         strcpy(cmdline, "wmc ");
169         for(i = 1; i < argc; i++)
170         {
171                 strcat(cmdline, argv[i]);
172                 if(i < argc-1)
173                         strcat(cmdline, " ");
174         }
175
176         while((optc = getopt(argc, argv, "B:cdDhH:io:O:p:uUvVW")) != EOF)
177         {
178                 switch(optc)
179                 {
180                 case 'B':
181                         switch(optarg[0])
182                         {
183                         case 'n':
184                         case 'N':
185                                 byteorder = WMC_BO_NATIVE;
186                                 break;
187                         case 'l':
188                         case 'L':
189                                 byteorder = WMC_BO_LITTLE;
190                                 break;
191                         case 'b':
192                         case 'B':
193                                 byteorder = WMC_BO_BIG;
194                                 break;
195                         default:
196                                 fprintf(stderr, "Byteordering must be n[ative], l[ittle] or b[ig]\n");
197                                 lose++;
198                         }
199                         break;
200                 case 'c':
201                         custombit = 1;
202                         break;
203                 case 'd':
204                         decimal = 1;
205                         break;
206                 case 'D':
207                         dodebug = 1;
208                         break;
209                 case 'h':
210                         printf("%s", usage);
211                         exit(0);
212                         /* No return */
213                 case 'H':
214                         header_name = xstrdup(optarg);
215                         break;
216                 case 'i':
217                         rcinline = 1;
218                         break;
219                 case 'o':
220                         output_name = xstrdup(optarg);
221                         break;
222                 case 'O':
223                         if (!strcmp( optarg, "rc" )) output_format = FORMAT_RC;
224                         else if (!strcmp( optarg, "res" )) output_format = FORMAT_RES;
225                         else if (!strcmp( optarg, "pot" )) output_format = FORMAT_POT;
226                         else
227                         {
228                             fprintf(stderr, "Output format must be rc or res\n" );
229                             lose++;
230                         }
231                         break;
232                 case 'u':
233                         unicodein = 1;
234                         break;
235                 case 'U':
236                         unicodeout = 1;
237                         break;
238                 case 'v':
239                         show_languages();
240                         show_codepages();
241                         exit(0);
242                         /* No return */
243                 case 'V':
244                         printf(version_string);
245                         exit(0);
246                         /* No return */
247                 case 'W':
248                         pedantic = 1;
249                         break;
250                 default:
251                         lose++;
252                         break;
253                 }
254         }
255
256         if(lose)
257         {
258                 fprintf(stderr, "%s", usage);
259                 return 1;
260         }
261
262         mcy_debug = dodebug;
263         if(dodebug)
264         {
265                 setbuf(stdout, NULL);
266                 setbuf(stderr, NULL);
267         }
268
269         /* Check for input file on command-line */
270         if(optind < argc)
271         {
272                 input_name = argv[optind];
273         }
274
275         /* Generate appropriate outfile names */
276         if(!output_name)
277         {
278                 output_name = dup_basename(input_name, ".mc");
279                 strcat(output_name, ".rc");
280         }
281
282         if(!header_name)
283         {
284                 header_name = dup_basename(input_name, ".mc");
285                 strcat(header_name, ".h");
286         }
287
288         if(input_name)
289         {
290                 if(!(yyin = fopen(input_name, "rb")))
291                         error("Could not open %s for input\n", input_name);
292         }
293         else
294                 yyin = stdin;
295
296         ret = mcy_parse();
297
298         if(input_name)
299                 fclose(yyin);
300
301         if(ret)
302         {
303                 /* Error during parse */
304                 exit(1);
305         }
306
307 #ifdef WORDS_BIGENDIAN
308         byte_swapped = (byteorder == WMC_BO_LITTLE);
309 #else
310         byte_swapped = (byteorder == WMC_BO_BIG);
311 #endif
312
313         switch (output_format)
314         {
315         case FORMAT_RC:
316             write_h_file(header_name);
317             write_rc_file(output_name);
318             if(!rcinline)
319                 write_bin_files();
320             break;
321         case FORMAT_RES:
322             write_res_file( output_name );
323             break;
324         case FORMAT_POT:
325             write_pot_file( output_name );
326             break;
327         }
328         output_name = NULL;
329         header_name = NULL;
330         return 0;
331 }
332
333 static void segvhandler(int sig)
334 {
335         fprintf(stderr, "\n%s:%d: Oops, segment violation\n", input_name, line_number);
336         fflush(stdout);
337         fflush(stderr);
338         abort();
339 }