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