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