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