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