1214571Sdim/* windmc.c -- a program to compile Windows message files.
2214571Sdim   Copyright 2007
3214571Sdim   Free Software Foundation, Inc.
4214571Sdim   Written by Kai Tietz, Onevision.
5214571Sdim
6214571Sdim   This file is part of GNU Binutils.
7214571Sdim
8214571Sdim   This program is free software; you can redistribute it and/or modify
9214571Sdim   it under the terms of the GNU General Public License as published by
10214571Sdim   the Free Software Foundation; either version 2 of the License, or
11214571Sdim   (at your option) any later version.
12214571Sdim
13214571Sdim   This program is distributed in the hope that it will be useful,
14214571Sdim   but WITHOUT ANY WARRANTY; without even the implied warranty of
15214571Sdim   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16214571Sdim   GNU General Public License for more details.
17214571Sdim
18214571Sdim   You should have received a copy of the GNU General Public License
19214571Sdim   along with this program; if not, write to the Free Software
20214571Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
21214571Sdim   02110-1301, USA.  */
22214571Sdim
23214571Sdim/* This program can read and comile Windows message format.
24214571Sdim
25214571Sdim   It is based on information taken from the following sources:
26214571Sdim
27214571Sdim   * Microsoft documentation.
28214571Sdim
29214571Sdim   * The wmc program, written by Bertho A. Stultiens (BS). */
30214571Sdim
31214571Sdim#include "sysdep.h"
32214571Sdim#include <assert.h>
33214571Sdim#include <time.h>
34214571Sdim#include "bfd.h"
35214571Sdim#include "getopt.h"
36214571Sdim#include "bucomm.h"
37214571Sdim#include "libiberty.h"
38214571Sdim#include "safe-ctype.h"
39214571Sdim#include "obstack.h"
40214571Sdim
41214571Sdim#include "windmc.h"
42214571Sdim#include "windint.h"
43214571Sdim
44214571Sdim/* Defines a message compiler element item with length and offset
45214571Sdim   information.  */
46214571Sdimtypedef struct mc_msg_item
47214571Sdim{
48214571Sdim  rc_uint_type res_len;
49214571Sdim  rc_uint_type res_off;
50214571Sdim  struct bin_messagetable_item *res;
51214571Sdim} mc_msg_item;
52214571Sdim
53214571Sdim/* Defined in bfd/binary.c.  Used to set architecture and machine of input
54214571Sdim   binary files.  */
55214571Sdimextern enum bfd_architecture  bfd_external_binary_architecture;
56214571Sdimextern unsigned long          bfd_external_machine;
57214571Sdim
58214571Sdimint target_is_bigendian = 0;
59214571Sdimconst char *def_target_arch;
60214571Sdim
61214571Sdim/* Globals and static variable definitions. */
62214571Sdim
63214571Sdim/* bfd global helper struct variable.  */
64214571Sdimstatic struct
65214571Sdim{
66214571Sdim  bfd *abfd;
67214571Sdim  asection *sec;
68214571Sdim} mc_bfd;
69214571Sdim
70214571Sdim/* Memory list.  */
71214571Sdimmc_node *mc_nodes = NULL;
72214571Sdimstatic mc_node_lang **mc_nodes_lang = NULL;
73214571Sdimstatic int mc_nodes_lang_count = 0;
74214571Sdimstatic mc_keyword **mc_severity_codes = NULL;
75214571Sdimstatic int mc_severity_codes_count = 0;
76214571Sdimstatic mc_keyword **mc_facility_codes = NULL;
77214571Sdimstatic int mc_facility_codes_count = 0;
78214571Sdim
79214571Sdim/* When we are building a resource tree, we allocate everything onto
80214571Sdim   an obstack, so that we can free it all at once if we want.  */
81214571Sdim#define obstack_chunk_alloc xmalloc
82214571Sdim#define obstack_chunk_free free
83214571Sdim
84214571Sdim/* The resource building obstack.  */
85214571Sdimstatic struct obstack res_obstack;
86214571Sdim
87214571Sdim/* Flag variables.  */
88214571Sdim/* Set by -C. Set the default code page to be used for input text file.  */
89214571Sdimstatic rc_uint_type mcset_codepage_in = 0;
90214571Sdim
91214571Sdim/* Set by -O. Set the default code page to be used for output text files.  */
92214571Sdimstatic rc_uint_type mcset_codepage_out = 0;
93214571Sdim
94214571Sdim/* Set by -b. .BIN filename should have .mc filename_ included for uniqueness.  */
95214571Sdimstatic int mcset_prefix_bin = 0;
96214571Sdim
97214571Sdim/* The base name of the .mc file.  */
98214571Sdimstatic const char *mcset_mc_basename = "unknown";
99214571Sdim
100214571Sdim/* Set by -e <ext>. Specify the extension for the header file.  */
101214571Sdimstatic const char *mcset_header_ext = ".h";
102214571Sdim
103214571Sdim/* Set by -h <path>. Gives the path of where to create the C include file.  */
104214571Sdimstatic const char *mcset_header_dir = "./";
105214571Sdim
106214571Sdim/* Set by -r <path>. Gives the path of where to create the RC include file
107214571Sdim   and the binary message resource files it includes. */
108214571Sdimstatic const char *mcset_rc_dir = "./";
109214571Sdim
110214571Sdim/* Modified by -a & -u. By -u input file is unicode, by -a is ASCII (default).  */
111214571Sdimstatic int mcset_text_in_is_unicode = 0;
112214571Sdim
113214571Sdim/* Modified by -A & -U. By -U bin file is unicode (default), by -A is ASCII.  */
114214571Sdimstatic int mcset_bin_out_is_unicode = 1;
115214571Sdim
116214571Sdim/* Set by -c. Sets the Customer bit in all the message ID's.  */
117214571Sdimint mcset_custom_bit = 0;
118214571Sdim
119214571Sdim/* Set by -o. Generate OLE2 header file. Use HRESULT definition instead of
120214571Sdim   status code definition.  */
121214571Sdimstatic int mcset_use_hresult = 0;
122214571Sdim
123214571Sdim/* Set by -m <msglen>. Generate a warning if the size of any message exceeds
124214571Sdim   maxmsglen characters.  */
125214571Sdimrc_uint_type mcset_max_message_length = 0;
126214571Sdim
127214571Sdim/* Set by -d. Sets message values in header to decimal initially.  */
128214571Sdimint mcset_out_values_are_decimal = 0;
129214571Sdim
130214571Sdim/* Set by -n. terminates all strings with null's in the message tables.  */
131214571Sdimstatic int mcset_automatic_null_termination = 0;
132214571Sdim
133214571Sdim/* The type used for message id output in header.  */
134214571Sdimunichar *mcset_msg_id_typedef = NULL;
135214571Sdim
136214571Sdim/* Set by -x path. Geberated debug C file for mapping ID's to text.  */
137214571Sdimstatic const char *mcset_dbg_dir = NULL;
138214571Sdim
139214571Sdim/* getopt long name definitions.  */
140214571Sdimstatic const struct option long_options[] =
141214571Sdim{
142214571Sdim  {"binprefix", no_argument, 0, 'b'},
143214571Sdim  {"target", required_argument, 0, 'F'},
144214571Sdim  {"extension", required_argument, 0, 'e'},
145214571Sdim  {"headerdir", required_argument, 0, 'h'},
146214571Sdim  {"rcdir", required_argument, 0, 'r'},
147214571Sdim  {"verbose", no_argument, 0, 'v'},
148214571Sdim  {"codepage_in", required_argument, 0, 'C'},
149214571Sdim  {"codepage_out", required_argument, 0, 'O'},
150214571Sdim  {"maxlength", required_argument, 0, 'm'},
151214571Sdim  {"ascii_in", no_argument, 0, 'a'},
152214571Sdim  {"ascii_out", no_argument, 0, 'A'},
153214571Sdim  {"unicode_in", no_argument, 0, 'u'},
154214571Sdim  {"unicode_out", no_argument, 0, 'U'},
155214571Sdim  {"customflag", no_argument, 0, 'c'},
156214571Sdim  {"decimal_values", no_argument, 0, 'd'},
157214571Sdim  {"hresult_use", no_argument, 0, 'o'},
158214571Sdim  {"nullterminate", no_argument, 0, 'n'},
159214571Sdim  {"xdbg", required_argument, 0, 'x'},
160214571Sdim  {"version", no_argument, 0, 'V'},
161214571Sdim  {"help", no_argument, 0, 'H'},
162214571Sdim  {0, no_argument, 0, 0}
163214571Sdim};
164214571Sdim
165214571Sdim
166214571Sdim/* Initialize the resource building obstack.  */
167214571Sdimstatic void
168214571Sdimres_init (void)
169214571Sdim{
170214571Sdim  obstack_init (&res_obstack);
171214571Sdim}
172214571Sdim
173214571Sdim/* Allocate space on the resource building obstack.  */
174214571Sdimvoid *
175214571Sdimres_alloc (rc_uint_type bytes)
176214571Sdim{
177214571Sdim  return (void *) obstack_alloc (&res_obstack, (size_t) bytes);
178214571Sdim}
179214571Sdim
180214571Sdimstatic FILE *
181214571Sdimmc_create_path_text_file (const char *path, const char *ext)
182214571Sdim{
183214571Sdim  FILE *ret;
184214571Sdim  size_t len = 1;
185214571Sdim  char *hsz;
186214571Sdim
187214571Sdim  len += (path != NULL ? strlen (path) : 0);
188214571Sdim  len += strlen (mcset_mc_basename);
189214571Sdim  len += (ext != NULL ? strlen (ext) : 0);
190214571Sdim  hsz = xmalloc (len);
191214571Sdim  sprintf (hsz, "%s%s%s", (path != NULL ? path : ""), mcset_mc_basename,
192214571Sdim    (ext != NULL ? ext : ""));
193214571Sdim  if ((ret = fopen (hsz, "wb")) == NULL)
194214571Sdim    fatal (_("can't create %s file ,%s' for output.\n"), (ext ? ext : "text"), hsz);
195214571Sdim  free (hsz);
196214571Sdim  return ret;
197214571Sdim}
198214571Sdim
199214571Sdimstatic void
200214571Sdimusage (FILE *stream, int status)
201214571Sdim{
202214571Sdim  fprintf (stream, _("Usage: %s [option(s)] [input-file]\n"),
203214571Sdim	   program_name);
204214571Sdim  fprintf (stream, _(" The options are:\n\
205214571Sdim  -a --ascii_in                Read input file as ASCII file\n\
206214571Sdim  -A --ascii_out               Write binary messages as ASCII\n\
207214571Sdim  -b --binprefix               .bin filename is prefixed by .mc filename_ for uniqueness.\n\
208214571Sdim  -c --customflag              Set custom flags for messages\n\
209214571Sdim  -C --codepage_in=<val>       Set codepage when reading mc text file\n\
210214571Sdim  -d --decimal_values          Print values to text files decimal\n\
211214571Sdim  -e --extension=<extension>   Set header extension used on export header file\n\
212214571Sdim  -F --target <target>         Specify output target for endianess.\n\
213214571Sdim  -h --headerdir=<directory>   Set the export directory for headers\n\
214214571Sdim  -u --unicode_in              Read input file as UTF16 file\n\
215214571Sdim  -U --unicode_out             Write binary messages as UFT16\n\
216214571Sdim  -m --maxlength=<val>         Set the maximal allowed message length\n\
217214571Sdim  -n --nullterminate           Automatic add a zero termination to strings\n\
218214571Sdim  -o --hresult_use             Use HRESULT definition instead of status code definition\n\
219214571Sdim  -O --codepage_out=<val>      Set codepage used for writing text file\n\
220214571Sdim  -r --rcdir=<directory>       Set the export directory for rc files\n\
221214571Sdim  -x --xdbg=<directory>        Where to create the .dbg C include file\n\
222214571Sdim                               that maps message ID's to their symbolic name.\n\
223214571Sdim"));
224214571Sdim  fprintf (stream, _("\
225214571Sdim  -H --help                    Print this help message\n\
226214571Sdim  -v --verbose                 Verbose - tells you what it's doing\n\
227214571Sdim  -V --version                 Print version information\n"));
228214571Sdim
229214571Sdim  list_supported_targets (program_name, stream);
230214571Sdim
231214571Sdim  if (REPORT_BUGS_TO[0] && status == 0)
232214571Sdim    fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
233214571Sdim
234214571Sdim  exit (status);
235214571Sdim}
236214571Sdim
237214571Sdimstatic void
238214571Sdimset_endianess (bfd *abfd, const char *target)
239214571Sdim{
240214571Sdim  const bfd_target *target_vec;
241214571Sdim
242214571Sdim  def_target_arch = NULL;
243214571Sdim  target_vec = bfd_find_target (target, abfd);
244214571Sdim  if (! target_vec)
245214571Sdim    fatal ("Can't detect target endianess and architecture.");
246214571Sdim  target_is_bigendian = ((target_vec->byteorder == BFD_ENDIAN_BIG) ? 1 : 0);
247214571Sdim  {
248214571Sdim    const char *tname = target_vec->name;
249214571Sdim    const char **arch = bfd_arch_list ();
250214571Sdim
251214571Sdim    if (arch && tname)
252214571Sdim      {
253214571Sdim	if (strchr (tname, '-') != NULL)
254214571Sdim	  tname = strchr (tname, '-') + 1;
255214571Sdim	while (*arch != NULL)
256214571Sdim	  {
257214571Sdim	    const char *in_a = strstr (*arch, tname);
258214571Sdim	    char end_ch = (in_a ? in_a[strlen (tname)] : 0);
259214571Sdim	    if (in_a && (in_a == *arch || in_a[-1] == ':')
260214571Sdim	        && end_ch == 0)
261214571Sdim	      {
262214571Sdim		def_target_arch = *arch;
263214571Sdim		break;
264214571Sdim	      }
265214571Sdim	    arch++;
266214571Sdim	  }
267214571Sdim      }
268214571Sdim    if (! def_target_arch)
269214571Sdim      fatal ("Can't detect architecture.");
270214571Sdim  }
271214571Sdim}
272214571Sdim
273214571Sdimstatic int
274214571Sdimprobe_codepage (rc_uint_type *cp, int *is_uni, const char *pswitch, int defmode)
275214571Sdim{
276214571Sdim  if (*is_uni == -1)
277214571Sdim    {
278214571Sdim      if (*cp != CP_UTF16)
279214571Sdim	*is_uni = defmode;
280214571Sdim      else
281214571Sdim	*is_uni = 1;
282214571Sdim    }
283214571Sdim  if (*is_uni)
284214571Sdim    {
285214571Sdim      if (*cp != 0 && *cp != CP_UTF16)
286214571Sdim	{
287214571Sdim	  fprintf (stderr, _("%s: warning: "), program_name);
288214571Sdim	  fprintf (stderr, _("A codepage was specified switch ,%s' and UTF16.\n"), pswitch);
289214571Sdim	  fprintf (stderr, _("\tcodepage settings are ignored.\n"));
290214571Sdim	}
291214571Sdim      *cp = CP_UTF16;
292214571Sdim      return 1;
293214571Sdim    }
294214571Sdim  if (*cp == CP_UTF16)
295214571Sdim    {
296214571Sdim      *is_uni = 1;
297214571Sdim      return 1;
298214571Sdim    }
299214571Sdim  if (*cp == 0)
300214571Sdim    *cp = 1252;
301214571Sdim  if (! unicode_is_valid_codepage (*cp))
302214571Sdim	fatal ("Code page 0x%x is unknown.", (unsigned int) *cp);
303214571Sdim  *is_uni = 0;
304214571Sdim  return 1;
305214571Sdim}
306214571Sdim
307214571Sdimmc_node *
308214571Sdimmc_add_node (void)
309214571Sdim{
310214571Sdim  mc_node *ret;
311214571Sdim
312214571Sdim  ret = res_alloc (sizeof (mc_node));
313214571Sdim  memset (ret, 0, sizeof (mc_node));
314214571Sdim  if (! mc_nodes)
315214571Sdim    mc_nodes = ret;
316214571Sdim  else
317214571Sdim    {
318214571Sdim      mc_node *h = mc_nodes;
319214571Sdim
320214571Sdim      while (h->next != NULL)
321214571Sdim	h = h->next;
322214571Sdim      h->next = ret;
323214571Sdim    }
324214571Sdim  return ret;
325214571Sdim}
326214571Sdim
327214571Sdimmc_node_lang *
328214571Sdimmc_add_node_lang (mc_node *root, const mc_keyword *lang, rc_uint_type vid)
329214571Sdim{
330214571Sdim  mc_node_lang *ret, *h, *p;
331214571Sdim
332214571Sdim  if (! lang || ! root)
333214571Sdim    fatal (_("try to add a ill language."));
334214571Sdim  ret = res_alloc (sizeof (mc_node_lang));
335214571Sdim  memset (ret, 0, sizeof (mc_node_lang));
336214571Sdim  ret->lang = lang;
337214571Sdim  ret->vid = vid;
338214571Sdim  if ((h = root->sub) == NULL)
339214571Sdim    root->sub = ret;
340214571Sdim  else
341214571Sdim    {
342214571Sdim      p = NULL;
343214571Sdim      while (h != NULL)
344214571Sdim	{
345214571Sdim	  if (h->lang->nval > lang->nval)
346214571Sdim	    break;
347214571Sdim	  if (h->lang->nval == lang->nval)
348214571Sdim	    {
349214571Sdim	      if (h->vid > vid)
350214571Sdim		break;
351214571Sdim	      if (h->vid == vid)
352214571Sdim		fatal ("double defined message id %ld.\n", (long) vid);
353214571Sdim	    }
354214571Sdim	  h = (p = h)->next;
355214571Sdim	}
356214571Sdim      ret->next = h;
357214571Sdim      if (! p)
358214571Sdim	root->sub = ret;
359214571Sdim      else
360214571Sdim	p->next = ret;
361214571Sdim    }
362214571Sdim  return ret;
363214571Sdim}
364214571Sdim
365214571Sdimstatic char *
366214571Sdimconvert_unicode_to_ACP (const unichar *usz)
367214571Sdim{
368214571Sdim  char *s;
369214571Sdim  rc_uint_type l;
370214571Sdim
371214571Sdim  if (! usz)
372214571Sdim    return NULL;
373214571Sdim  codepage_from_unicode (&l, usz, &s, mcset_codepage_out);
374214571Sdim  if (! s)
375214571Sdim    fatal ("unicode string not mappable to ASCII codepage 0x%lx.\n", (long) mcset_codepage_out);
376214571Sdim  return s;
377214571Sdim}
378214571Sdim
379214571Sdimstatic void
380214571Sdimwrite_dbg_define (FILE *fp, const unichar *sym_name, const unichar *typecast)
381214571Sdim{
382214571Sdim  char *sym;
383214571Sdim
384214571Sdim  if (!sym_name || sym_name[0] == 0)
385214571Sdim    return;
386214571Sdim  sym = convert_unicode_to_ACP (sym_name);
387214571Sdim  fprintf (fp, "  {(");
388214571Sdim  if (typecast)
389214571Sdim    unicode_print (fp, typecast, unichar_len (typecast));
390214571Sdim  else
391214571Sdim    fprintf (fp, "DWORD");
392214571Sdim  fprintf (fp, ") %s, \"%s\" },\n", sym, sym);
393214571Sdim}
394214571Sdim
395214571Sdimstatic void
396214571Sdimwrite_header_define (FILE *fp, const unichar *sym_name, rc_uint_type vid, const unichar *typecast, mc_node_lang *nl)
397214571Sdim{
398214571Sdim  char *sym;
399214571Sdim  char *tdef = NULL;
400214571Sdim
401214571Sdim  if (!sym_name || sym_name[0] == 0)
402214571Sdim    {
403214571Sdim      if (nl != NULL)
404214571Sdim	{
405214571Sdim	  if (mcset_out_values_are_decimal)
406214571Sdim	    fprintf (fp, "//\n// MessageId: 0x%lu\n//\n", (unsigned long) vid);
407214571Sdim	  else
408214571Sdim	    fprintf (fp, "//\n// MessageId: 0x%lx\n//\n", (unsigned long) vid);
409214571Sdim	}
410214571Sdim      return;
411214571Sdim    }
412214571Sdim  sym = convert_unicode_to_ACP (sym_name);
413214571Sdim  if (typecast && typecast[0] != 0)
414214571Sdim    tdef = convert_unicode_to_ACP (typecast);
415214571Sdim  fprintf (fp, "//\n// MessageId: %s\n//\n", sym);
416214571Sdim  if (! mcset_out_values_are_decimal)
417214571Sdim    fprintf (fp, "#define %s %s%s%s 0x%lx\n\n", sym,
418214571Sdim      (tdef ? "(" : ""), (tdef ? tdef : ""), (tdef ? ")" : ""),
419214571Sdim    (unsigned long) vid);
420214571Sdim  else
421214571Sdim    fprintf (fp, "#define %s %s%s%s 0x%lu\n\n", sym,
422214571Sdim      (tdef ? "(" : ""), (tdef ? tdef : ""), (tdef ? ")" : ""),
423214571Sdim    (unsigned long) vid);
424214571Sdim}
425214571Sdim
426214571Sdimstatic int
427214571Sdimsort_mc_node_lang (const void *l, const void *r)
428214571Sdim{
429214571Sdim  const mc_node_lang *l1 = *((const mc_node_lang **)l);
430214571Sdim  const mc_node_lang *r1 = *((const mc_node_lang **)r);
431214571Sdim
432214571Sdim  if (l == r)
433214571Sdim    return 0;
434214571Sdim  if (l1->lang != r1->lang)
435214571Sdim    {
436214571Sdim      if (l1->lang->nval < r1->lang->nval)
437214571Sdim	return -1;
438214571Sdim      return 1;
439214571Sdim    }
440214571Sdim  if (l1->vid == r1->vid)
441214571Sdim    return 0;
442214571Sdim  if (l1->vid < r1->vid)
443214571Sdim    return -1;
444214571Sdim  return 1;
445214571Sdim}
446214571Sdim
447214571Sdimstatic int
448214571Sdimsort_keyword_by_nval (const void *l, const void *r)
449214571Sdim{
450214571Sdim  const mc_keyword *l1 = *((const mc_keyword **)l);
451214571Sdim  const mc_keyword *r1 = *((const mc_keyword **)r);
452214571Sdim  rc_uint_type len1, len2;
453214571Sdim  int e;
454214571Sdim
455214571Sdim  if (l == r)
456214571Sdim    return 0;
457214571Sdim  if (l1->nval != r1->nval)
458214571Sdim    {
459214571Sdim      if (l1->nval < r1->nval)
460214571Sdim	return -1;
461214571Sdim      return 1;
462214571Sdim    }
463214571Sdim  len1 = unichar_len (l1->usz);
464214571Sdim  len2 = unichar_len (r1->usz);
465214571Sdim  if (len1 <= len2)
466214571Sdim    e = memcmp (l1->usz, r1->usz, sizeof (unichar) * len1);
467214571Sdim  else
468214571Sdim    e = memcmp (l1->usz, r1->usz, sizeof (unichar) * len2);
469214571Sdim  if (e)
470214571Sdim    return e;
471214571Sdim  if (len1 < len2)
472214571Sdim    return -1;
473214571Sdim  else if (len1 > len2)
474214571Sdim    return 1;
475214571Sdim  return 0;
476214571Sdim}
477214571Sdim
478214571Sdimstatic void
479214571Sdimdo_sorts (void)
480214571Sdim{
481214571Sdim  mc_node *h;
482214571Sdim  mc_node_lang *n;
483214571Sdim  const mc_keyword *k;
484214571Sdim  int i;
485214571Sdim
486214571Sdim  /* Sort message by their language and id ascending.  */
487214571Sdim  mc_nodes_lang_count = 0;
488214571Sdim
489214571Sdim  h = mc_nodes;
490214571Sdim  while (h != NULL)
491214571Sdim    {
492214571Sdim      n = h->sub;
493214571Sdim      while (n != NULL)
494214571Sdim	{
495214571Sdim	  mc_nodes_lang_count +=1;
496214571Sdim	  n = n->next;
497214571Sdim	}
498214571Sdim      h = h->next;
499214571Sdim    }
500214571Sdim
501214571Sdim  if (mc_nodes_lang_count != 0)
502214571Sdim    {
503214571Sdim      h = mc_nodes;
504214571Sdim      i = 0;
505214571Sdim      mc_nodes_lang = xmalloc (sizeof (mc_node_lang *) * mc_nodes_lang_count);
506214571Sdim
507214571Sdim      while (h != NULL)
508214571Sdim	{
509214571Sdim	  n = h->sub;
510214571Sdim	  while (n != NULL)
511214571Sdim	    {
512214571Sdim	      mc_nodes_lang[i++] = n;
513214571Sdim	      n = n->next;
514214571Sdim	    }
515214571Sdim	  h = h->next;
516214571Sdim	}
517214571Sdim      qsort (mc_nodes_lang, (size_t) mc_nodes_lang_count, sizeof (mc_node_lang *), sort_mc_node_lang);
518214571Sdim    }
519214571Sdim  /* Sort facility code definitions by there id ascending.  */
520214571Sdim  i = 0;
521214571Sdim  while ((k = enum_facility (i)) != NULL)
522214571Sdim    ++i;
523214571Sdim  mc_facility_codes_count = i;
524214571Sdim  if (i != 0)
525214571Sdim    {
526214571Sdim      mc_facility_codes = xmalloc (sizeof (mc_keyword *) * i);
527214571Sdim      i = 0;
528214571Sdim      while ((k = enum_facility (i)) != NULL)
529214571Sdim	mc_facility_codes[i++] = (mc_keyword *) k;
530214571Sdim      qsort (mc_facility_codes, (size_t) mc_facility_codes_count, sizeof (mc_keyword *), sort_keyword_by_nval);
531214571Sdim    }
532214571Sdim
533214571Sdim  /* Sort severity code definitions by there id ascending.  */
534214571Sdim  i = 0;
535214571Sdim  while ((k = enum_severity (i)) != NULL)
536214571Sdim    ++i;
537214571Sdim  mc_severity_codes_count = i;
538214571Sdim  if (i != 0)
539214571Sdim    {
540214571Sdim      mc_severity_codes = xmalloc (sizeof (mc_keyword *) * i);
541214571Sdim      i = 0;
542214571Sdim      while ((k = enum_severity (i)) != NULL)
543214571Sdim	mc_severity_codes[i++] = (mc_keyword *) k;
544214571Sdim      qsort (mc_severity_codes, (size_t) mc_severity_codes_count, sizeof (mc_keyword *), sort_keyword_by_nval);
545214571Sdim    }
546214571Sdim}
547214571Sdim
548214571Sdimstatic int
549214571Sdimmc_get_block_count (mc_node_lang **nl, int elems)
550214571Sdim{
551214571Sdim  rc_uint_type exid;
552214571Sdim  int i, ret;
553214571Sdim
554214571Sdim  if (! nl)
555214571Sdim    return 0;
556214571Sdim  i = 0;
557214571Sdim  ret = 0;
558214571Sdim  while (i < elems)
559214571Sdim    {
560214571Sdim      ret++;
561214571Sdim      exid = nl[i++]->vid;
562214571Sdim      while (i < elems && nl[i]->vid == exid + 1)
563214571Sdim	exid = nl[i++]->vid;
564214571Sdim    }
565214571Sdim  return ret;
566214571Sdim}
567214571Sdim
568214571Sdimstatic bfd *
569214571Sdimwindmc_open_as_binary (const char *filename)
570214571Sdim{
571214571Sdim  bfd *abfd;
572214571Sdim
573214571Sdim  abfd = bfd_openw (filename, "binary");
574214571Sdim  if (! abfd)
575214571Sdim    fatal ("can't open `%s' for output", filename);
576214571Sdim
577214571Sdim  return abfd;
578214571Sdim}
579214571Sdim
580214571Sdimstatic void
581214571Sdimtarget_put_16 (void *p, rc_uint_type value)
582214571Sdim{
583214571Sdim  assert (!! p);
584214571Sdim
585214571Sdim  if (target_is_bigendian)
586214571Sdim    bfd_putb16 (value, p);
587214571Sdim  else
588214571Sdim    bfd_putl16 (value, p);
589214571Sdim}
590214571Sdim
591214571Sdimstatic void
592214571Sdimtarget_put_32 (void *p, rc_uint_type value)
593214571Sdim{
594214571Sdim  assert (!! p);
595214571Sdim
596214571Sdim  if (target_is_bigendian)
597214571Sdim    bfd_putb32 (value, p);
598214571Sdim  else
599214571Sdim    bfd_putl32 (value, p);
600214571Sdim}
601214571Sdim
602214571Sdimstatic struct bin_messagetable_item *
603214571Sdimmc_generate_bin_item (mc_node_lang *n, rc_uint_type *res_len)
604214571Sdim{
605214571Sdim  struct bin_messagetable_item *ret = NULL;
606214571Sdim  rc_uint_type len;
607214571Sdim
608214571Sdim  *res_len = 0;
609214571Sdim  if (mcset_bin_out_is_unicode == 1)
610214571Sdim    {
611214571Sdim      unichar *ht = n->message;
612214571Sdim      rc_uint_type txt_len;
613214571Sdim
614214571Sdim      txt_len = unichar_len (n->message);
615214571Sdim      if (mcset_automatic_null_termination && txt_len != 0)
616214571Sdim	{
617214571Sdim	  while (txt_len > 0 && ht[txt_len - 1] > 0 && ht[txt_len - 1] < 0x20)
618214571Sdim	    ht[--txt_len] = 0;
619214571Sdim	}
620214571Sdim      txt_len *= sizeof (unichar);
621214571Sdim      len = BIN_MESSAGETABLE_ITEM_SIZE + txt_len + sizeof (unichar);
622214571Sdim      ret = res_alloc ((len + 3) & ~3);
623214571Sdim      memset (ret, 0, (len + 3) & ~3);
624214571Sdim      target_put_16 (ret->length, (len + 3) & ~3);
625214571Sdim      target_put_16 (ret->flags, MESSAGE_RESOURCE_UNICODE);
626214571Sdim      txt_len = 0;
627214571Sdim      while (*ht != 0)
628214571Sdim	{
629214571Sdim	  target_put_16 (ret->data + txt_len, *ht++);
630214571Sdim	  txt_len += 2;
631214571Sdim	}
632214571Sdim    }
633214571Sdim  else
634214571Sdim    {
635214571Sdim      rc_uint_type txt_len, l;
636214571Sdim      char *cvt_txt;
637214571Sdim
638214571Sdim      codepage_from_unicode( &l, n->message, &cvt_txt, n->lang->lang_info.wincp);
639214571Sdim      if (! cvt_txt)
640214571Sdim	fatal ("Failed to convert message to language codepage.\n");
641214571Sdim      txt_len = strlen (cvt_txt);
642214571Sdim      if (mcset_automatic_null_termination && txt_len > 0)
643214571Sdim	{
644214571Sdim	  while (txt_len > 0 && cvt_txt[txt_len - 1] > 0 && cvt_txt[txt_len - 1] < 0x20)
645214571Sdim	    cvt_txt[--txt_len] = 0;
646214571Sdim	}
647214571Sdim      len = BIN_MESSAGETABLE_ITEM_SIZE + txt_len + 1;
648214571Sdim      ret = res_alloc ((len + 3) & ~3);
649214571Sdim      memset (ret, 0, (len + 3) & ~3);
650214571Sdim      target_put_16 (ret->length, (len + 3) & ~3);
651214571Sdim      target_put_16 (ret->flags, 0);
652214571Sdim      strcpy ((char *) ret->data, cvt_txt);
653214571Sdim    }
654214571Sdim  *res_len = (len + 3) & ~3;
655214571Sdim  return ret;
656214571Sdim}
657214571Sdim
658214571Sdimstatic void
659214571Sdimmc_write_blocks (struct bin_messagetable *mtbl, mc_node_lang **nl, mc_msg_item *ml, int elems)
660214571Sdim{
661214571Sdim  int i, idx = 0;
662214571Sdim  rc_uint_type exid;
663214571Sdim
664214571Sdim  if (! nl)
665214571Sdim    return;
666214571Sdim  i = 0;
667214571Sdim  while (i < elems)
668214571Sdim    {
669214571Sdim      target_put_32 (mtbl->items[idx].lowid, nl[i]->vid);
670214571Sdim      target_put_32 (mtbl->items[idx].highid, nl[i]->vid);
671214571Sdim      target_put_32 (mtbl->items[idx].offset, ml[i].res_off);
672214571Sdim      exid = nl[i++]->vid;
673214571Sdim      while (i < elems && nl[i]->vid == exid + 1)
674214571Sdim	{
675214571Sdim	  target_put_32 (mtbl->items[idx].highid, nl[i]->vid);
676214571Sdim	  exid = nl[i++]->vid;
677214571Sdim	}
678214571Sdim      ++idx;
679214571Sdim    }
680214571Sdim}
681214571Sdim
682214571Sdimstatic void
683214571Sdimset_windmc_bfd_content (const void *data, rc_uint_type off, rc_uint_type length)
684214571Sdim{
685214571Sdim  if (! bfd_set_section_contents (mc_bfd.abfd, mc_bfd.sec, data, off, length))
686214571Sdim    bfd_fatal ("bfd_set_section_contents");
687214571Sdim}
688214571Sdim
689214571Sdimstatic void
690214571Sdimwindmc_write_bin (const char *filename, mc_node_lang **nl, int elems)
691214571Sdim{
692214571Sdim  unsigned long sec_length = 1;
693214571Sdim  int block_count, i;
694214571Sdim  mc_msg_item *mi;
695214571Sdim  struct bin_messagetable *mtbl;
696214571Sdim  rc_uint_type dta_off, dta_start;
697214571Sdim
698214571Sdim  if (elems <= 0)
699214571Sdim    return;
700214571Sdim  mc_bfd.abfd = windmc_open_as_binary (filename);
701214571Sdim  mc_bfd.sec = bfd_make_section (mc_bfd.abfd, ".data");
702214571Sdim  if (mc_bfd.sec == NULL)
703214571Sdim    bfd_fatal ("bfd_make_section");
704214571Sdim  if (! bfd_set_section_flags (mc_bfd.abfd, mc_bfd.sec,
705214571Sdim			       (SEC_HAS_CONTENTS | SEC_ALLOC
706214571Sdim			        | SEC_LOAD | SEC_DATA)))
707214571Sdim    bfd_fatal ("bfd_set_section_flags");
708214571Sdim  /* Requiring this is probably a bug in BFD.  */
709214571Sdim  mc_bfd.sec->output_section = mc_bfd.sec;
710214571Sdim
711214571Sdim  block_count = mc_get_block_count (nl, elems);
712214571Sdim
713214571Sdim  dta_off = (rc_uint_type) ((BIN_MESSAGETABLE_BLOCK_SIZE * block_count) + BIN_MESSAGETABLE_SIZE - 4);
714214571Sdim  dta_start = dta_off = (dta_off + 3) & ~3;
715214571Sdim  mi = xmalloc (sizeof (mc_msg_item) * elems);
716214571Sdim  mtbl = xmalloc (dta_start);
717214571Sdim
718214571Sdim  /* Clear header region.  */
719214571Sdim  memset (mtbl, 0, dta_start);
720214571Sdim  target_put_32 (mtbl->cblocks, block_count);
721214571Sdim  /* Prepare items section for output.  */
722214571Sdim  for (i = 0; i < elems; i++)
723214571Sdim    {
724214571Sdim      mi[i].res_off = dta_off;
725214571Sdim      mi[i].res = mc_generate_bin_item (nl[i], &mi[i].res_len);
726214571Sdim      dta_off += mi[i].res_len;
727214571Sdim    }
728214571Sdim  sec_length = (dta_off + 3) & ~3;
729214571Sdim  if (! bfd_set_section_size (mc_bfd.abfd, mc_bfd.sec, sec_length))
730214571Sdim    bfd_fatal ("bfd_set_section_size");
731214571Sdim  /* Make sure we write the complete block.  */
732214571Sdim  set_windmc_bfd_content ("\0", sec_length - 1, 1);
733214571Sdim
734214571Sdim  /* Write block information.  */
735214571Sdim  mc_write_blocks (mtbl, nl, mi, elems);
736214571Sdim
737214571Sdim  set_windmc_bfd_content (mtbl, 0, dta_start);
738214571Sdim
739214571Sdim  /* Write items.  */
740214571Sdim  for (i = 0; i < elems; i++)
741214571Sdim    set_windmc_bfd_content (mi[i].res, mi[i].res_off, mi[i].res_len);
742214571Sdim
743214571Sdim  free (mtbl);
744214571Sdim  free (mi);
745214571Sdim  bfd_close (mc_bfd.abfd);
746214571Sdim  mc_bfd.abfd = NULL;
747214571Sdim  mc_bfd.sec = NULL;
748214571Sdim}
749214571Sdim
750214571Sdimstatic void
751214571Sdimwrite_bin (void)
752214571Sdim{
753214571Sdim  mc_node_lang *n = NULL;
754214571Sdim  int i, c;
755214571Sdim
756214571Sdim  if (! mc_nodes_lang_count)
757214571Sdim    return;
758214571Sdim
759214571Sdim  i = 0;
760214571Sdim  while (i < mc_nodes_lang_count)
761214571Sdim    {
762214571Sdim      char *nd;
763214571Sdim      char *filename;
764214571Sdim
765214571Sdim      if (n && n->lang == mc_nodes_lang[i]->lang)
766214571Sdim	{
767214571Sdim	  i++;
768214571Sdim	  continue;
769214571Sdim	}
770214571Sdim      n = mc_nodes_lang[i];
771214571Sdim      c = i + 1;
772214571Sdim      while (c < mc_nodes_lang_count && n->lang == mc_nodes_lang[c]->lang)
773214571Sdim	c++;
774214571Sdim      nd = convert_unicode_to_ACP (n->lang->sval);
775214571Sdim
776214571Sdim      /* Prepare filename for binary output.  */
777214571Sdim      filename = xmalloc (strlen (nd) + 4 + 1 + strlen (mcset_mc_basename) + 1 + strlen (mcset_rc_dir));
778214571Sdim      strcpy (filename, mcset_rc_dir);
779214571Sdim      if (mcset_prefix_bin)
780214571Sdim	sprintf (filename + strlen (filename), "%s_", mcset_mc_basename);
781214571Sdim      strcat (filename, nd);
782214571Sdim      strcat (filename, ".bin");
783214571Sdim
784214571Sdim      /* Write message file.  */
785214571Sdim      windmc_write_bin (filename, &mc_nodes_lang[i], (c - i));
786214571Sdim
787214571Sdim      free (filename);
788214571Sdim      i = c;
789214571Sdim    }
790214571Sdim}
791214571Sdim
792214571Sdimstatic void
793214571Sdimwrite_rc (FILE *fp)
794214571Sdim{
795214571Sdim  mc_node_lang *n;
796214571Sdim  int i, l;
797214571Sdim
798214571Sdim  fprintf (fp,
799214571Sdim    "/* Do not edit this file manually.\n"
800214571Sdim    "   This file is autogenerated by windmc.  */\n\n");
801214571Sdim  if (! mc_nodes_lang_count)
802214571Sdim    return;
803214571Sdim  n = NULL;
804214571Sdim  i = 0;
805214571Sdim  for (l = 0; l < mc_nodes_lang_count; l++)
806214571Sdim    {
807214571Sdim      if (n && n->lang == mc_nodes_lang[l]->lang)
808214571Sdim	continue;
809214571Sdim      ++i;
810214571Sdim      n = mc_nodes_lang[l];
811214571Sdim      fprintf (fp, "\n// Country: %s\n// Language: %s\n#pragma code_page(%u)\n",
812214571Sdim	n->lang->lang_info.country, n->lang->lang_info.name,
813214571Sdim	(unsigned) n->lang->lang_info.wincp);
814214571Sdim      fprintf (fp, "LANGUAGE 0x%lx, 0x%lx\n", (long) (n->lang->nval & 0x3ff),
815214571Sdim	(long) ((n->lang->nval & 0xffff) >> 10));
816214571Sdim      fprintf (fp, "1 MESSAGETABLE \"");
817214571Sdim      if (mcset_prefix_bin)
818214571Sdim	fprintf (fp, "%s_", mcset_mc_basename);
819214571Sdim      unicode_print (fp, n->lang->sval, unichar_len (n->lang->sval));
820214571Sdim      fprintf (fp, ".bin\"\n");
821214571Sdim    }
822214571Sdim}
823214571Sdim
824214571Sdimstatic void
825214571Sdimwrite_dbg (FILE *fp)
826214571Sdim{
827214571Sdim  mc_node *h;
828214571Sdim
829214571Sdim  fprintf (fp,
830214571Sdim    "/* Do not edit this file manually.\n"
831214571Sdim    "   This file is autogenerated by windmc.\n\n"
832214571Sdim    "   This file maps each message ID value in to a text string that contains\n"
833214571Sdim    "   the symbolic name used for it.  */\n\n");
834214571Sdim
835214571Sdim  fprintf (fp,
836214571Sdim    "struct %sSymbolicName\n"
837214571Sdim    "{\n  ", mcset_mc_basename);
838214571Sdim  if (mcset_msg_id_typedef)
839214571Sdim    unicode_print (fp, mcset_msg_id_typedef, unichar_len (mcset_msg_id_typedef));
840214571Sdim  else
841214571Sdim    fprintf (fp, "DWORD");
842214571Sdim  fprintf (fp,
843214571Sdim    " MessageId;\n"
844214571Sdim    "  char *SymbolicName;\n"
845214571Sdim    "} %sSymbolicNames[] =\n"
846214571Sdim    "{\n", mcset_mc_basename);
847214571Sdim  h = mc_nodes;
848214571Sdim  while (h != NULL)
849214571Sdim    {
850214571Sdim      if (h->symbol)
851214571Sdim	write_dbg_define (fp, h->symbol, mcset_msg_id_typedef);
852214571Sdim      h = h->next;
853214571Sdim    }
854214571Sdim  fprintf (fp, "  { (");
855214571Sdim  if (mcset_msg_id_typedef)
856214571Sdim    unicode_print (fp, mcset_msg_id_typedef, unichar_len (mcset_msg_id_typedef));
857214571Sdim  else
858214571Sdim    fprintf (fp, "DWORD");
859214571Sdim  fprintf (fp,
860214571Sdim    ") 0xffffffff, NULL }\n"
861214571Sdim    "};\n");
862214571Sdim}
863214571Sdim
864214571Sdimstatic void
865214571Sdimwrite_header (FILE *fp)
866214571Sdim{
867214571Sdim  char *s;
868214571Sdim  int i;
869214571Sdim  const mc_keyword *key;
870214571Sdim  mc_node *h;
871214571Sdim
872214571Sdim  fprintf (fp,
873214571Sdim    "/* Do not edit this file manually.\n"
874214571Sdim    "   This file is autogenerated by windmc.  */\n\n"
875214571Sdim    "//\n//  The values are 32 bit layed out as follows:\n//\n"
876214571Sdim    "//   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1\n"
877214571Sdim    "//   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"
878214571Sdim    "//  +---+-+-+-----------------------+-------------------------------+\n"
879214571Sdim    "//  |Sev|C|R|     Facility          |               Code            |\n"
880214571Sdim    "//  +---+-+-+-----------------------+-------------------------------+\n//\n"
881214571Sdim    "//  where\n//\n"
882214571Sdim    "//      C    - is the Customer code flag\n//\n"
883214571Sdim    "//      R    - is a reserved bit\n//\n"
884214571Sdim    "//      Code - is the facility's status code\n//\n");
885214571Sdim
886214571Sdim  h = mc_nodes;
887214571Sdim
888214571Sdim  fprintf (fp, "//      Sev  - is the severity code\n//\n");
889214571Sdim  if (mc_severity_codes_count != 0)
890214571Sdim    {
891214571Sdim      for (i = 0; i < mc_severity_codes_count; i++)
892214571Sdim	{
893214571Sdim	  key = mc_severity_codes[i];
894214571Sdim	  fprintf (fp, "//           %s - %02lx\n", convert_unicode_to_ACP (key->usz),
895214571Sdim		   (unsigned long) key->nval);
896214571Sdim	  if (key->sval && key->sval[0] != 0)
897214571Sdim	    {
898214571Sdim	      if (! mcset_out_values_are_decimal)
899214571Sdim		fprintf (fp, "#define %s 0x%lx\n", convert_unicode_to_ACP (key->sval),
900214571Sdim			 (unsigned long) key->nval);
901214571Sdim	      else
902214571Sdim		fprintf (fp, "#define %s 0x%lu\n", convert_unicode_to_ACP (key->sval),
903214571Sdim			 (unsigned long) key->nval);
904214571Sdim	    }
905214571Sdim	}
906214571Sdim      fprintf (fp, "//\n");
907214571Sdim    }
908214571Sdim  fprintf (fp, "//      Facility - is the facility code\n//\n");
909214571Sdim  if (mc_facility_codes_count != 0)
910214571Sdim    {
911214571Sdim      for (i = 0; i < mc_facility_codes_count; i++)
912214571Sdim	{
913214571Sdim	  key = mc_facility_codes[i];
914214571Sdim	  fprintf (fp, "//           %s - %04lx\n", convert_unicode_to_ACP (key->usz),
915214571Sdim		   (unsigned long) key->nval);
916214571Sdim	  if (key->sval && key->sval[0] != 0)
917214571Sdim	    {
918214571Sdim	      if (! mcset_out_values_are_decimal)
919214571Sdim		fprintf (fp, "#define %s 0x%lx\n", convert_unicode_to_ACP (key->sval),
920214571Sdim			 (unsigned long) key->nval);
921214571Sdim	      else
922214571Sdim		fprintf (fp, "#define %s 0x%lu\n", convert_unicode_to_ACP (key->sval),
923214571Sdim			 (unsigned long) key->nval);
924214571Sdim	    }
925214571Sdim	}
926214571Sdim      fprintf (fp, "//\n");
927214571Sdim    }
928214571Sdim  fprintf (fp, "\n");
929214571Sdim  while (h != NULL)
930214571Sdim    {
931214571Sdim      if (h->user_text)
932214571Sdim	{
933214571Sdim	  s = convert_unicode_to_ACP (h->user_text);
934214571Sdim	  if (s)
935214571Sdim	    fprintf (fp, "%s", s);
936214571Sdim	}
937214571Sdim      if (h->symbol)
938214571Sdim	write_header_define (fp, h->symbol, h->vid, mcset_msg_id_typedef, h->sub);
939214571Sdim      h = h->next;
940214571Sdim    }
941214571Sdim}
942214571Sdim
943214571Sdimstatic const char *
944214571Sdimmc_unify_path (const char *path)
945214571Sdim{
946214571Sdim  char *end;
947214571Sdim  char *hsz;
948214571Sdim
949214571Sdim  if (! path || *path == 0)
950214571Sdim    return "./";
951214571Sdim  hsz = xmalloc (strlen (path) + 2);
952214571Sdim  strcpy (hsz, path);
953214571Sdim  end = hsz + strlen (hsz);
954214571Sdim  if (hsz[-1] != '/' && hsz[-1] != '\\')
955214571Sdim    strcpy (end, "/");
956214571Sdim  while ((end = strchr (hsz, '\\')) != NULL)
957214571Sdim    *end = '/';
958214571Sdim  return hsz;
959214571Sdim}
960214571Sdim
961214571Sdimint main (int, char **);
962214571Sdim
963214571Sdimint
964214571Sdimmain (int argc, char **argv)
965214571Sdim{
966214571Sdim  FILE *h_fp;
967214571Sdim  int c;
968214571Sdim  char *target, *input_filename;
969214571Sdim  int verbose;
970214571Sdim
971214571Sdim#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
972214571Sdim  setlocale (LC_MESSAGES, "");
973214571Sdim#endif
974214571Sdim#if defined (HAVE_SETLOCALE)
975214571Sdim  setlocale (LC_CTYPE, "");
976214571Sdim#endif
977214571Sdim  bindtextdomain (PACKAGE, LOCALEDIR);
978214571Sdim  textdomain (PACKAGE);
979214571Sdim
980214571Sdim  program_name = argv[0];
981214571Sdim  xmalloc_set_program_name (program_name);
982214571Sdim
983214571Sdim  expandargv (&argc, &argv);
984214571Sdim
985214571Sdim  bfd_init ();
986214571Sdim  set_default_bfd_target ();
987214571Sdim
988214571Sdim  target = NULL;
989214571Sdim  verbose = 0;
990214571Sdim  input_filename = NULL;
991214571Sdim
992214571Sdim  res_init ();
993214571Sdim
994214571Sdim  while ((c = getopt_long (argc, argv, "C:F:O:h:e:m:r:x:aAbcdHunoUvV", long_options,
995214571Sdim			   (int *) 0)) != EOF)
996214571Sdim    {
997214571Sdim      switch (c)
998214571Sdim	{
999214571Sdim	case 'b':
1000214571Sdim	  mcset_prefix_bin = 1;
1001214571Sdim	  break;
1002214571Sdim	case 'e':
1003214571Sdim	  {
1004214571Sdim	    mcset_header_ext = optarg;
1005214571Sdim	    if (mcset_header_ext[0] != '.' && mcset_header_ext[0] != 0)
1006214571Sdim	      {
1007214571Sdim		char *hsz = xmalloc (strlen (mcset_header_ext) + 2);
1008214571Sdim
1009214571Sdim		sprintf (hsz, ".%s", mcset_header_ext);
1010214571Sdim		mcset_header_ext = hsz;
1011214571Sdim	      }
1012214571Sdim	  }
1013214571Sdim	  break;
1014214571Sdim	case 'h':
1015214571Sdim	  mcset_header_dir = mc_unify_path (optarg);
1016214571Sdim	  break;
1017214571Sdim	case 'r':
1018214571Sdim	  mcset_rc_dir = mc_unify_path (optarg);
1019214571Sdim	  break;
1020214571Sdim	case 'a':
1021214571Sdim	  mcset_text_in_is_unicode = 0;
1022214571Sdim	  break;
1023214571Sdim	case 'x':
1024214571Sdim	  if (*optarg != 0)
1025214571Sdim	    mcset_dbg_dir = mc_unify_path (optarg);
1026214571Sdim	  break;
1027214571Sdim	case 'A':
1028214571Sdim	  mcset_bin_out_is_unicode = 0;
1029214571Sdim	  break;
1030214571Sdim	case 'd':
1031214571Sdim	  mcset_out_values_are_decimal = 1;
1032214571Sdim	  break;
1033214571Sdim	case 'u':
1034214571Sdim	  mcset_text_in_is_unicode = 1;
1035214571Sdim	  break;
1036214571Sdim	case 'U':
1037214571Sdim	  mcset_bin_out_is_unicode = 1;
1038214571Sdim	  break;
1039214571Sdim	case 'c':
1040214571Sdim	  mcset_custom_bit = 1;
1041214571Sdim	  break;
1042214571Sdim	case 'n':
1043214571Sdim	  mcset_automatic_null_termination = 1;
1044214571Sdim	  break;
1045214571Sdim	case 'o':
1046214571Sdim	  mcset_use_hresult = 1;
1047214571Sdim	  fatal ("option -o is not implemented until yet.\n");
1048214571Sdim	  break;
1049214571Sdim	case 'F':
1050214571Sdim	  target = optarg;
1051214571Sdim	  break;
1052214571Sdim	case 'v':
1053214571Sdim	  verbose ++;
1054214571Sdim	  break;
1055214571Sdim	case 'm':
1056214571Sdim	  mcset_max_message_length = strtol (optarg, (char **) NULL, 10);
1057214571Sdim	  break;
1058214571Sdim	case 'C':
1059214571Sdim	  mcset_codepage_in = strtol (optarg, (char **) NULL, 10);
1060214571Sdim	  break;
1061214571Sdim	case 'O':
1062214571Sdim	  mcset_codepage_out = strtol (optarg, (char **) NULL, 10);
1063214571Sdim	  break;
1064214571Sdim	case '?':
1065214571Sdim	case 'H':
1066214571Sdim	  usage (stdout, 0);
1067214571Sdim	  break;
1068214571Sdim	case 'V':
1069214571Sdim	  print_version ("windmc");
1070214571Sdim	  break;
1071214571Sdim
1072214571Sdim	default:
1073214571Sdim	  usage (stderr, 1);
1074214571Sdim	  break;
1075214571Sdim	}
1076214571Sdim    }
1077214571Sdim  if (input_filename == NULL && optind < argc)
1078214571Sdim    {
1079214571Sdim      input_filename = argv[optind];
1080214571Sdim      ++optind;
1081214571Sdim    }
1082214571Sdim
1083214571Sdim  set_endianess (NULL, target);
1084214571Sdim
1085214571Sdim  if (input_filename == NULL)
1086214571Sdim    {
1087214571Sdim      fprintf (stderr, "Error: No input file was specified.\n");
1088214571Sdim      usage (stderr, 1);
1089214571Sdim    }
1090214571Sdim  mc_set_inputfile (input_filename);
1091214571Sdim
1092214571Sdim  if (!probe_codepage (&mcset_codepage_in, &mcset_text_in_is_unicode, "codepage_in", 0))
1093214571Sdim    usage (stderr, 1);
1094214571Sdim  if (mcset_codepage_out == 0)
1095214571Sdim    mcset_codepage_out = 1252;
1096214571Sdim  if (! unicode_is_valid_codepage (mcset_codepage_out))
1097214571Sdim    fatal ("Code page 0x%x is unknown.", (unsigned int) mcset_codepage_out);
1098214571Sdim  if (mcset_codepage_out == CP_UTF16)
1099214571Sdim    fatal ("UTF16 is no valid text output code page.");
1100214571Sdim  if (verbose)
1101214571Sdim    {
1102214571Sdim      fprintf (stderr, "// Default target is %s and it is %s endian.\n",
1103214571Sdim	def_target_arch, (target_is_bigendian ? "big" : "little"));
1104214571Sdim      fprintf (stderr, "// Input codepage: 0x%x\n", (unsigned int) mcset_codepage_in);
1105214571Sdim      fprintf (stderr, "// Output codepage: 0x%x\n", (unsigned int) mcset_codepage_out);
1106214571Sdim    }
1107214571Sdim
1108214571Sdim  if (argc != optind)
1109214571Sdim    usage (stderr, 1);
1110214571Sdim
1111214571Sdim  /* Initialize mcset_mc_basename.  */
1112214571Sdim  {
1113214571Sdim    const char *bn, *bn2;
1114214571Sdim    char *hsz;
1115214571Sdim
1116214571Sdim    bn = strrchr (input_filename, '/');
1117214571Sdim    bn2 = strrchr (input_filename, '\\');
1118214571Sdim    if (! bn)
1119214571Sdim      bn = bn2;
1120214571Sdim    if (bn && bn2 && bn < bn2)
1121214571Sdim      bn = bn2;
1122214571Sdim    if (! bn)
1123214571Sdim      bn = input_filename;
1124214571Sdim    else
1125214571Sdim      bn++;
1126214571Sdim    mcset_mc_basename = hsz = xstrdup (bn);
1127214571Sdim
1128214571Sdim    /* Cut of right-hand extension.  */
1129214571Sdim    if ((hsz = strrchr (hsz, '.')) != NULL)
1130214571Sdim      *hsz = 0;
1131214571Sdim  }
1132214571Sdim
1133214571Sdim  /* Load the input file and do code page transformations to UTF16.  */
1134214571Sdim  {
1135214571Sdim    unichar *u;
1136214571Sdim    rc_uint_type ul;
1137214571Sdim    char *buff;
1138214571Sdim    long flen;
1139214571Sdim    FILE *fp = fopen (input_filename, "rb");
1140214571Sdim
1141214571Sdim    if (!fp)
1142214571Sdim      fatal (_("unable to open file ,%s' for input.\n"), input_filename);
1143214571Sdim
1144214571Sdim    fseek (fp, 0, SEEK_END);
1145214571Sdim    flen = ftell (fp);
1146214571Sdim    fseek (fp, 0, SEEK_SET);
1147214571Sdim    buff = malloc (flen + 3);
1148214571Sdim    memset (buff, 0, flen + 3);
1149214571Sdim    fread (buff, 1, flen, fp);
1150214571Sdim    fclose (fp);
1151214571Sdim    if (mcset_text_in_is_unicode != 1)
1152214571Sdim      {
1153214571Sdim	unicode_from_codepage (&ul, &u, buff, mcset_codepage_in);
1154214571Sdim	if (! u)
1155214571Sdim	  fatal ("Failed to convert input to UFT16\n");
1156214571Sdim	mc_set_content (u);
1157214571Sdim      }
1158214571Sdim    else
1159214571Sdim      {
1160214571Sdim	if ((flen & 1) != 0)
1161214571Sdim	  fatal (_("input file does not seems to be UFT16.\n"));
1162214571Sdim	mc_set_content ((unichar *) buff);
1163214571Sdim      }
1164214571Sdim    free (buff);
1165214571Sdim  }
1166214571Sdim
1167214571Sdim  while (yyparse ())
1168214571Sdim    ;
1169214571Sdim
1170214571Sdim  do_sorts ();
1171214571Sdim
1172214571Sdim  h_fp = mc_create_path_text_file (mcset_header_dir, mcset_header_ext);
1173214571Sdim  write_header (h_fp);
1174214571Sdim  fclose (h_fp);
1175214571Sdim
1176214571Sdim  h_fp = mc_create_path_text_file (mcset_rc_dir, ".rc");
1177214571Sdim  write_rc (h_fp);
1178214571Sdim  fclose (h_fp);
1179214571Sdim
1180214571Sdim  if (mcset_dbg_dir != NULL)
1181214571Sdim    {
1182214571Sdim      h_fp = mc_create_path_text_file (mcset_dbg_dir, ".dbg");
1183214571Sdim      write_dbg (h_fp);
1184214571Sdim      fclose (h_fp);
1185214571Sdim    }
1186214571Sdim  write_bin ();
1187214571Sdim
1188214571Sdim  if (mc_nodes_lang)
1189214571Sdim    free (mc_nodes_lang);
1190214571Sdim  if (mc_severity_codes)
1191214571Sdim    free (mc_severity_codes);
1192214571Sdim  if (mc_facility_codes)
1193214571Sdim    free (mc_facility_codes);
1194214571Sdim
1195214571Sdim  xexit (0);
1196214571Sdim  return 0;
1197214571Sdim}
1198