Upload Tizen:Base source
[external/binutils.git] / binutils / windmc.c
1 /* windmc.c -- a program to compile Windows message files.
2    Copyright 2007, 2008, 2009, 2010
3    Free Software Foundation, Inc.
4    Written by Kai Tietz, Onevision.
5
6    This file is part of GNU Binutils.
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
21    02110-1301, USA.  */
22
23
24 /* This program can read and comile Windows message format.
25
26    It is based on information taken from the following sources:
27
28    * Microsoft documentation.
29
30    * The wmc program, written by Bertho A. Stultiens (BS). */
31
32 #include "sysdep.h"
33 #include <assert.h>
34 #include <time.h>
35 #include "bfd.h"
36 #include "getopt.h"
37 #include "bucomm.h"
38 #include "libiberty.h"
39 #include "safe-ctype.h"
40 #include "obstack.h"
41
42 #include "windmc.h"
43 #include "windint.h"
44
45 /* Defines a message compiler element item with length and offset
46    information.  */
47 typedef struct mc_msg_item
48 {
49   rc_uint_type res_len;
50   rc_uint_type res_off;
51   struct bin_messagetable_item *res;
52 } mc_msg_item;
53
54 int target_is_bigendian = 0;
55 const char *def_target_arch;
56
57 /* Globals and static variable definitions. */
58
59 /* bfd global helper struct variable.  */
60 static struct
61 {
62   bfd *abfd;
63   asection *sec;
64 } mc_bfd;
65
66 /* Memory list.  */
67 mc_node *mc_nodes = NULL;
68 static mc_node_lang **mc_nodes_lang = NULL;
69 static int mc_nodes_lang_count = 0;
70 static mc_keyword **mc_severity_codes = NULL;
71 static int mc_severity_codes_count = 0;
72 static mc_keyword **mc_facility_codes = NULL;
73 static int mc_facility_codes_count = 0;
74
75 /* When we are building a resource tree, we allocate everything onto
76    an obstack, so that we can free it all at once if we want.  */
77 #define obstack_chunk_alloc xmalloc
78 #define obstack_chunk_free free
79
80 /* The resource building obstack.  */
81 static struct obstack res_obstack;
82
83 /* Flag variables.  */
84 /* Set by -C. Set the default code page to be used for input text file.  */
85 static rc_uint_type mcset_codepage_in = 0;
86
87 /* Set by -O. Set the default code page to be used for output text files.  */
88 static rc_uint_type mcset_codepage_out = 0;
89
90 /* Set by -b. .BIN filename should have .mc filename_ included for uniqueness.  */
91 static int mcset_prefix_bin = 0;
92
93 /* The base name of the .mc file.  */
94 static const char *mcset_mc_basename = "unknown";
95
96 /* Set by -e <ext>. Specify the extension for the header file.  */
97 static const char *mcset_header_ext = ".h";
98
99 /* Set by -h <path>. Gives the path of where to create the C include file.  */
100 static const char *mcset_header_dir = "./";
101
102 /* Set by -r <path>. Gives the path of where to create the RC include file
103    and the binary message resource files it includes. */
104 static const char *mcset_rc_dir = "./";
105
106 /* Modified by -a & -u. By -u input file is unicode, by -a is ASCII (default).  */
107 static int mcset_text_in_is_unicode = 0;
108
109 /* Modified by -A & -U. By -U bin file is unicode (default), by -A is ASCII.  */
110 static int mcset_bin_out_is_unicode = 1;
111
112 /* Set by -c. Sets the Customer bit in all the message ID's.  */
113 int mcset_custom_bit = 0;
114
115 /* Set by -o. Generate OLE2 header file. Use HRESULT definition instead of
116    status code definition.  */
117 static int mcset_use_hresult = 0;
118
119 /* Set by -m <msglen>. Generate a warning if the size of any message exceeds
120    maxmsglen characters.  */
121 rc_uint_type mcset_max_message_length = 0;
122
123 /* Set by -d. Sets message values in header to decimal initially.  */
124 int mcset_out_values_are_decimal = 0;
125
126 /* Set by -n. terminates all strings with null's in the message tables.  */
127 static int mcset_automatic_null_termination = 0;
128
129 /* The type used for message id output in header.  */
130 unichar *mcset_msg_id_typedef = NULL;
131
132 /* Set by -x path. Geberated debug C file for mapping ID's to text.  */
133 static const char *mcset_dbg_dir = NULL;
134
135 /* getopt long name definitions.  */
136 static const struct option long_options[] =
137 {
138   {"binprefix", no_argument, 0, 'b'},
139   {"target", required_argument, 0, 'F'},
140   {"extension", required_argument, 0, 'e'},
141   {"headerdir", required_argument, 0, 'h'},
142   {"rcdir", required_argument, 0, 'r'},
143   {"verbose", no_argument, 0, 'v'},
144   {"codepage_in", required_argument, 0, 'C'},
145   {"codepage_out", required_argument, 0, 'O'},
146   {"maxlength", required_argument, 0, 'm'},
147   {"ascii_in", no_argument, 0, 'a'},
148   {"ascii_out", no_argument, 0, 'A'},
149   {"unicode_in", no_argument, 0, 'u'},
150   {"unicode_out", no_argument, 0, 'U'},
151   {"customflag", no_argument, 0, 'c'},
152   {"decimal_values", no_argument, 0, 'd'},
153   {"hresult_use", no_argument, 0, 'o'},
154   {"nullterminate", no_argument, 0, 'n'},
155   {"xdbg", required_argument, 0, 'x'},
156   {"version", no_argument, 0, 'V'},
157   {"help", no_argument, 0, 'H'},
158   {0, no_argument, 0, 0}
159 };
160
161
162 /* Initialize the resource building obstack.  */
163 static void
164 res_init (void)
165 {
166   obstack_init (&res_obstack);
167 }
168
169 /* Allocate space on the resource building obstack.  */
170 void *
171 res_alloc (rc_uint_type bytes)
172 {
173   return obstack_alloc (&res_obstack, (size_t) bytes);
174 }
175
176 static FILE *
177 mc_create_path_text_file (const char *path, const char *ext)
178 {
179   FILE *ret;
180   size_t len = 1;
181   char *hsz;
182
183   len += (path != NULL ? strlen (path) : 0);
184   len += strlen (mcset_mc_basename);
185   len += (ext != NULL ? strlen (ext) : 0);
186   hsz = xmalloc (len);
187   sprintf (hsz, "%s%s%s", (path != NULL ? path : ""), mcset_mc_basename,
188     (ext != NULL ? ext : ""));
189   if ((ret = fopen (hsz, "wb")) == NULL)
190     fatal (_("can't create %s file `%s' for output.\n"), (ext ? ext : "text"), hsz);
191   free (hsz);
192   return ret;
193 }
194
195 static void
196 usage (FILE *stream, int status)
197 {
198   fprintf (stream, _("Usage: %s [option(s)] [input-file]\n"),
199            program_name);
200   fprintf (stream, _(" The options are:\n\
201   -a --ascii_in                Read input file as ASCII file\n\
202   -A --ascii_out               Write binary messages as ASCII\n\
203   -b --binprefix               .bin filename is prefixed by .mc filename_ for uniqueness.\n\
204   -c --customflag              Set custom flags for messages\n\
205   -C --codepage_in=<val>       Set codepage when reading mc text file\n\
206   -d --decimal_values          Print values to text files decimal\n\
207   -e --extension=<extension>   Set header extension used on export header file\n\
208   -F --target <target>         Specify output target for endianess.\n\
209   -h --headerdir=<directory>   Set the export directory for headers\n\
210   -u --unicode_in              Read input file as UTF16 file\n\
211   -U --unicode_out             Write binary messages as UFT16\n\
212   -m --maxlength=<val>         Set the maximal allowed message length\n\
213   -n --nullterminate           Automatic add a zero termination to strings\n\
214   -o --hresult_use             Use HRESULT definition instead of status code definition\n\
215   -O --codepage_out=<val>      Set codepage used for writing text file\n\
216   -r --rcdir=<directory>       Set the export directory for rc files\n\
217   -x --xdbg=<directory>        Where to create the .dbg C include file\n\
218                                that maps message ID's to their symbolic name.\n\
219 "));
220   fprintf (stream, _("\
221   -H --help                    Print this help message\n\
222   -v --verbose                 Verbose - tells you what it's doing\n\
223   -V --version                 Print version information\n"));
224
225   list_supported_targets (program_name, stream);
226
227   if (REPORT_BUGS_TO[0] && status == 0)
228     fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
229
230   exit (status);
231 }
232
233 static void
234 set_endianess (bfd *abfd, const char *target)
235 {
236   const bfd_target *target_vec;
237
238   def_target_arch = NULL;
239   target_vec = bfd_get_target_info (target, abfd, &target_is_bigendian, NULL,
240                                    &def_target_arch);
241   if (! target_vec)
242     fatal ("Can't detect target endianess and architecture.");
243   if (! def_target_arch)
244     fatal ("Can't detect architecture.");
245 }
246
247 static int
248 probe_codepage (rc_uint_type *cp, int *is_uni, const char *pswitch, int defmode)
249 {
250   if (*is_uni == -1)
251     {
252       if (*cp != CP_UTF16)
253         *is_uni = defmode;
254       else
255         *is_uni = 1;
256     }
257   if (*is_uni)
258     {
259       if (*cp != 0 && *cp != CP_UTF16)
260         {
261           fprintf (stderr, _("%s: warning: "), program_name);
262           fprintf (stderr, _("A codepage was specified switch `%s' and UTF16.\n"), pswitch);
263           fprintf (stderr, _("\tcodepage settings are ignored.\n"));
264         }
265       *cp = CP_UTF16;
266       return 1;
267     }
268   if (*cp == CP_UTF16)
269     {
270       *is_uni = 1;
271       return 1;
272     }
273   if (*cp == 0)
274     *cp = 1252;
275   if (! unicode_is_valid_codepage (*cp))
276         fatal ("Code page 0x%x is unknown.", (unsigned int) *cp);
277   *is_uni = 0;
278   return 1;
279 }
280
281 mc_node *
282 mc_add_node (void)
283 {
284   mc_node *ret;
285
286   ret = res_alloc (sizeof (mc_node));
287   memset (ret, 0, sizeof (mc_node));
288   if (! mc_nodes)
289     mc_nodes = ret;
290   else
291     {
292       mc_node *h = mc_nodes;
293
294       while (h->next != NULL)
295         h = h->next;
296       h->next = ret;
297     }
298   return ret;
299 }
300
301 mc_node_lang *
302 mc_add_node_lang (mc_node *root, const mc_keyword *lang, rc_uint_type vid)
303 {
304   mc_node_lang *ret, *h, *p;
305
306   if (! lang || ! root)
307     fatal (_("try to add a ill language."));
308   ret = res_alloc (sizeof (mc_node_lang));
309   memset (ret, 0, sizeof (mc_node_lang));
310   ret->lang = lang;
311   ret->vid = vid;
312   if ((h = root->sub) == NULL)
313     root->sub = ret;
314   else
315     {
316       p = NULL;
317       while (h != NULL)
318         {
319           if (h->lang->nval > lang->nval)
320             break;
321           if (h->lang->nval == lang->nval)
322             {
323               if (h->vid > vid)
324                 break;
325               if (h->vid == vid)
326                 fatal ("double defined message id %ld.\n", (long) vid);
327             }
328           h = (p = h)->next;
329         }
330       ret->next = h;
331       if (! p)
332         root->sub = ret;
333       else
334         p->next = ret;
335     }
336   return ret;
337 }
338
339 static char *
340 convert_unicode_to_ACP (const unichar *usz)
341 {
342   char *s;
343   rc_uint_type l;
344
345   if (! usz)
346     return NULL;
347   codepage_from_unicode (&l, usz, &s, mcset_codepage_out);
348   if (! s)
349     fatal ("unicode string not mappable to ASCII codepage 0x%lx.\n",
350            (unsigned long) mcset_codepage_out);
351   return s;
352 }
353
354 static void
355 write_dbg_define (FILE *fp, const unichar *sym_name, const unichar *typecast)
356 {
357   char *sym;
358
359   if (!sym_name || sym_name[0] == 0)
360     return;
361   sym = convert_unicode_to_ACP (sym_name);
362   fprintf (fp, "  {(");
363   if (typecast)
364     unicode_print (fp, typecast, unichar_len (typecast));
365   else
366     fprintf (fp, "DWORD");
367   fprintf (fp, ") %s, \"%s\" },\n", sym, sym);
368 }
369
370 static void
371 write_header_define (FILE *fp, const unichar *sym_name, rc_uint_type vid, const unichar *typecast, mc_node_lang *nl)
372 {
373   char *sym;
374   char *tdef = NULL;
375
376   if (!sym_name || sym_name[0] == 0)
377     {
378       if (nl != NULL)
379         {
380           if (mcset_out_values_are_decimal)
381             fprintf (fp, "//\n// MessageId: 0x%lu\n//\n", (unsigned long) vid);
382           else
383             fprintf (fp, "//\n// MessageId: 0x%lx\n//\n", (unsigned long) vid);
384         }
385       return;
386     }
387   sym = convert_unicode_to_ACP (sym_name);
388   if (typecast && typecast[0] != 0)
389     tdef = convert_unicode_to_ACP (typecast);
390   fprintf (fp, "//\n// MessageId: %s\n//\n", sym);
391   if (! mcset_out_values_are_decimal)
392     fprintf (fp, "#define %s %s%s%s 0x%lx\n\n", sym,
393       (tdef ? "(" : ""), (tdef ? tdef : ""), (tdef ? ")" : ""),
394     (unsigned long) vid);
395   else
396     fprintf (fp, "#define %s %s%s%s 0x%lu\n\n", sym,
397       (tdef ? "(" : ""), (tdef ? tdef : ""), (tdef ? ")" : ""),
398     (unsigned long) vid);
399 }
400
401 static int
402 sort_mc_node_lang (const void *l, const void *r)
403 {
404   const mc_node_lang *l1 = *((const mc_node_lang **)l);
405   const mc_node_lang *r1 = *((const mc_node_lang **)r);
406
407   if (l == r)
408     return 0;
409   if (l1->lang != r1->lang)
410     {
411       if (l1->lang->nval < r1->lang->nval)
412         return -1;
413       return 1;
414     }
415   if (l1->vid == r1->vid)
416     return 0;
417   if (l1->vid < r1->vid)
418     return -1;
419   return 1;
420 }
421
422 static int
423 sort_keyword_by_nval (const void *l, const void *r)
424 {
425   const mc_keyword *l1 = *((const mc_keyword **)l);
426   const mc_keyword *r1 = *((const mc_keyword **)r);
427   rc_uint_type len1, len2;
428   int e;
429
430   if (l == r)
431     return 0;
432   if (l1->nval != r1->nval)
433     {
434       if (l1->nval < r1->nval)
435         return -1;
436       return 1;
437     }
438   len1 = unichar_len (l1->usz);
439   len2 = unichar_len (r1->usz);
440   if (len1 <= len2)
441     e = memcmp (l1->usz, r1->usz, sizeof (unichar) * len1);
442   else
443     e = memcmp (l1->usz, r1->usz, sizeof (unichar) * len2);
444   if (e)
445     return e;
446   if (len1 < len2)
447     return -1;
448   else if (len1 > len2)
449     return 1;
450   return 0;
451 }
452
453 static void
454 do_sorts (void)
455 {
456   mc_node *h;
457   mc_node_lang *n;
458   const mc_keyword *k;
459   int i;
460
461   /* Sort message by their language and id ascending.  */
462   mc_nodes_lang_count = 0;
463
464   h = mc_nodes;
465   while (h != NULL)
466     {
467       n = h->sub;
468       while (n != NULL)
469         {
470           mc_nodes_lang_count +=1;
471           n = n->next;
472         }
473       h = h->next;
474     }
475
476   if (mc_nodes_lang_count != 0)
477     {
478       h = mc_nodes;
479       i = 0;
480       mc_nodes_lang = xmalloc (sizeof (mc_node_lang *) * mc_nodes_lang_count);
481
482       while (h != NULL)
483         {
484           n = h->sub;
485           while (n != NULL)
486             {
487               mc_nodes_lang[i++] = n;
488               n = n->next;
489             }
490           h = h->next;
491         }
492       qsort (mc_nodes_lang, (size_t) mc_nodes_lang_count, sizeof (mc_node_lang *), sort_mc_node_lang);
493     }
494   /* Sort facility code definitions by there id ascending.  */
495   i = 0;
496   while ((k = enum_facility (i)) != NULL)
497     ++i;
498   mc_facility_codes_count = i;
499   if (i != 0)
500     {
501       mc_facility_codes = xmalloc (sizeof (mc_keyword *) * i);
502       i = 0;
503       while ((k = enum_facility (i)) != NULL)
504         mc_facility_codes[i++] = (mc_keyword *) k;
505       qsort (mc_facility_codes, (size_t) mc_facility_codes_count, sizeof (mc_keyword *), sort_keyword_by_nval);
506     }
507
508   /* Sort severity code definitions by there id ascending.  */
509   i = 0;
510   while ((k = enum_severity (i)) != NULL)
511     ++i;
512   mc_severity_codes_count = i;
513   if (i != 0)
514     {
515       mc_severity_codes = xmalloc (sizeof (mc_keyword *) * i);
516       i = 0;
517       while ((k = enum_severity (i)) != NULL)
518         mc_severity_codes[i++] = (mc_keyword *) k;
519       qsort (mc_severity_codes, (size_t) mc_severity_codes_count, sizeof (mc_keyword *), sort_keyword_by_nval);
520     }
521 }
522
523 static int
524 mc_get_block_count (mc_node_lang **nl, int elems)
525 {
526   rc_uint_type exid;
527   int i, ret;
528
529   if (! nl)
530     return 0;
531   i = 0;
532   ret = 0;
533   while (i < elems)
534     {
535       ret++;
536       exid = nl[i++]->vid;
537       while (i < elems && nl[i]->vid == exid + 1)
538         exid = nl[i++]->vid;
539     }
540   return ret;
541 }
542
543 static bfd *
544 windmc_open_as_binary (const char *filename)
545 {
546   bfd *abfd;
547
548   abfd = bfd_openw (filename, "binary");
549   if (! abfd)
550     fatal ("can't open `%s' for output", filename);
551
552   return abfd;
553 }
554
555 static void
556 target_put_16 (void *p, rc_uint_type value)
557 {
558   assert (!! p);
559
560   if (target_is_bigendian)
561     bfd_putb16 (value, p);
562   else
563     bfd_putl16 (value, p);
564 }
565
566 static void
567 target_put_32 (void *p, rc_uint_type value)
568 {
569   assert (!! p);
570
571   if (target_is_bigendian)
572     bfd_putb32 (value, p);
573   else
574     bfd_putl32 (value, p);
575 }
576
577 static struct bin_messagetable_item *
578 mc_generate_bin_item (mc_node_lang *n, rc_uint_type *res_len)
579 {
580   struct bin_messagetable_item *ret = NULL;
581   rc_uint_type len;
582
583   *res_len = 0;
584   if (mcset_bin_out_is_unicode == 1)
585     {
586       unichar *ht = n->message;
587       rc_uint_type txt_len;
588
589       txt_len = unichar_len (n->message);
590       if (mcset_automatic_null_termination && txt_len != 0)
591         {
592           while (txt_len > 0 && ht[txt_len - 1] > 0 && ht[txt_len - 1] < 0x20)
593             ht[--txt_len] = 0;
594         }
595       txt_len *= sizeof (unichar);
596       len = BIN_MESSAGETABLE_ITEM_SIZE + txt_len + sizeof (unichar);
597       ret = res_alloc ((len + 3) & ~3);
598       memset (ret, 0, (len + 3) & ~3);
599       target_put_16 (ret->length, (len + 3) & ~3);
600       target_put_16 (ret->flags, MESSAGE_RESOURCE_UNICODE);
601       txt_len = 0;
602       while (*ht != 0)
603         {
604           target_put_16 (ret->data + txt_len, *ht++);
605           txt_len += 2;
606         }
607     }
608   else
609     {
610       rc_uint_type txt_len, l;
611       char *cvt_txt;
612
613       codepage_from_unicode( &l, n->message, &cvt_txt, n->lang->lang_info.wincp);
614       if (! cvt_txt)
615         fatal ("Failed to convert message to language codepage.\n");
616       txt_len = strlen (cvt_txt);
617       if (mcset_automatic_null_termination && txt_len > 0)
618         {
619           while (txt_len > 0 && cvt_txt[txt_len - 1] > 0 && cvt_txt[txt_len - 1] < 0x20)
620             cvt_txt[--txt_len] = 0;
621         }
622       len = BIN_MESSAGETABLE_ITEM_SIZE + txt_len + 1;
623       ret = res_alloc ((len + 3) & ~3);
624       memset (ret, 0, (len + 3) & ~3);
625       target_put_16 (ret->length, (len + 3) & ~3);
626       target_put_16 (ret->flags, 0);
627       strcpy ((char *) ret->data, cvt_txt);
628     }
629   *res_len = (len + 3) & ~3;
630   return ret;
631 }
632
633 static void
634 mc_write_blocks (struct bin_messagetable *mtbl, mc_node_lang **nl, mc_msg_item *ml, int elems)
635 {
636   int i, idx = 0;
637   rc_uint_type exid;
638
639   if (! nl)
640     return;
641   i = 0;
642   while (i < elems)
643     {
644       target_put_32 (mtbl->items[idx].lowid, nl[i]->vid);
645       target_put_32 (mtbl->items[idx].highid, nl[i]->vid);
646       target_put_32 (mtbl->items[idx].offset, ml[i].res_off);
647       exid = nl[i++]->vid;
648       while (i < elems && nl[i]->vid == exid + 1)
649         {
650           target_put_32 (mtbl->items[idx].highid, nl[i]->vid);
651           exid = nl[i++]->vid;
652         }
653       ++idx;
654     }
655 }
656
657 static void
658 set_windmc_bfd_content (const void *data, rc_uint_type off, rc_uint_type length)
659 {
660   if (! bfd_set_section_contents (mc_bfd.abfd, mc_bfd.sec, data, off, length))
661     bfd_fatal ("bfd_set_section_contents");
662 }
663
664 static void
665 windmc_write_bin (const char *filename, mc_node_lang **nl, int elems)
666 {
667   unsigned long sec_length = 1;
668   int block_count, i;
669   mc_msg_item *mi;
670   struct bin_messagetable *mtbl;
671   rc_uint_type dta_off, dta_start;
672
673   if (elems <= 0)
674     return;
675   mc_bfd.abfd = windmc_open_as_binary (filename);
676   mc_bfd.sec = bfd_make_section_with_flags (mc_bfd.abfd, ".data",
677                                             (SEC_HAS_CONTENTS | SEC_ALLOC
678                                              | SEC_LOAD | SEC_DATA));
679   if (mc_bfd.sec == NULL)
680     bfd_fatal ("bfd_make_section");
681   /* Requiring this is probably a bug in BFD.  */
682   mc_bfd.sec->output_section = mc_bfd.sec;
683
684   block_count = mc_get_block_count (nl, elems);
685
686   dta_off = (rc_uint_type) ((BIN_MESSAGETABLE_BLOCK_SIZE * block_count) + BIN_MESSAGETABLE_SIZE - 4);
687   dta_start = dta_off = (dta_off + 3) & ~3;
688   mi = xmalloc (sizeof (mc_msg_item) * elems);
689   mtbl = xmalloc (dta_start);
690
691   /* Clear header region.  */
692   memset (mtbl, 0, dta_start);
693   target_put_32 (mtbl->cblocks, block_count);
694   /* Prepare items section for output.  */
695   for (i = 0; i < elems; i++)
696     {
697       mi[i].res_off = dta_off;
698       mi[i].res = mc_generate_bin_item (nl[i], &mi[i].res_len);
699       dta_off += mi[i].res_len;
700     }
701   sec_length = (dta_off + 3) & ~3;
702   if (! bfd_set_section_size (mc_bfd.abfd, mc_bfd.sec, sec_length))
703     bfd_fatal ("bfd_set_section_size");
704   /* Make sure we write the complete block.  */
705   set_windmc_bfd_content ("\0", sec_length - 1, 1);
706
707   /* Write block information.  */
708   mc_write_blocks (mtbl, nl, mi, elems);
709
710   set_windmc_bfd_content (mtbl, 0, dta_start);
711
712   /* Write items.  */
713   for (i = 0; i < elems; i++)
714     set_windmc_bfd_content (mi[i].res, mi[i].res_off, mi[i].res_len);
715
716   free (mtbl);
717   free (mi);
718   bfd_close (mc_bfd.abfd);
719   mc_bfd.abfd = NULL;
720   mc_bfd.sec = NULL;
721 }
722
723 static void
724 write_bin (void)
725 {
726   mc_node_lang *n = NULL;
727   int i, c;
728
729   if (! mc_nodes_lang_count)
730     return;
731
732   i = 0;
733   while (i < mc_nodes_lang_count)
734     {
735       char *nd;
736       char *filename;
737
738       if (n && n->lang == mc_nodes_lang[i]->lang)
739         {
740           i++;
741           continue;
742         }
743       n = mc_nodes_lang[i];
744       c = i + 1;
745       while (c < mc_nodes_lang_count && n->lang == mc_nodes_lang[c]->lang)
746         c++;
747       nd = convert_unicode_to_ACP (n->lang->sval);
748
749       /* Prepare filename for binary output.  */
750       filename = xmalloc (strlen (nd) + 4 + 1 + strlen (mcset_mc_basename) + 1 + strlen (mcset_rc_dir));
751       strcpy (filename, mcset_rc_dir);
752       if (mcset_prefix_bin)
753         sprintf (filename + strlen (filename), "%s_", mcset_mc_basename);
754       strcat (filename, nd);
755       strcat (filename, ".bin");
756
757       /* Write message file.  */
758       windmc_write_bin (filename, &mc_nodes_lang[i], (c - i));
759
760       free (filename);
761       i = c;
762     }
763 }
764
765 static void
766 write_rc (FILE *fp)
767 {
768   mc_node_lang *n;
769   int i, l;
770
771   fprintf (fp,
772            "/* Do not edit this file manually.\n"
773            "   This file is autogenerated by windmc.  */\n\n");
774   if (! mc_nodes_lang_count)
775     return;
776   n = NULL;
777   i = 0;
778   for (l = 0; l < mc_nodes_lang_count; l++)
779     {
780       if (n && n->lang == mc_nodes_lang[l]->lang)
781         continue;
782       ++i;
783       n = mc_nodes_lang[l];
784       fprintf (fp, "\n// Country: %s\n// Language: %s\n#pragma code_page(%u)\n",
785                n->lang->lang_info.country, n->lang->lang_info.name,
786                (unsigned) n->lang->lang_info.wincp);
787       fprintf (fp, "LANGUAGE 0x%lx, 0x%lx\n",
788                (unsigned long) (n->lang->nval & 0x3ff),
789                (unsigned long) ((n->lang->nval & 0xffff) >> 10));
790       fprintf (fp, "1 MESSAGETABLE \"");
791       if (mcset_prefix_bin)
792         fprintf (fp, "%s_", mcset_mc_basename);
793       unicode_print (fp, n->lang->sval, unichar_len (n->lang->sval));
794       fprintf (fp, ".bin\"\n");
795     }
796 }
797
798 static void
799 write_dbg (FILE *fp)
800 {
801   mc_node *h;
802
803   fprintf (fp,
804     "/* Do not edit this file manually.\n"
805     "   This file is autogenerated by windmc.\n\n"
806     "   This file maps each message ID value in to a text string that contains\n"
807     "   the symbolic name used for it.  */\n\n");
808
809   fprintf (fp,
810     "struct %sSymbolicName\n"
811     "{\n  ", mcset_mc_basename);
812   if (mcset_msg_id_typedef)
813     unicode_print (fp, mcset_msg_id_typedef, unichar_len (mcset_msg_id_typedef));
814   else
815     fprintf (fp, "DWORD");
816   fprintf (fp,
817     " MessageId;\n"
818     "  char *SymbolicName;\n"
819     "} %sSymbolicNames[] =\n"
820     "{\n", mcset_mc_basename);
821   h = mc_nodes;
822   while (h != NULL)
823     {
824       if (h->symbol)
825         write_dbg_define (fp, h->symbol, mcset_msg_id_typedef);
826       h = h->next;
827     }
828   fprintf (fp, "  { (");
829   if (mcset_msg_id_typedef)
830     unicode_print (fp, mcset_msg_id_typedef, unichar_len (mcset_msg_id_typedef));
831   else
832     fprintf (fp, "DWORD");
833   fprintf (fp,
834     ") 0xffffffff, NULL }\n"
835     "};\n");
836 }
837
838 static void
839 write_header (FILE *fp)
840 {
841   char *s;
842   int i;
843   const mc_keyword *key;
844   mc_node *h;
845
846   fprintf (fp,
847     "/* Do not edit this file manually.\n"
848     "   This file is autogenerated by windmc.  */\n\n"
849     "//\n//  The values are 32 bit layed out as follows:\n//\n"
850     "//   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1\n"
851     "//   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0\n"
852     "//  +---+-+-+-----------------------+-------------------------------+\n"
853     "//  |Sev|C|R|     Facility          |               Code            |\n"
854     "//  +---+-+-+-----------------------+-------------------------------+\n//\n"
855     "//  where\n//\n"
856     "//      C    - is the Customer code flag\n//\n"
857     "//      R    - is a reserved bit\n//\n"
858     "//      Code - is the facility's status code\n//\n");
859
860   h = mc_nodes;
861
862   fprintf (fp, "//      Sev  - is the severity code\n//\n");
863   if (mc_severity_codes_count != 0)
864     {
865       for (i = 0; i < mc_severity_codes_count; i++)
866         {
867           key = mc_severity_codes[i];
868           fprintf (fp, "//           %s - %02lx\n", convert_unicode_to_ACP (key->usz),
869                    (unsigned long) key->nval);
870           if (key->sval && key->sval[0] != 0)
871             {
872               if (! mcset_out_values_are_decimal)
873                 fprintf (fp, "#define %s 0x%lx\n", convert_unicode_to_ACP (key->sval),
874                          (unsigned long) key->nval);
875               else
876                 fprintf (fp, "#define %s 0x%lu\n", convert_unicode_to_ACP (key->sval),
877                          (unsigned long) key->nval);
878             }
879         }
880       fprintf (fp, "//\n");
881     }
882   fprintf (fp, "//      Facility - is the facility code\n//\n");
883   if (mc_facility_codes_count != 0)
884     {
885       for (i = 0; i < mc_facility_codes_count; i++)
886         {
887           key = mc_facility_codes[i];
888           fprintf (fp, "//           %s - %04lx\n", convert_unicode_to_ACP (key->usz),
889                    (unsigned long) key->nval);
890           if (key->sval && key->sval[0] != 0)
891             {
892               if (! mcset_out_values_are_decimal)
893                 fprintf (fp, "#define %s 0x%lx\n", convert_unicode_to_ACP (key->sval),
894                          (unsigned long) key->nval);
895               else
896                 fprintf (fp, "#define %s 0x%lu\n", convert_unicode_to_ACP (key->sval),
897                          (unsigned long) key->nval);
898             }
899         }
900       fprintf (fp, "//\n");
901     }
902   fprintf (fp, "\n");
903   while (h != NULL)
904     {
905       if (h->user_text)
906         {
907           s = convert_unicode_to_ACP (h->user_text);
908           if (s)
909             fprintf (fp, "%s", s);
910         }
911       if (h->symbol)
912         write_header_define (fp, h->symbol, h->vid, mcset_msg_id_typedef, h->sub);
913       h = h->next;
914     }
915 }
916
917 static const char *
918 mc_unify_path (const char *path)
919 {
920   char *end;
921   char *hsz;
922
923   if (! path || *path == 0)
924     return "./";
925   hsz = xmalloc (strlen (path) + 2);
926   strcpy (hsz, path);
927   end = hsz + strlen (hsz);
928   if (hsz[-1] != '/' && hsz[-1] != '\\')
929     strcpy (end, "/");
930   while ((end = strchr (hsz, '\\')) != NULL)
931     *end = '/';
932   return hsz;
933 }
934
935 int main (int, char **);
936
937 int
938 main (int argc, char **argv)
939 {
940   FILE *h_fp;
941   int c;
942   char *target, *input_filename;
943   int verbose;
944
945 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
946   setlocale (LC_MESSAGES, "");
947 #endif
948 #if defined (HAVE_SETLOCALE)
949   setlocale (LC_CTYPE, "");
950 #endif
951   bindtextdomain (PACKAGE, LOCALEDIR);
952   textdomain (PACKAGE);
953
954   program_name = argv[0];
955   xmalloc_set_program_name (program_name);
956
957   expandargv (&argc, &argv);
958
959   bfd_init ();
960   set_default_bfd_target ();
961
962   target = NULL;
963   verbose = 0;
964   input_filename = NULL;
965
966   res_init ();
967
968   while ((c = getopt_long (argc, argv, "C:F:O:h:e:m:r:x:aAbcdHunoUvV", long_options,
969                            (int *) 0)) != EOF)
970     {
971       switch (c)
972         {
973         case 'b':
974           mcset_prefix_bin = 1;
975           break;
976         case 'e':
977           {
978             mcset_header_ext = optarg;
979             if (mcset_header_ext[0] != '.' && mcset_header_ext[0] != 0)
980               {
981                 char *hsz = xmalloc (strlen (mcset_header_ext) + 2);
982
983                 sprintf (hsz, ".%s", mcset_header_ext);
984                 mcset_header_ext = hsz;
985               }
986           }
987           break;
988         case 'h':
989           mcset_header_dir = mc_unify_path (optarg);
990           break;
991         case 'r':
992           mcset_rc_dir = mc_unify_path (optarg);
993           break;
994         case 'a':
995           mcset_text_in_is_unicode = 0;
996           break;
997         case 'x':
998           if (*optarg != 0)
999             mcset_dbg_dir = mc_unify_path (optarg);
1000           break;
1001         case 'A':
1002           mcset_bin_out_is_unicode = 0;
1003           break;
1004         case 'd':
1005           mcset_out_values_are_decimal = 1;
1006           break;
1007         case 'u':
1008           mcset_text_in_is_unicode = 1;
1009           break;
1010         case 'U':
1011           mcset_bin_out_is_unicode = 1;
1012           break;
1013         case 'c':
1014           mcset_custom_bit = 1;
1015           break;
1016         case 'n':
1017           mcset_automatic_null_termination = 1;
1018           break;
1019         case 'o':
1020           mcset_use_hresult = 1;
1021           fatal ("option -o is not implemented until yet.\n");
1022           break;
1023         case 'F':
1024           target = optarg;
1025           break;
1026         case 'v':
1027           verbose ++;
1028           break;
1029         case 'm':
1030           mcset_max_message_length = strtol (optarg, (char **) NULL, 10);
1031           break;
1032         case 'C':
1033           mcset_codepage_in = strtol (optarg, (char **) NULL, 10);
1034           break;
1035         case 'O':
1036           mcset_codepage_out = strtol (optarg, (char **) NULL, 10);
1037           break;
1038         case '?':
1039         case 'H':
1040           usage (stdout, 0);
1041           break;
1042         case 'V':
1043           print_version ("windmc");
1044           break;
1045
1046         default:
1047           usage (stderr, 1);
1048           break;
1049         }
1050     }
1051   if (input_filename == NULL && optind < argc)
1052     {
1053       input_filename = argv[optind];
1054       ++optind;
1055     }
1056
1057   set_endianess (NULL, target);
1058
1059   if (input_filename == NULL)
1060     {
1061       fprintf (stderr, "Error: No input file was specified.\n");
1062       usage (stderr, 1);
1063     }
1064   mc_set_inputfile (input_filename);
1065
1066   if (!probe_codepage (&mcset_codepage_in, &mcset_text_in_is_unicode, "codepage_in", 0))
1067     usage (stderr, 1);
1068   if (mcset_codepage_out == 0)
1069     mcset_codepage_out = 1252;
1070   if (! unicode_is_valid_codepage (mcset_codepage_out))
1071     fatal ("Code page 0x%x is unknown.", (unsigned int) mcset_codepage_out);
1072   if (mcset_codepage_out == CP_UTF16)
1073     fatal ("UTF16 is no valid text output code page.");
1074   if (verbose)
1075     {
1076       fprintf (stderr, "// Default target is %s and it is %s endian.\n",
1077         def_target_arch, (target_is_bigendian ? "big" : "little"));
1078       fprintf (stderr, "// Input codepage: 0x%x\n", (unsigned int) mcset_codepage_in);
1079       fprintf (stderr, "// Output codepage: 0x%x\n", (unsigned int) mcset_codepage_out);
1080     }
1081
1082   if (argc != optind)
1083     usage (stderr, 1);
1084
1085   /* Initialize mcset_mc_basename.  */
1086   {
1087     const char *bn, *bn2;
1088     char *hsz;
1089
1090     bn = strrchr (input_filename, '/');
1091     bn2 = strrchr (input_filename, '\\');
1092     if (! bn)
1093       bn = bn2;
1094     if (bn && bn2 && bn < bn2)
1095       bn = bn2;
1096     if (! bn)
1097       bn = input_filename;
1098     else
1099       bn++;
1100     mcset_mc_basename = hsz = xstrdup (bn);
1101
1102     /* Cut of right-hand extension.  */
1103     if ((hsz = strrchr (hsz, '.')) != NULL)
1104       *hsz = 0;
1105   }
1106
1107   /* Load the input file and do code page transformations to UTF16.  */
1108   {
1109     unichar *u;
1110     rc_uint_type ul;
1111     char *buff;
1112     bfd_size_type flen;
1113     FILE *fp = fopen (input_filename, "rb");
1114
1115     if (!fp)
1116       fatal (_("unable to open file `%s' for input.\n"), input_filename);
1117
1118     fseek (fp, 0, SEEK_END);
1119     flen = ftell (fp);
1120     fseek (fp, 0, SEEK_SET);
1121     buff = malloc (flen + 3);
1122     memset (buff, 0, flen + 3);
1123     if (fread (buff, 1, flen, fp) < flen)
1124       fatal (_("unable to read contents of %s"), input_filename);
1125     fclose (fp);
1126     if (mcset_text_in_is_unicode != 1)
1127       {
1128         unicode_from_codepage (&ul, &u, buff, mcset_codepage_in);
1129         if (! u)
1130           fatal ("Failed to convert input to UFT16\n");
1131         mc_set_content (u);
1132       }
1133     else
1134       {
1135         if ((flen & 1) != 0)
1136           fatal (_("input file does not seems to be UFT16.\n"));
1137         mc_set_content ((unichar *) buff);
1138       }
1139     free (buff);
1140   }
1141
1142   while (yyparse ())
1143     ;
1144
1145   do_sorts ();
1146
1147   h_fp = mc_create_path_text_file (mcset_header_dir, mcset_header_ext);
1148   write_header (h_fp);
1149   fclose (h_fp);
1150
1151   h_fp = mc_create_path_text_file (mcset_rc_dir, ".rc");
1152   write_rc (h_fp);
1153   fclose (h_fp);
1154
1155   if (mcset_dbg_dir != NULL)
1156     {
1157       h_fp = mc_create_path_text_file (mcset_dbg_dir, ".dbg");
1158       write_dbg (h_fp);
1159       fclose (h_fp);
1160     }
1161   write_bin ();
1162
1163   if (mc_nodes_lang)
1164     free (mc_nodes_lang);
1165   if (mc_severity_codes)
1166     free (mc_severity_codes);
1167   if (mc_facility_codes)
1168     free (mc_facility_codes);
1169
1170   xexit (0);
1171   return 0;
1172 }