]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - binutils/windmc.c
2009-11-16 Kai Tietz <kai.tietz@onevision.com>
[thirdparty/binutils-gdb.git] / binutils / windmc.c
CommitLineData
692ed3e7 1/* windmc.c -- a program to compile Windows message files.
8b31b6c4 2 Copyright 2007, 2008, 2009
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)
190 fatal (_("can't create %s file ,%s' for output.\n"), (ext ? ext : "text"), hsz);
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\
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
233static void
234set_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);
d25576aa 243
692ed3e7 244 {
d25576aa
NC
245 const char * tname = target_vec->name;
246 const char ** arches = bfd_arch_list ();
692ed3e7 247
d25576aa 248 if (arches && tname)
692ed3e7 249 {
d25576aa
NC
250 const char ** arch = arches;
251
692ed3e7
NC
252 if (strchr (tname, '-') != NULL)
253 tname = strchr (tname, '-') + 1;
d25576aa 254
692ed3e7
NC
255 while (*arch != NULL)
256 {
257 const char *in_a = strstr (*arch, tname);
258 char end_ch = (in_a ? in_a[strlen (tname)] : 0);
d25576aa 259
692ed3e7
NC
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 }
d25576aa
NC
269
270 free (arches);
271
692ed3e7
NC
272 if (! def_target_arch)
273 fatal ("Can't detect architecture.");
274 }
275}
276
277static int
278probe_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
311mc_node *
312mc_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
331mc_node_lang *
332mc_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
369static char *
370convert_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)
0af1713e
AM
379 fatal ("unicode string not mappable to ASCII codepage 0x%lx.\n",
380 (unsigned long) mcset_codepage_out);
692ed3e7
NC
381 return s;
382}
383
384static void
385write_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
400static void
401write_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
431static int
432sort_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
452static int
453sort_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
483static void
484do_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
553static int
554mc_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
573static bfd *
574windmc_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
585static void
586target_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
596static void
597target_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
607static struct bin_messagetable_item *
608mc_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
663static void
664mc_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
687static void
688set_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
694static void
695windmc_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);
0eb80fd3
AM
706 mc_bfd.sec = bfd_make_section_with_flags (mc_bfd.abfd, ".data",
707 (SEC_HAS_CONTENTS | SEC_ALLOC
708 | SEC_LOAD | SEC_DATA));
692ed3e7
NC
709 if (mc_bfd.sec == NULL)
710 bfd_fatal ("bfd_make_section");
692ed3e7
NC
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
753static void
754write_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
795static void
796write_rc (FILE *fp)
797{
798 mc_node_lang *n;
799 int i, l;
800
801 fprintf (fp,
0af1713e
AM
802 "/* Do not edit this file manually.\n"
803 " This file is autogenerated by windmc. */\n\n");
692ed3e7
NC
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",
0af1713e
AM
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));
692ed3e7
NC
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
828static void
829write_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
868static void
869write_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
947static const char *
948mc_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
965int main (int, char **);
966
967int
968main (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;
20359e08 1142 bfd_size_type flen;
692ed3e7
NC
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);
20359e08
NC
1153 if (fread (buff, 1, flen, fp) < flen)
1154 fatal (_("unable to read contents of %s"), input_filename);
692ed3e7
NC
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}