gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / binutils / windmc.c
CommitLineData
692ed3e7 1/* windmc.c -- a program to compile Windows message files.
b3adc24a 2 Copyright (C) 2007-2020 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;
fd361982 701 if (!bfd_set_section_size (mc_bfd.sec, sec_length))
692ed3e7
NC
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)
913e0fd4 824 write_dbg_define (fp, h->symbol, h->id_typecast);
692ed3e7
NC
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)
913e0fd4 911 write_header_define (fp, h->symbol, h->vid, h->id_typecast, h->sub);
692ed3e7
NC
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);
86eafac0 955 bfd_set_error_program_name (program_name);
692ed3e7
NC
956
957 expandargv (&argc, &argv);
958
bf2dd8d7
AM
959 if (bfd_init () != BFD_INIT_MAGIC)
960 fatal (_("fatal error: libbfd ABI mismatch"));
692ed3e7
NC
961 set_default_bfd_target ();
962
963 target = NULL;
964 verbose = 0;
965 input_filename = NULL;
966
967 res_init ();
968
969 while ((c = getopt_long (argc, argv, "C:F:O:h:e:m:r:x:aAbcdHunoUvV", long_options,
970 (int *) 0)) != EOF)
971 {
972 switch (c)
973 {
974 case 'b':
975 mcset_prefix_bin = 1;
976 break;
977 case 'e':
978 {
979 mcset_header_ext = optarg;
980 if (mcset_header_ext[0] != '.' && mcset_header_ext[0] != 0)
981 {
982 char *hsz = xmalloc (strlen (mcset_header_ext) + 2);
983
984 sprintf (hsz, ".%s", mcset_header_ext);
985 mcset_header_ext = hsz;
986 }
987 }
988 break;
989 case 'h':
990 mcset_header_dir = mc_unify_path (optarg);
991 break;
992 case 'r':
993 mcset_rc_dir = mc_unify_path (optarg);
994 break;
995 case 'a':
996 mcset_text_in_is_unicode = 0;
997 break;
998 case 'x':
999 if (*optarg != 0)
1000 mcset_dbg_dir = mc_unify_path (optarg);
1001 break;
1002 case 'A':
1003 mcset_bin_out_is_unicode = 0;
1004 break;
1005 case 'd':
1006 mcset_out_values_are_decimal = 1;
1007 break;
1008 case 'u':
1009 mcset_text_in_is_unicode = 1;
1010 break;
1011 case 'U':
1012 mcset_bin_out_is_unicode = 1;
1013 break;
1014 case 'c':
1015 mcset_custom_bit = 1;
1016 break;
1017 case 'n':
1018 mcset_automatic_null_termination = 1;
1019 break;
1020 case 'o':
1021 mcset_use_hresult = 1;
1022 fatal ("option -o is not implemented until yet.\n");
1023 break;
1024 case 'F':
1025 target = optarg;
1026 break;
1027 case 'v':
1028 verbose ++;
1029 break;
1030 case 'm':
1031 mcset_max_message_length = strtol (optarg, (char **) NULL, 10);
1032 break;
1033 case 'C':
1034 mcset_codepage_in = strtol (optarg, (char **) NULL, 10);
1035 break;
1036 case 'O':
1037 mcset_codepage_out = strtol (optarg, (char **) NULL, 10);
1038 break;
1039 case '?':
1040 case 'H':
1041 usage (stdout, 0);
1042 break;
1043 case 'V':
1044 print_version ("windmc");
1045 break;
1046
1047 default:
1048 usage (stderr, 1);
1049 break;
1050 }
1051 }
1052 if (input_filename == NULL && optind < argc)
1053 {
1054 input_filename = argv[optind];
1055 ++optind;
1056 }
1057
cc643b88 1058 set_endianness (NULL, target);
692ed3e7
NC
1059
1060 if (input_filename == NULL)
1061 {
1062 fprintf (stderr, "Error: No input file was specified.\n");
1063 usage (stderr, 1);
1064 }
1065 mc_set_inputfile (input_filename);
1066
1067 if (!probe_codepage (&mcset_codepage_in, &mcset_text_in_is_unicode, "codepage_in", 0))
1068 usage (stderr, 1);
1069 if (mcset_codepage_out == 0)
1070 mcset_codepage_out = 1252;
1071 if (! unicode_is_valid_codepage (mcset_codepage_out))
1072 fatal ("Code page 0x%x is unknown.", (unsigned int) mcset_codepage_out);
1073 if (mcset_codepage_out == CP_UTF16)
1074 fatal ("UTF16 is no valid text output code page.");
1075 if (verbose)
1076 {
1077 fprintf (stderr, "// Default target is %s and it is %s endian.\n",
1078 def_target_arch, (target_is_bigendian ? "big" : "little"));
1079 fprintf (stderr, "// Input codepage: 0x%x\n", (unsigned int) mcset_codepage_in);
1080 fprintf (stderr, "// Output codepage: 0x%x\n", (unsigned int) mcset_codepage_out);
1081 }
1082
1083 if (argc != optind)
1084 usage (stderr, 1);
1085
1086 /* Initialize mcset_mc_basename. */
1087 {
1088 const char *bn, *bn2;
1089 char *hsz;
1090
1091 bn = strrchr (input_filename, '/');
1092 bn2 = strrchr (input_filename, '\\');
1093 if (! bn)
1094 bn = bn2;
1095 if (bn && bn2 && bn < bn2)
1096 bn = bn2;
1097 if (! bn)
1098 bn = input_filename;
1099 else
1100 bn++;
1101 mcset_mc_basename = hsz = xstrdup (bn);
1102
1103 /* Cut of right-hand extension. */
1104 if ((hsz = strrchr (hsz, '.')) != NULL)
1105 *hsz = 0;
1106 }
1107
1108 /* Load the input file and do code page transformations to UTF16. */
1109 {
1110 unichar *u;
1111 rc_uint_type ul;
1112 char *buff;
20359e08 1113 bfd_size_type flen;
692ed3e7
NC
1114 FILE *fp = fopen (input_filename, "rb");
1115
1116 if (!fp)
426fb1a6 1117 fatal (_("unable to open file `%s' for input.\n"), input_filename);
692ed3e7
NC
1118
1119 fseek (fp, 0, SEEK_END);
1120 flen = ftell (fp);
1121 fseek (fp, 0, SEEK_SET);
1122 buff = malloc (flen + 3);
1123 memset (buff, 0, flen + 3);
20359e08
NC
1124 if (fread (buff, 1, flen, fp) < flen)
1125 fatal (_("unable to read contents of %s"), input_filename);
692ed3e7
NC
1126 fclose (fp);
1127 if (mcset_text_in_is_unicode != 1)
1128 {
1129 unicode_from_codepage (&ul, &u, buff, mcset_codepage_in);
1130 if (! u)
1131 fatal ("Failed to convert input to UFT16\n");
1132 mc_set_content (u);
1133 }
1134 else
1135 {
1136 if ((flen & 1) != 0)
1137 fatal (_("input file does not seems to be UFT16.\n"));
1138 mc_set_content ((unichar *) buff);
1139 }
1140 free (buff);
1141 }
1142
1143 while (yyparse ())
1144 ;
1145
1146 do_sorts ();
1147
1148 h_fp = mc_create_path_text_file (mcset_header_dir, mcset_header_ext);
1149 write_header (h_fp);
1150 fclose (h_fp);
1151
1152 h_fp = mc_create_path_text_file (mcset_rc_dir, ".rc");
1153 write_rc (h_fp);
1154 fclose (h_fp);
1155
1156 if (mcset_dbg_dir != NULL)
1157 {
1158 h_fp = mc_create_path_text_file (mcset_dbg_dir, ".dbg");
1159 write_dbg (h_fp);
1160 fclose (h_fp);
1161 }
1162 write_bin ();
1163
9db70fc3
AM
1164 free (mc_nodes_lang);
1165 free (mc_severity_codes);
1166 free (mc_facility_codes);
692ed3e7
NC
1167
1168 xexit (0);
1169 return 0;
1170}
This page took 0.551147 seconds and 4 git commands to generate.