gdb/
[deliverable/binutils-gdb.git] / binutils / windmc.c
CommitLineData
692ed3e7 1/* windmc.c -- a program to compile Windows message files.
cc643b88 2 Copyright 2007, 2008, 2009, 2010, 2011
692ed3e7
NC
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
32866df7 10 the Free Software Foundation; either version 3 of the License, or
692ed3e7
NC
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
32866df7 23
692ed3e7
NC
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. */
47typedef 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
692ed3e7
NC
54int target_is_bigendian = 0;
55const char *def_target_arch;
56
57/* Globals and static variable definitions. */
58
59/* bfd global helper struct variable. */
60static struct
61{
62 bfd *abfd;
63 asection *sec;
64} mc_bfd;
65
66/* Memory list. */
67mc_node *mc_nodes = NULL;
68static mc_node_lang **mc_nodes_lang = NULL;
69static int mc_nodes_lang_count = 0;
70static mc_keyword **mc_severity_codes = NULL;
71static int mc_severity_codes_count = 0;
72static mc_keyword **mc_facility_codes = NULL;
73static 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. */
81static struct obstack res_obstack;
82
83/* Flag variables. */
84/* Set by -C. Set the default code page to be used for input text file. */
85static rc_uint_type mcset_codepage_in = 0;
86
87/* Set by -O. Set the default code page to be used for output text files. */
88static rc_uint_type mcset_codepage_out = 0;
89
90/* Set by -b. .BIN filename should have .mc filename_ included for uniqueness. */
91static int mcset_prefix_bin = 0;
92
93/* The base name of the .mc file. */
94static const char *mcset_mc_basename = "unknown";
95
96/* Set by -e <ext>. Specify the extension for the header file. */
97static const char *mcset_header_ext = ".h";
98
99/* Set by -h <path>. Gives the path of where to create the C include file. */
100static 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. */
104static const char *mcset_rc_dir = "./";
105
106/* Modified by -a & -u. By -u input file is unicode, by -a is ASCII (default). */
107static int mcset_text_in_is_unicode = 0;
108
109/* Modified by -A & -U. By -U bin file is unicode (default), by -A is ASCII. */
110static int mcset_bin_out_is_unicode = 1;
111
112/* Set by -c. Sets the Customer bit in all the message ID's. */
113int mcset_custom_bit = 0;
114
115/* Set by -o. Generate OLE2 header file. Use HRESULT definition instead of
116 status code definition. */
117static int mcset_use_hresult = 0;
118
119/* Set by -m <msglen>. Generate a warning if the size of any message exceeds
120 maxmsglen characters. */
121rc_uint_type mcset_max_message_length = 0;
122
123/* Set by -d. Sets message values in header to decimal initially. */
124int mcset_out_values_are_decimal = 0;
125
126/* Set by -n. terminates all strings with null's in the message tables. */
127static int mcset_automatic_null_termination = 0;
128
129/* The type used for message id output in header. */
130unichar *mcset_msg_id_typedef = NULL;
131
132/* Set by -x path. Geberated debug C file for mapping ID's to text. */
133static const char *mcset_dbg_dir = NULL;
134
135/* getopt long name definitions. */
136static 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. */
163static void
164res_init (void)
165{
166 obstack_init (&res_obstack);
167}
168
169/* Allocate space on the resource building obstack. */
170void *
171res_alloc (rc_uint_type bytes)
172{
78aff5a5 173 return obstack_alloc (&res_obstack, (size_t) bytes);
692ed3e7
NC
174}
175
176static FILE *
177mc_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)
426fb1a6 190 fatal (_("can't create %s file `%s' for output.\n"), (ext ? ext : "text"), hsz);
692ed3e7
NC
191 free (hsz);
192 return ret;
193}
194
195static void
196usage (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\
cc643b88 208 -F --target <target> Specify output target for endianness.\n\
692ed3e7
NC
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
233static void
cc643b88 234set_endianness (bfd *abfd, const char *target)
692ed3e7
NC
235{
236 const bfd_target *target_vec;
237
238 def_target_arch = NULL;
c4d1af07
KT
239 target_vec = bfd_get_target_info (target, abfd, &target_is_bigendian, NULL,
240 &def_target_arch);
692ed3e7 241 if (! target_vec)
cc643b88 242 fatal ("Can't detect target endianness and architecture.");
c4d1af07
KT
243 if (! def_target_arch)
244 fatal ("Can't detect architecture.");
692ed3e7
NC
245}
246
247static int
248probe_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);
426fb1a6 262 fprintf (stderr, _("A codepage was specified switch `%s' and UTF16.\n"), pswitch);
692ed3e7
NC
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
281mc_node *
282mc_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
301mc_node_lang *
302mc_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
339static char *
340convert_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)
0af1713e
AM
349 fatal ("unicode string not mappable to ASCII codepage 0x%lx.\n",
350 (unsigned long) mcset_codepage_out);
692ed3e7
NC
351 return s;
352}
353
354static void
355write_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
370static void
371write_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
401static int
402sort_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
422static int
423sort_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
453static void
454do_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
523static int
524mc_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
543static bfd *
544windmc_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
555static void
556target_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
566static void
567target_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
577static struct bin_messagetable_item *
578mc_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
633static void
634mc_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
657static void
658set_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
664static void
665windmc_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);
0eb80fd3
AM
676 mc_bfd.sec = bfd_make_section_with_flags (mc_bfd.abfd, ".data",
677 (SEC_HAS_CONTENTS | SEC_ALLOC
678 | SEC_LOAD | SEC_DATA));
692ed3e7
NC
679 if (mc_bfd.sec == NULL)
680 bfd_fatal ("bfd_make_section");
692ed3e7
NC
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
723static void
724write_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
765static void
766write_rc (FILE *fp)
767{
768 mc_node_lang *n;
769 int i, l;
770
771 fprintf (fp,
0af1713e
AM
772 "/* Do not edit this file manually.\n"
773 " This file is autogenerated by windmc. */\n\n");
692ed3e7
NC
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",
0af1713e
AM
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));
692ed3e7
NC
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
798static void
799write_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
838static void
839write_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
917static const char *
918mc_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
935int main (int, char **);
936
937int
938main (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
cc643b88 1057 set_endianness (NULL, target);
692ed3e7
NC
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;
20359e08 1112 bfd_size_type flen;
692ed3e7
NC
1113 FILE *fp = fopen (input_filename, "rb");
1114
1115 if (!fp)
426fb1a6 1116 fatal (_("unable to open file `%s' for input.\n"), input_filename);
692ed3e7
NC
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);
20359e08
NC
1123 if (fread (buff, 1, flen, fp) < flen)
1124 fatal (_("unable to read contents of %s"), input_filename);
692ed3e7
NC
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}
This page took 0.241533 seconds and 4 git commands to generate.