gas/testsuite/
[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);
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)
384 fatal ("unicode string not mappable to ASCII codepage 0x%lx.\n", (long) mcset_codepage_out);
385 return s;
386}
387
388static void
389write_dbg_define (FILE *fp, const unichar *sym_name, const unichar *typecast)
390{
391 char *sym;
392
393 if (!sym_name || sym_name[0] == 0)
394 return;
395 sym = convert_unicode_to_ACP (sym_name);
396 fprintf (fp, " {(");
397 if (typecast)
398 unicode_print (fp, typecast, unichar_len (typecast));
399 else
400 fprintf (fp, "DWORD");
401 fprintf (fp, ") %s, \"%s\" },\n", sym, sym);
402}
403
404static void
405write_header_define (FILE *fp, const unichar *sym_name, rc_uint_type vid, const unichar *typecast, mc_node_lang *nl)
406{
407 char *sym;
408 char *tdef = NULL;
409
410 if (!sym_name || sym_name[0] == 0)
411 {
412 if (nl != NULL)
413 {
414 if (mcset_out_values_are_decimal)
415 fprintf (fp, "//\n// MessageId: 0x%lu\n//\n", (unsigned long) vid);
416 else
417 fprintf (fp, "//\n// MessageId: 0x%lx\n//\n", (unsigned long) vid);
418 }
419 return;
420 }
421 sym = convert_unicode_to_ACP (sym_name);
422 if (typecast && typecast[0] != 0)
423 tdef = convert_unicode_to_ACP (typecast);
424 fprintf (fp, "//\n// MessageId: %s\n//\n", sym);
425 if (! mcset_out_values_are_decimal)
426 fprintf (fp, "#define %s %s%s%s 0x%lx\n\n", sym,
427 (tdef ? "(" : ""), (tdef ? tdef : ""), (tdef ? ")" : ""),
428 (unsigned long) vid);
429 else
430 fprintf (fp, "#define %s %s%s%s 0x%lu\n\n", sym,
431 (tdef ? "(" : ""), (tdef ? tdef : ""), (tdef ? ")" : ""),
432 (unsigned long) vid);
433}
434
435static int
436sort_mc_node_lang (const void *l, const void *r)
437{
438 const mc_node_lang *l1 = *((const mc_node_lang **)l);
439 const mc_node_lang *r1 = *((const mc_node_lang **)r);
440
441 if (l == r)
442 return 0;
443 if (l1->lang != r1->lang)
444 {
445 if (l1->lang->nval < r1->lang->nval)
446 return -1;
447 return 1;
448 }
449 if (l1->vid == r1->vid)
450 return 0;
451 if (l1->vid < r1->vid)
452 return -1;
453 return 1;
454}
455
456static int
457sort_keyword_by_nval (const void *l, const void *r)
458{
459 const mc_keyword *l1 = *((const mc_keyword **)l);
460 const mc_keyword *r1 = *((const mc_keyword **)r);
461 rc_uint_type len1, len2;
462 int e;
463
464 if (l == r)
465 return 0;
466 if (l1->nval != r1->nval)
467 {
468 if (l1->nval < r1->nval)
469 return -1;
470 return 1;
471 }
472 len1 = unichar_len (l1->usz);
473 len2 = unichar_len (r1->usz);
474 if (len1 <= len2)
475 e = memcmp (l1->usz, r1->usz, sizeof (unichar) * len1);
476 else
477 e = memcmp (l1->usz, r1->usz, sizeof (unichar) * len2);
478 if (e)
479 return e;
480 if (len1 < len2)
481 return -1;
482 else if (len1 > len2)
483 return 1;
484 return 0;
485}
486
487static void
488do_sorts (void)
489{
490 mc_node *h;
491 mc_node_lang *n;
492 const mc_keyword *k;
493 int i;
494
495 /* Sort message by their language and id ascending. */
496 mc_nodes_lang_count = 0;
497
498 h = mc_nodes;
499 while (h != NULL)
500 {
501 n = h->sub;
502 while (n != NULL)
503 {
504 mc_nodes_lang_count +=1;
505 n = n->next;
506 }
507 h = h->next;
508 }
509
510 if (mc_nodes_lang_count != 0)
511 {
512 h = mc_nodes;
513 i = 0;
514 mc_nodes_lang = xmalloc (sizeof (mc_node_lang *) * mc_nodes_lang_count);
515
516 while (h != NULL)
517 {
518 n = h->sub;
519 while (n != NULL)
520 {
521 mc_nodes_lang[i++] = n;
522 n = n->next;
523 }
524 h = h->next;
525 }
526 qsort (mc_nodes_lang, (size_t) mc_nodes_lang_count, sizeof (mc_node_lang *), sort_mc_node_lang);
527 }
528 /* Sort facility code definitions by there id ascending. */
529 i = 0;
530 while ((k = enum_facility (i)) != NULL)
531 ++i;
532 mc_facility_codes_count = i;
533 if (i != 0)
534 {
535 mc_facility_codes = xmalloc (sizeof (mc_keyword *) * i);
536 i = 0;
537 while ((k = enum_facility (i)) != NULL)
538 mc_facility_codes[i++] = (mc_keyword *) k;
539 qsort (mc_facility_codes, (size_t) mc_facility_codes_count, sizeof (mc_keyword *), sort_keyword_by_nval);
540 }
541
542 /* Sort severity code definitions by there id ascending. */
543 i = 0;
544 while ((k = enum_severity (i)) != NULL)
545 ++i;
546 mc_severity_codes_count = i;
547 if (i != 0)
548 {
549 mc_severity_codes = xmalloc (sizeof (mc_keyword *) * i);
550 i = 0;
551 while ((k = enum_severity (i)) != NULL)
552 mc_severity_codes[i++] = (mc_keyword *) k;
553 qsort (mc_severity_codes, (size_t) mc_severity_codes_count, sizeof (mc_keyword *), sort_keyword_by_nval);
554 }
555}
556
557static int
558mc_get_block_count (mc_node_lang **nl, int elems)
559{
560 rc_uint_type exid;
561 int i, ret;
562
563 if (! nl)
564 return 0;
565 i = 0;
566 ret = 0;
567 while (i < elems)
568 {
569 ret++;
570 exid = nl[i++]->vid;
571 while (i < elems && nl[i]->vid == exid + 1)
572 exid = nl[i++]->vid;
573 }
574 return ret;
575}
576
577static bfd *
578windmc_open_as_binary (const char *filename)
579{
580 bfd *abfd;
581
582 abfd = bfd_openw (filename, "binary");
583 if (! abfd)
584 fatal ("can't open `%s' for output", filename);
585
586 return abfd;
587}
588
589static void
590target_put_16 (void *p, rc_uint_type value)
591{
592 assert (!! p);
593
594 if (target_is_bigendian)
595 bfd_putb16 (value, p);
596 else
597 bfd_putl16 (value, p);
598}
599
600static void
601target_put_32 (void *p, rc_uint_type value)
602{
603 assert (!! p);
604
605 if (target_is_bigendian)
606 bfd_putb32 (value, p);
607 else
608 bfd_putl32 (value, p);
609}
610
611static struct bin_messagetable_item *
612mc_generate_bin_item (mc_node_lang *n, rc_uint_type *res_len)
613{
614 struct bin_messagetable_item *ret = NULL;
615 rc_uint_type len;
616
617 *res_len = 0;
618 if (mcset_bin_out_is_unicode == 1)
619 {
620 unichar *ht = n->message;
621 rc_uint_type txt_len;
622
623 txt_len = unichar_len (n->message);
624 if (mcset_automatic_null_termination && txt_len != 0)
625 {
626 while (txt_len > 0 && ht[txt_len - 1] > 0 && ht[txt_len - 1] < 0x20)
627 ht[--txt_len] = 0;
628 }
629 txt_len *= sizeof (unichar);
630 len = BIN_MESSAGETABLE_ITEM_SIZE + txt_len + sizeof (unichar);
631 ret = res_alloc ((len + 3) & ~3);
632 memset (ret, 0, (len + 3) & ~3);
633 target_put_16 (ret->length, (len + 3) & ~3);
634 target_put_16 (ret->flags, MESSAGE_RESOURCE_UNICODE);
635 txt_len = 0;
636 while (*ht != 0)
637 {
638 target_put_16 (ret->data + txt_len, *ht++);
639 txt_len += 2;
640 }
641 }
642 else
643 {
644 rc_uint_type txt_len, l;
645 char *cvt_txt;
646
647 codepage_from_unicode( &l, n->message, &cvt_txt, n->lang->lang_info.wincp);
648 if (! cvt_txt)
649 fatal ("Failed to convert message to language codepage.\n");
650 txt_len = strlen (cvt_txt);
651 if (mcset_automatic_null_termination && txt_len > 0)
652 {
653 while (txt_len > 0 && cvt_txt[txt_len - 1] > 0 && cvt_txt[txt_len - 1] < 0x20)
654 cvt_txt[--txt_len] = 0;
655 }
656 len = BIN_MESSAGETABLE_ITEM_SIZE + txt_len + 1;
657 ret = res_alloc ((len + 3) & ~3);
658 memset (ret, 0, (len + 3) & ~3);
659 target_put_16 (ret->length, (len + 3) & ~3);
660 target_put_16 (ret->flags, 0);
661 strcpy ((char *) ret->data, cvt_txt);
662 }
663 *res_len = (len + 3) & ~3;
664 return ret;
665}
666
667static void
668mc_write_blocks (struct bin_messagetable *mtbl, mc_node_lang **nl, mc_msg_item *ml, int elems)
669{
670 int i, idx = 0;
671 rc_uint_type exid;
672
673 if (! nl)
674 return;
675 i = 0;
676 while (i < elems)
677 {
678 target_put_32 (mtbl->items[idx].lowid, nl[i]->vid);
679 target_put_32 (mtbl->items[idx].highid, nl[i]->vid);
680 target_put_32 (mtbl->items[idx].offset, ml[i].res_off);
681 exid = nl[i++]->vid;
682 while (i < elems && nl[i]->vid == exid + 1)
683 {
684 target_put_32 (mtbl->items[idx].highid, nl[i]->vid);
685 exid = nl[i++]->vid;
686 }
687 ++idx;
688 }
689}
690
691static void
692set_windmc_bfd_content (const void *data, rc_uint_type off, rc_uint_type length)
693{
694 if (! bfd_set_section_contents (mc_bfd.abfd, mc_bfd.sec, data, off, length))
695 bfd_fatal ("bfd_set_section_contents");
696}
697
698static void
699windmc_write_bin (const char *filename, mc_node_lang **nl, int elems)
700{
701 unsigned long sec_length = 1;
702 int block_count, i;
703 mc_msg_item *mi;
704 struct bin_messagetable *mtbl;
705 rc_uint_type dta_off, dta_start;
706
707 if (elems <= 0)
708 return;
709 mc_bfd.abfd = windmc_open_as_binary (filename);
710 mc_bfd.sec = bfd_make_section (mc_bfd.abfd, ".data");
711 if (mc_bfd.sec == NULL)
712 bfd_fatal ("bfd_make_section");
713 if (! bfd_set_section_flags (mc_bfd.abfd, mc_bfd.sec,
714 (SEC_HAS_CONTENTS | SEC_ALLOC
715 | SEC_LOAD | SEC_DATA)))
716 bfd_fatal ("bfd_set_section_flags");
717 /* Requiring this is probably a bug in BFD. */
718 mc_bfd.sec->output_section = mc_bfd.sec;
719
720 block_count = mc_get_block_count (nl, elems);
721
722 dta_off = (rc_uint_type) ((BIN_MESSAGETABLE_BLOCK_SIZE * block_count) + BIN_MESSAGETABLE_SIZE - 4);
723 dta_start = dta_off = (dta_off + 3) & ~3;
724 mi = xmalloc (sizeof (mc_msg_item) * elems);
725 mtbl = xmalloc (dta_start);
726
727 /* Clear header region. */
728 memset (mtbl, 0, dta_start);
729 target_put_32 (mtbl->cblocks, block_count);
730 /* Prepare items section for output. */
731 for (i = 0; i < elems; i++)
732 {
733 mi[i].res_off = dta_off;
734 mi[i].res = mc_generate_bin_item (nl[i], &mi[i].res_len);
735 dta_off += mi[i].res_len;
736 }
737 sec_length = (dta_off + 3) & ~3;
738 if (! bfd_set_section_size (mc_bfd.abfd, mc_bfd.sec, sec_length))
739 bfd_fatal ("bfd_set_section_size");
740 /* Make sure we write the complete block. */
741 set_windmc_bfd_content ("\0", sec_length - 1, 1);
742
743 /* Write block information. */
744 mc_write_blocks (mtbl, nl, mi, elems);
745
746 set_windmc_bfd_content (mtbl, 0, dta_start);
747
748 /* Write items. */
749 for (i = 0; i < elems; i++)
750 set_windmc_bfd_content (mi[i].res, mi[i].res_off, mi[i].res_len);
751
752 free (mtbl);
753 free (mi);
754 bfd_close (mc_bfd.abfd);
755 mc_bfd.abfd = NULL;
756 mc_bfd.sec = NULL;
757}
758
759static void
760write_bin (void)
761{
762 mc_node_lang *n = NULL;
763 int i, c;
764
765 if (! mc_nodes_lang_count)
766 return;
767
768 i = 0;
769 while (i < mc_nodes_lang_count)
770 {
771 char *nd;
772 char *filename;
773
774 if (n && n->lang == mc_nodes_lang[i]->lang)
775 {
776 i++;
777 continue;
778 }
779 n = mc_nodes_lang[i];
780 c = i + 1;
781 while (c < mc_nodes_lang_count && n->lang == mc_nodes_lang[c]->lang)
782 c++;
783 nd = convert_unicode_to_ACP (n->lang->sval);
784
785 /* Prepare filename for binary output. */
786 filename = xmalloc (strlen (nd) + 4 + 1 + strlen (mcset_mc_basename) + 1 + strlen (mcset_rc_dir));
787 strcpy (filename, mcset_rc_dir);
788 if (mcset_prefix_bin)
789 sprintf (filename + strlen (filename), "%s_", mcset_mc_basename);
790 strcat (filename, nd);
791 strcat (filename, ".bin");
792
793 /* Write message file. */
794 windmc_write_bin (filename, &mc_nodes_lang[i], (c - i));
795
796 free (filename);
797 i = c;
798 }
799}
800
801static void
802write_rc (FILE *fp)
803{
804 mc_node_lang *n;
805 int i, l;
806
807 fprintf (fp,
808 "/* Do not edit this file manually.\n"
809 " This file is autogenerated by windmc. */\n\n");
810 if (! mc_nodes_lang_count)
811 return;
812 n = NULL;
813 i = 0;
814 for (l = 0; l < mc_nodes_lang_count; l++)
815 {
816 if (n && n->lang == mc_nodes_lang[l]->lang)
817 continue;
818 ++i;
819 n = mc_nodes_lang[l];
820 fprintf (fp, "\n// Country: %s\n// Language: %s\n#pragma code_page(%u)\n",
821 n->lang->lang_info.country, n->lang->lang_info.name,
822 (unsigned) n->lang->lang_info.wincp);
823 fprintf (fp, "LANGUAGE 0x%lx, 0x%lx\n", (long) (n->lang->nval & 0x3ff),
824 (long) ((n->lang->nval & 0xffff) >> 10));
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;
1147 long flen;
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);
1158 fread (buff, 1, flen, fp);
1159 fclose (fp);
1160 if (mcset_text_in_is_unicode != 1)
1161 {
1162 unicode_from_codepage (&ul, &u, buff, mcset_codepage_in);
1163 if (! u)
1164 fatal ("Failed to convert input to UFT16\n");
1165 mc_set_content (u);
1166 }
1167 else
1168 {
1169 if ((flen & 1) != 0)
1170 fatal (_("input file does not seems to be UFT16.\n"));
1171 mc_set_content ((unichar *) buff);
1172 }
1173 free (buff);
1174 }
1175
1176 while (yyparse ())
1177 ;
1178
1179 do_sorts ();
1180
1181 h_fp = mc_create_path_text_file (mcset_header_dir, mcset_header_ext);
1182 write_header (h_fp);
1183 fclose (h_fp);
1184
1185 h_fp = mc_create_path_text_file (mcset_rc_dir, ".rc");
1186 write_rc (h_fp);
1187 fclose (h_fp);
1188
1189 if (mcset_dbg_dir != NULL)
1190 {
1191 h_fp = mc_create_path_text_file (mcset_dbg_dir, ".dbg");
1192 write_dbg (h_fp);
1193 fclose (h_fp);
1194 }
1195 write_bin ();
1196
1197 if (mc_nodes_lang)
1198 free (mc_nodes_lang);
1199 if (mc_severity_codes)
1200 free (mc_severity_codes);
1201 if (mc_facility_codes)
1202 free (mc_facility_codes);
1203
1204 xexit (0);
1205 return 0;
1206}
This page took 0.15441 seconds and 4 git commands to generate.