* obcopy.c (copy_object): New parameter `input_arch', architecture
[external/binutils.git] / binutils / windmc.c
1 /* windmc.c -- a program to compile Windows message files.
2    Copyright 2007, 2008, 2009
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_find_target (target, abfd);
240   if (! target_vec)
241     fatal ("Can't detect target endianess and architecture.");
242   target_is_bigendian = ((target_vec->byteorder == BFD_ENDIAN_BIG) ? 1 : 0);
243
244   {
245     const char *  tname = target_vec->name;
246     const char ** arches = bfd_arch_list ();
247
248     if (arches && tname)
249       {
250         const char ** arch = arches;
251
252         if (strchr (tname, '-') != NULL)
253           tname = strchr (tname, '-') + 1;
254
255         while (*arch != NULL)
256           {
257             const char *in_a = strstr (*arch, tname);
258             char end_ch = (in_a ? in_a[strlen (tname)] : 0);
259
260             if (in_a && (in_a == *arch || in_a[-1] == ':')
261                 && end_ch == 0)
262               {
263                 def_target_arch = *arch;
264                 break;
265               }
266             arch++;
267           }
268       }
269
270     free (arches);
271
272     if (! def_target_arch)
273       fatal ("Can't detect architecture.");
274   }
275 }
276
277 static int
278 probe_codepage (rc_uint_type *cp, int *is_uni, const char *pswitch, int defmode)
279 {
280   if (*is_uni == -1)
281     {
282       if (*cp != CP_UTF16)
283         *is_uni = defmode;
284       else
285         *is_uni = 1;
286     }
287   if (*is_uni)
288     {
289       if (*cp != 0 && *cp != CP_UTF16)
290         {
291           fprintf (stderr, _("%s: warning: "), program_name);
292           fprintf (stderr, _("A codepage was specified switch ,%s' and UTF16.\n"), pswitch);
293           fprintf (stderr, _("\tcodepage settings are ignored.\n"));
294         }
295       *cp = CP_UTF16;
296       return 1;
297     }
298   if (*cp == CP_UTF16)
299     {
300       *is_uni = 1;
301       return 1;
302     }
303   if (*cp == 0)
304     *cp = 1252;
305   if (! unicode_is_valid_codepage (*cp))
306         fatal ("Code page 0x%x is unknown.", (unsigned int) *cp);
307   *is_uni = 0;
308   return 1;
309 }
310
311 mc_node *
312 mc_add_node (void)
313 {
314   mc_node *ret;
315
316   ret = res_alloc (sizeof (mc_node));
317   memset (ret, 0, sizeof (mc_node));
318   if (! mc_nodes)
319     mc_nodes = ret;
320   else
321     {
322       mc_node *h = mc_nodes;
323
324       while (h->next != NULL)
325         h = h->next;
326       h->next = ret;
327     }
328   return ret;
329 }
330
331 mc_node_lang *
332 mc_add_node_lang (mc_node *root, const mc_keyword *lang, rc_uint_type vid)
333 {
334   mc_node_lang *ret, *h, *p;
335
336   if (! lang || ! root)
337     fatal (_("try to add a ill language."));
338   ret = res_alloc (sizeof (mc_node_lang));
339   memset (ret, 0, sizeof (mc_node_lang));
340   ret->lang = lang;
341   ret->vid = vid;
342   if ((h = root->sub) == NULL)
343     root->sub = ret;
344   else
345     {
346       p = NULL;
347       while (h != NULL)
348         {
349           if (h->lang->nval > lang->nval)
350             break;
351           if (h->lang->nval == lang->nval)
352             {
353               if (h->vid > vid)
354                 break;
355               if (h->vid == vid)
356                 fatal ("double defined message id %ld.\n", (long) vid);
357             }
358           h = (p = h)->next;
359         }
360       ret->next = h;
361       if (! p)
362         root->sub = ret;
363       else
364         p->next = ret;
365     }
366   return ret;
367 }
368
369 static char *
370 convert_unicode_to_ACP (const unichar *usz)
371 {
372   char *s;
373   rc_uint_type l;
374
375   if (! usz)
376     return NULL;
377   codepage_from_unicode (&l, usz, &s, mcset_codepage_out);
378   if (! s)
379     fatal ("unicode string not mappable to ASCII codepage 0x%lx.\n",
380            (unsigned long) mcset_codepage_out);
381   return s;
382 }
383
384 static void
385 write_dbg_define (FILE *fp, const unichar *sym_name, const unichar *typecast)
386 {
387   char *sym;
388
389   if (!sym_name || sym_name[0] == 0)
390     return;
391   sym = convert_unicode_to_ACP (sym_name);
392   fprintf (fp, "  {(");
393   if (typecast)
394     unicode_print (fp, typecast, unichar_len (typecast));
395   else
396     fprintf (fp, "DWORD");
397   fprintf (fp, ") %s, \"%s\" },\n", sym, sym);
398 }
399
400 static void
401 write_header_define (FILE *fp, const unichar *sym_name, rc_uint_type vid, const unichar *typecast, mc_node_lang *nl)
402 {
403   char *sym;
404   char *tdef = NULL;
405
406   if (!sym_name || sym_name[0] == 0)
407     {
408       if (nl != NULL)
409         {
410           if (mcset_out_values_are_decimal)
411             fprintf (fp, "//\n// MessageId: 0x%lu\n//\n", (unsigned long) vid);
412           else
413             fprintf (fp, "//\n// MessageId: 0x%lx\n//\n", (unsigned long) vid);
414         }
415       return;
416     }
417   sym = convert_unicode_to_ACP (sym_name);
418   if (typecast && typecast[0] != 0)
419     tdef = convert_unicode_to_ACP (typecast);
420   fprintf (fp, "//\n// MessageId: %s\n//\n", sym);
421   if (! mcset_out_values_are_decimal)
422     fprintf (fp, "#define %s %s%s%s 0x%lx\n\n", sym,
423       (tdef ? "(" : ""), (tdef ? tdef : ""), (tdef ? ")" : ""),
424     (unsigned long) vid);
425   else
426     fprintf (fp, "#define %s %s%s%s 0x%lu\n\n", sym,
427       (tdef ? "(" : ""), (tdef ? tdef : ""), (tdef ? ")" : ""),
428     (unsigned long) vid);
429 }
430
431 static int
432 sort_mc_node_lang (const void *l, const void *r)
433 {
434   const mc_node_lang *l1 = *((const mc_node_lang **)l);
435   const mc_node_lang *r1 = *((const mc_node_lang **)r);
436
437   if (l == r)
438     return 0;
439   if (l1->lang != r1->lang)
440     {
441       if (l1->lang->nval < r1->lang->nval)
442         return -1;
443       return 1;
444     }
445   if (l1->vid == r1->vid)
446     return 0;
447   if (l1->vid < r1->vid)
448     return -1;
449   return 1;
450 }
451
452 static int
453 sort_keyword_by_nval (const void *l, const void *r)
454 {
455   const mc_keyword *l1 = *((const mc_keyword **)l);
456   const mc_keyword *r1 = *((const mc_keyword **)r);
457   rc_uint_type len1, len2;
458   int e;
459
460   if (l == r)
461     return 0;
462   if (l1->nval != r1->nval)
463     {
464       if (l1->nval < r1->nval)
465         return -1;
466       return 1;
467     }
468   len1 = unichar_len (l1->usz);
469   len2 = unichar_len (r1->usz);
470   if (len1 <= len2)
471     e = memcmp (l1->usz, r1->usz, sizeof (unichar) * len1);
472   else
473     e = memcmp (l1->usz, r1->usz, sizeof (unichar) * len2);
474   if (e)
475     return e;
476   if (len1 < len2)
477     return -1;
478   else if (len1 > len2)
479     return 1;
480   return 0;
481 }
482
483 static void
484 do_sorts (void)
485 {
486   mc_node *h;
487   mc_node_lang *n;
488   const mc_keyword *k;
489   int i;
490
491   /* Sort message by their language and id ascending.  */
492   mc_nodes_lang_count = 0;
493
494   h = mc_nodes;
495   while (h != NULL)
496     {
497       n = h->sub;
498       while (n != NULL)
499         {
500           mc_nodes_lang_count +=1;
501           n = n->next;
502         }
503       h = h->next;
504     }
505
506   if (mc_nodes_lang_count != 0)
507     {
508       h = mc_nodes;
509       i = 0;
510       mc_nodes_lang = xmalloc (sizeof (mc_node_lang *) * mc_nodes_lang_count);
511
512       while (h != NULL)
513         {
514           n = h->sub;
515           while (n != NULL)
516             {
517               mc_nodes_lang[i++] = n;
518               n = n->next;
519             }
520           h = h->next;
521         }
522       qsort (mc_nodes_lang, (size_t) mc_nodes_lang_count, sizeof (mc_node_lang *), sort_mc_node_lang);
523     }
524   /* Sort facility code definitions by there id ascending.  */
525   i = 0;
526   while ((k = enum_facility (i)) != NULL)
527     ++i;
528   mc_facility_codes_count = i;
529   if (i != 0)
530     {
531       mc_facility_codes = xmalloc (sizeof (mc_keyword *) * i);
532       i = 0;
533       while ((k = enum_facility (i)) != NULL)
534         mc_facility_codes[i++] = (mc_keyword *) k;
535       qsort (mc_facility_codes, (size_t) mc_facility_codes_count, sizeof (mc_keyword *), sort_keyword_by_nval);
536     }
537
538   /* Sort severity code definitions by there id ascending.  */
539   i = 0;
540   while ((k = enum_severity (i)) != NULL)
541     ++i;
542   mc_severity_codes_count = i;
543   if (i != 0)
544     {
545       mc_severity_codes = xmalloc (sizeof (mc_keyword *) * i);
546       i = 0;
547       while ((k = enum_severity (i)) != NULL)
548         mc_severity_codes[i++] = (mc_keyword *) k;
549       qsort (mc_severity_codes, (size_t) mc_severity_codes_count, sizeof (mc_keyword *), sort_keyword_by_nval);
550     }
551 }
552
553 static int
554 mc_get_block_count (mc_node_lang **nl, int elems)
555 {
556   rc_uint_type exid;
557   int i, ret;
558
559   if (! nl)
560     return 0;
561   i = 0;
562   ret = 0;
563   while (i < elems)
564     {
565       ret++;
566       exid = nl[i++]->vid;
567       while (i < elems && nl[i]->vid == exid + 1)
568         exid = nl[i++]->vid;
569     }
570   return ret;
571 }
572
573 static bfd *
574 windmc_open_as_binary (const char *filename)
575 {
576   bfd *abfd;
577
578   abfd = bfd_openw (filename, "binary");
579   if (! abfd)
580     fatal ("can't open `%s' for output", filename);
581
582   return abfd;
583 }
584
585 static void
586 target_put_16 (void *p, rc_uint_type value)
587 {
588   assert (!! p);
589
590   if (target_is_bigendian)
591     bfd_putb16 (value, p);
592   else
593     bfd_putl16 (value, p);
594 }
595
596 static void
597 target_put_32 (void *p, rc_uint_type value)
598 {
599   assert (!! p);
600
601   if (target_is_bigendian)
602     bfd_putb32 (value, p);
603   else
604     bfd_putl32 (value, p);
605 }
606
607 static struct bin_messagetable_item *
608 mc_generate_bin_item (mc_node_lang *n, rc_uint_type *res_len)
609 {
610   struct bin_messagetable_item *ret = NULL;
611   rc_uint_type len;
612
613   *res_len = 0;
614   if (mcset_bin_out_is_unicode == 1)
615     {
616       unichar *ht = n->message;
617       rc_uint_type txt_len;
618
619       txt_len = unichar_len (n->message);
620       if (mcset_automatic_null_termination && txt_len != 0)
621         {
622           while (txt_len > 0 && ht[txt_len - 1] > 0 && ht[txt_len - 1] < 0x20)
623             ht[--txt_len] = 0;
624         }
625       txt_len *= sizeof (unichar);
626       len = BIN_MESSAGETABLE_ITEM_SIZE + txt_len + sizeof (unichar);
627       ret = res_alloc ((len + 3) & ~3);
628       memset (ret, 0, (len + 3) & ~3);
629       target_put_16 (ret->length, (len + 3) & ~3);
630       target_put_16 (ret->flags, MESSAGE_RESOURCE_UNICODE);
631       txt_len = 0;
632       while (*ht != 0)
633         {
634           target_put_16 (ret->data + txt_len, *ht++);
635           txt_len += 2;
636         }
637     }
638   else
639     {
640       rc_uint_type txt_len, l;
641       char *cvt_txt;
642
643       codepage_from_unicode( &l, n->message, &cvt_txt, n->lang->lang_info.wincp);
644       if (! cvt_txt)
645         fatal ("Failed to convert message to language codepage.\n");
646       txt_len = strlen (cvt_txt);
647       if (mcset_automatic_null_termination && txt_len > 0)
648         {
649           while (txt_len > 0 && cvt_txt[txt_len - 1] > 0 && cvt_txt[txt_len - 1] < 0x20)
650             cvt_txt[--txt_len] = 0;
651         }
652       len = BIN_MESSAGETABLE_ITEM_SIZE + txt_len + 1;
653       ret = res_alloc ((len + 3) & ~3);
654       memset (ret, 0, (len + 3) & ~3);
655       target_put_16 (ret->length, (len + 3) & ~3);
656       target_put_16 (ret->flags, 0);
657       strcpy ((char *) ret->data, cvt_txt);
658     }
659   *res_len = (len + 3) & ~3;
660   return ret;
661 }
662
663 static void
664 mc_write_blocks (struct bin_messagetable *mtbl, mc_node_lang **nl, mc_msg_item *ml, int elems)
665 {
666   int i, idx = 0;
667   rc_uint_type exid;
668
669   if (! nl)
670     return;
671   i = 0;
672   while (i < elems)
673     {
674       target_put_32 (mtbl->items[idx].lowid, nl[i]->vid);
675       target_put_32 (mtbl->items[idx].highid, nl[i]->vid);
676       target_put_32 (mtbl->items[idx].offset, ml[i].res_off);
677       exid = nl[i++]->vid;
678       while (i < elems && nl[i]->vid == exid + 1)
679         {
680           target_put_32 (mtbl->items[idx].highid, nl[i]->vid);
681           exid = nl[i++]->vid;
682         }
683       ++idx;
684     }
685 }
686
687 static void
688 set_windmc_bfd_content (const void *data, rc_uint_type off, rc_uint_type length)
689 {
690   if (! bfd_set_section_contents (mc_bfd.abfd, mc_bfd.sec, data, off, length))
691     bfd_fatal ("bfd_set_section_contents");
692 }
693
694 static void
695 windmc_write_bin (const char *filename, mc_node_lang **nl, int elems)
696 {
697   unsigned long sec_length = 1;
698   int block_count, i;
699   mc_msg_item *mi;
700   struct bin_messagetable *mtbl;
701   rc_uint_type dta_off, dta_start;
702
703   if (elems <= 0)
704     return;
705   mc_bfd.abfd = windmc_open_as_binary (filename);
706   mc_bfd.sec = bfd_make_section_with_flags (mc_bfd.abfd, ".data",
707                                             (SEC_HAS_CONTENTS | SEC_ALLOC
708                                              | SEC_LOAD | SEC_DATA));
709   if (mc_bfd.sec == NULL)
710     bfd_fatal ("bfd_make_section");
711   /* Requiring this is probably a bug in BFD.  */
712   mc_bfd.sec->output_section = mc_bfd.sec;
713
714   block_count = mc_get_block_count (nl, elems);
715
716   dta_off = (rc_uint_type) ((BIN_MESSAGETABLE_BLOCK_SIZE * block_count) + BIN_MESSAGETABLE_SIZE - 4);
717   dta_start = dta_off = (dta_off + 3) & ~3;
718   mi = xmalloc (sizeof (mc_msg_item) * elems);
719   mtbl = xmalloc (dta_start);
720
721   /* Clear header region.  */
722   memset (mtbl, 0, dta_start);
723   target_put_32 (mtbl->cblocks, block_count);
724   /* Prepare items section for output.  */
725   for (i = 0; i < elems; i++)
726     {
727       mi[i].res_off = dta_off;
728       mi[i].res = mc_generate_bin_item (nl[i], &mi[i].res_len);
729       dta_off += mi[i].res_len;
730     }
731   sec_length = (dta_off + 3) & ~3;
732   if (! bfd_set_section_size (mc_bfd.abfd, mc_bfd.sec, sec_length))
733     bfd_fatal ("bfd_set_section_size");
734   /* Make sure we write the complete block.  */
735   set_windmc_bfd_content ("\0", sec_length - 1, 1);
736
737   /* Write block information.  */
738   mc_write_blocks (mtbl, nl, mi, elems);
739
740   set_windmc_bfd_content (mtbl, 0, dta_start);
741
742   /* Write items.  */
743   for (i = 0; i < elems; i++)
744     set_windmc_bfd_content (mi[i].res, mi[i].res_off, mi[i].res_len);
745
746   free (mtbl);
747   free (mi);
748   bfd_close (mc_bfd.abfd);
749   mc_bfd.abfd = NULL;
750   mc_bfd.sec = NULL;
751 }
752
753 static void
754 write_bin (void)
755 {
756   mc_node_lang *n = NULL;
757   int i, c;
758
759   if (! mc_nodes_lang_count)
760     return;
761
762   i = 0;
763   while (i < mc_nodes_lang_count)
764     {
765       char *nd;
766       char *filename;
767
768       if (n && n->lang == mc_nodes_lang[i]->lang)
769         {
770           i++;
771           continue;
772         }
773       n = mc_nodes_lang[i];
774       c = i + 1;
775       while (c < mc_nodes_lang_count && n->lang == mc_nodes_lang[c]->lang)
776         c++;
777       nd = convert_unicode_to_ACP (n->lang->sval);
778
779       /* Prepare filename for binary output.  */
780       filename = xmalloc (strlen (nd) + 4 + 1 + strlen (mcset_mc_basename) + 1 + strlen (mcset_rc_dir));
781       strcpy (filename, mcset_rc_dir);
782       if (mcset_prefix_bin)
783         sprintf (filename + strlen (filename), "%s_", mcset_mc_basename);
784       strcat (filename, nd);
785       strcat (filename, ".bin");
786
787       /* Write message file.  */
788       windmc_write_bin (filename, &mc_nodes_lang[i], (c - i));
789
790       free (filename);
791       i = c;
792     }
793 }
794
795 static void
796 write_rc (FILE *fp)
797 {
798   mc_node_lang *n;
799   int i, l;
800
801   fprintf (fp,
802            "/* Do not edit this file manually.\n"
803            "   This file is autogenerated by windmc.  */\n\n");
804   if (! mc_nodes_lang_count)
805     return;
806   n = NULL;
807   i = 0;
808   for (l = 0; l < mc_nodes_lang_count; l++)
809     {
810       if (n && n->lang == mc_nodes_lang[l]->lang)
811         continue;
812       ++i;
813       n = mc_nodes_lang[l];
814       fprintf (fp, "\n// Country: %s\n// Language: %s\n#pragma code_page(%u)\n",
815                n->lang->lang_info.country, n->lang->lang_info.name,
816                (unsigned) n->lang->lang_info.wincp);
817       fprintf (fp, "LANGUAGE 0x%lx, 0x%lx\n",
818                (unsigned long) (n->lang->nval & 0x3ff),
819                (unsigned long) ((n->lang->nval & 0xffff) >> 10));
820       fprintf (fp, "1 MESSAGETABLE \"");
821       if (mcset_prefix_bin)
822         fprintf (fp, "%s_", mcset_mc_basename);
823       unicode_print (fp, n->lang->sval, unichar_len (n->lang->sval));
824       fprintf (fp, ".bin\"\n");
825     }
826 }
827
828 static void
829 write_dbg (FILE *fp)
830 {
831   mc_node *h;
832
833   fprintf (fp,
834     "/* Do not edit this file manually.\n"
835     "   This file is autogenerated by windmc.\n\n"
836     "   This file maps each message ID value in to a text string that contains\n"
837     "   the symbolic name used for it.  */\n\n");
838
839   fprintf (fp,
840     "struct %sSymbolicName\n"
841     "{\n  ", mcset_mc_basename);
842   if (mcset_msg_id_typedef)
843     unicode_print (fp, mcset_msg_id_typedef, unichar_len (mcset_msg_id_typedef));
844   else
845     fprintf (fp, "DWORD");
846   fprintf (fp,
847     " MessageId;\n"
848     "  char *SymbolicName;\n"
849     "} %sSymbolicNames[] =\n"
850     "{\n", mcset_mc_basename);
851   h = mc_nodes;
852   while (h != NULL)
853     {
854       if (h->symbol)
855         write_dbg_define (fp, h->symbol, mcset_msg_id_typedef);
856       h = h->next;
857     }
858   fprintf (fp, "  { (");
859   if (mcset_msg_id_typedef)
860     unicode_print (fp, mcset_msg_id_typedef, unichar_len (mcset_msg_id_typedef));
861   else
862     fprintf (fp, "DWORD");
863   fprintf (fp,
864     ") 0xffffffff, NULL }\n"
865     "};\n");
866 }
867
868 static void
869 write_header (FILE *fp)
870 {
871   char *s;
872   int i;
873   const mc_keyword *key;
874   mc_node *h;
875
876   fprintf (fp,
877     "/* Do not edit this file manually.\n"
878     "   This file is autogenerated by windmc.  */\n\n"
879     "//\n//  The values are 32 bit layed out as follows:\n//\n"
880     "//   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1\n"
881     "//   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"
882     "//  +---+-+-+-----------------------+-------------------------------+\n"
883     "//  |Sev|C|R|     Facility          |               Code            |\n"
884     "//  +---+-+-+-----------------------+-------------------------------+\n//\n"
885     "//  where\n//\n"
886     "//      C    - is the Customer code flag\n//\n"
887     "//      R    - is a reserved bit\n//\n"
888     "//      Code - is the facility's status code\n//\n");
889
890   h = mc_nodes;
891
892   fprintf (fp, "//      Sev  - is the severity code\n//\n");
893   if (mc_severity_codes_count != 0)
894     {
895       for (i = 0; i < mc_severity_codes_count; i++)
896         {
897           key = mc_severity_codes[i];
898           fprintf (fp, "//           %s - %02lx\n", convert_unicode_to_ACP (key->usz),
899                    (unsigned long) key->nval);
900           if (key->sval && key->sval[0] != 0)
901             {
902               if (! mcset_out_values_are_decimal)
903                 fprintf (fp, "#define %s 0x%lx\n", convert_unicode_to_ACP (key->sval),
904                          (unsigned long) key->nval);
905               else
906                 fprintf (fp, "#define %s 0x%lu\n", convert_unicode_to_ACP (key->sval),
907                          (unsigned long) key->nval);
908             }
909         }
910       fprintf (fp, "//\n");
911     }
912   fprintf (fp, "//      Facility - is the facility code\n//\n");
913   if (mc_facility_codes_count != 0)
914     {
915       for (i = 0; i < mc_facility_codes_count; i++)
916         {
917           key = mc_facility_codes[i];
918           fprintf (fp, "//           %s - %04lx\n", convert_unicode_to_ACP (key->usz),
919                    (unsigned long) key->nval);
920           if (key->sval && key->sval[0] != 0)
921             {
922               if (! mcset_out_values_are_decimal)
923                 fprintf (fp, "#define %s 0x%lx\n", convert_unicode_to_ACP (key->sval),
924                          (unsigned long) key->nval);
925               else
926                 fprintf (fp, "#define %s 0x%lu\n", convert_unicode_to_ACP (key->sval),
927                          (unsigned long) key->nval);
928             }
929         }
930       fprintf (fp, "//\n");
931     }
932   fprintf (fp, "\n");
933   while (h != NULL)
934     {
935       if (h->user_text)
936         {
937           s = convert_unicode_to_ACP (h->user_text);
938           if (s)
939             fprintf (fp, "%s", s);
940         }
941       if (h->symbol)
942         write_header_define (fp, h->symbol, h->vid, mcset_msg_id_typedef, h->sub);
943       h = h->next;
944     }
945 }
946
947 static const char *
948 mc_unify_path (const char *path)
949 {
950   char *end;
951   char *hsz;
952
953   if (! path || *path == 0)
954     return "./";
955   hsz = xmalloc (strlen (path) + 2);
956   strcpy (hsz, path);
957   end = hsz + strlen (hsz);
958   if (hsz[-1] != '/' && hsz[-1] != '\\')
959     strcpy (end, "/");
960   while ((end = strchr (hsz, '\\')) != NULL)
961     *end = '/';
962   return hsz;
963 }
964
965 int main (int, char **);
966
967 int
968 main (int argc, char **argv)
969 {
970   FILE *h_fp;
971   int c;
972   char *target, *input_filename;
973   int verbose;
974
975 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
976   setlocale (LC_MESSAGES, "");
977 #endif
978 #if defined (HAVE_SETLOCALE)
979   setlocale (LC_CTYPE, "");
980 #endif
981   bindtextdomain (PACKAGE, LOCALEDIR);
982   textdomain (PACKAGE);
983
984   program_name = argv[0];
985   xmalloc_set_program_name (program_name);
986
987   expandargv (&argc, &argv);
988
989   bfd_init ();
990   set_default_bfd_target ();
991
992   target = NULL;
993   verbose = 0;
994   input_filename = NULL;
995
996   res_init ();
997
998   while ((c = getopt_long (argc, argv, "C:F:O:h:e:m:r:x:aAbcdHunoUvV", long_options,
999                            (int *) 0)) != EOF)
1000     {
1001       switch (c)
1002         {
1003         case 'b':
1004           mcset_prefix_bin = 1;
1005           break;
1006         case 'e':
1007           {
1008             mcset_header_ext = optarg;
1009             if (mcset_header_ext[0] != '.' && mcset_header_ext[0] != 0)
1010               {
1011                 char *hsz = xmalloc (strlen (mcset_header_ext) + 2);
1012
1013                 sprintf (hsz, ".%s", mcset_header_ext);
1014                 mcset_header_ext = hsz;
1015               }
1016           }
1017           break;
1018         case 'h':
1019           mcset_header_dir = mc_unify_path (optarg);
1020           break;
1021         case 'r':
1022           mcset_rc_dir = mc_unify_path (optarg);
1023           break;
1024         case 'a':
1025           mcset_text_in_is_unicode = 0;
1026           break;
1027         case 'x':
1028           if (*optarg != 0)
1029             mcset_dbg_dir = mc_unify_path (optarg);
1030           break;
1031         case 'A':
1032           mcset_bin_out_is_unicode = 0;
1033           break;
1034         case 'd':
1035           mcset_out_values_are_decimal = 1;
1036           break;
1037         case 'u':
1038           mcset_text_in_is_unicode = 1;
1039           break;
1040         case 'U':
1041           mcset_bin_out_is_unicode = 1;
1042           break;
1043         case 'c':
1044           mcset_custom_bit = 1;
1045           break;
1046         case 'n':
1047           mcset_automatic_null_termination = 1;
1048           break;
1049         case 'o':
1050           mcset_use_hresult = 1;
1051           fatal ("option -o is not implemented until yet.\n");
1052           break;
1053         case 'F':
1054           target = optarg;
1055           break;
1056         case 'v':
1057           verbose ++;
1058           break;
1059         case 'm':
1060           mcset_max_message_length = strtol (optarg, (char **) NULL, 10);
1061           break;
1062         case 'C':
1063           mcset_codepage_in = strtol (optarg, (char **) NULL, 10);
1064           break;
1065         case 'O':
1066           mcset_codepage_out = strtol (optarg, (char **) NULL, 10);
1067           break;
1068         case '?':
1069         case 'H':
1070           usage (stdout, 0);
1071           break;
1072         case 'V':
1073           print_version ("windmc");
1074           break;
1075
1076         default:
1077           usage (stderr, 1);
1078           break;
1079         }
1080     }
1081   if (input_filename == NULL && optind < argc)
1082     {
1083       input_filename = argv[optind];
1084       ++optind;
1085     }
1086
1087   set_endianess (NULL, target);
1088
1089   if (input_filename == NULL)
1090     {
1091       fprintf (stderr, "Error: No input file was specified.\n");
1092       usage (stderr, 1);
1093     }
1094   mc_set_inputfile (input_filename);
1095
1096   if (!probe_codepage (&mcset_codepage_in, &mcset_text_in_is_unicode, "codepage_in", 0))
1097     usage (stderr, 1);
1098   if (mcset_codepage_out == 0)
1099     mcset_codepage_out = 1252;
1100   if (! unicode_is_valid_codepage (mcset_codepage_out))
1101     fatal ("Code page 0x%x is unknown.", (unsigned int) mcset_codepage_out);
1102   if (mcset_codepage_out == CP_UTF16)
1103     fatal ("UTF16 is no valid text output code page.");
1104   if (verbose)
1105     {
1106       fprintf (stderr, "// Default target is %s and it is %s endian.\n",
1107         def_target_arch, (target_is_bigendian ? "big" : "little"));
1108       fprintf (stderr, "// Input codepage: 0x%x\n", (unsigned int) mcset_codepage_in);
1109       fprintf (stderr, "// Output codepage: 0x%x\n", (unsigned int) mcset_codepage_out);
1110     }
1111
1112   if (argc != optind)
1113     usage (stderr, 1);
1114
1115   /* Initialize mcset_mc_basename.  */
1116   {
1117     const char *bn, *bn2;
1118     char *hsz;
1119
1120     bn = strrchr (input_filename, '/');
1121     bn2 = strrchr (input_filename, '\\');
1122     if (! bn)
1123       bn = bn2;
1124     if (bn && bn2 && bn < bn2)
1125       bn = bn2;
1126     if (! bn)
1127       bn = input_filename;
1128     else
1129       bn++;
1130     mcset_mc_basename = hsz = xstrdup (bn);
1131
1132     /* Cut of right-hand extension.  */
1133     if ((hsz = strrchr (hsz, '.')) != NULL)
1134       *hsz = 0;
1135   }
1136
1137   /* Load the input file and do code page transformations to UTF16.  */
1138   {
1139     unichar *u;
1140     rc_uint_type ul;
1141     char *buff;
1142     bfd_size_type flen;
1143     FILE *fp = fopen (input_filename, "rb");
1144
1145     if (!fp)
1146       fatal (_("unable to open file ,%s' for input.\n"), input_filename);
1147
1148     fseek (fp, 0, SEEK_END);
1149     flen = ftell (fp);
1150     fseek (fp, 0, SEEK_SET);
1151     buff = malloc (flen + 3);
1152     memset (buff, 0, flen + 3);
1153     if (fread (buff, 1, flen, fp) < flen)
1154       fatal (_("unable to read contents of %s"), input_filename);
1155     fclose (fp);
1156     if (mcset_text_in_is_unicode != 1)
1157       {
1158         unicode_from_codepage (&ul, &u, buff, mcset_codepage_in);
1159         if (! u)
1160           fatal ("Failed to convert input to UFT16\n");
1161         mc_set_content (u);
1162       }
1163     else
1164       {
1165         if ((flen & 1) != 0)
1166           fatal (_("input file does not seems to be UFT16.\n"));
1167         mc_set_content ((unichar *) buff);
1168       }
1169     free (buff);
1170   }
1171
1172   while (yyparse ())
1173     ;
1174
1175   do_sorts ();
1176
1177   h_fp = mc_create_path_text_file (mcset_header_dir, mcset_header_ext);
1178   write_header (h_fp);
1179   fclose (h_fp);
1180
1181   h_fp = mc_create_path_text_file (mcset_rc_dir, ".rc");
1182   write_rc (h_fp);
1183   fclose (h_fp);
1184
1185   if (mcset_dbg_dir != NULL)
1186     {
1187       h_fp = mc_create_path_text_file (mcset_dbg_dir, ".dbg");
1188       write_dbg (h_fp);
1189       fclose (h_fp);
1190     }
1191   write_bin ();
1192
1193   if (mc_nodes_lang)
1194     free (mc_nodes_lang);
1195   if (mc_severity_codes)
1196     free (mc_severity_codes);
1197   if (mc_facility_codes)
1198     free (mc_facility_codes);
1199
1200   xexit (0);
1201   return 0;
1202 }