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