Annotation of src/external/gpl3/binutils.old/dist/binutils/windmc.c, Revision 1.1
1.1 ! christos 1: /* windmc.c -- a program to compile Windows message files.
! 2: Copyright 2007, 2008, 2009, 2010, 2011
! 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
! 10: the Free Software Foundation; either version 3 of the License, or
! 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:
! 23:
! 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. */
! 47: typedef 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: int target_is_bigendian = 0;
! 55: const char *def_target_arch;
! 56:
! 57: /* Globals and static variable definitions. */
! 58:
! 59: /* bfd global helper struct variable. */
! 60: static struct
! 61: {
! 62: bfd *abfd;
! 63: asection *sec;
! 64: } mc_bfd;
! 65:
! 66: /* Memory list. */
! 67: mc_node *mc_nodes = NULL;
! 68: static mc_node_lang **mc_nodes_lang = NULL;
! 69: static int mc_nodes_lang_count = 0;
! 70: static mc_keyword **mc_severity_codes = NULL;
! 71: static int mc_severity_codes_count = 0;
! 72: static mc_keyword **mc_facility_codes = NULL;
! 73: static int mc_facility_codes_count = 0;
! 74:
! 75: /* When we are building a resource tree, we allocate everything onto
! 76: an obstack, so that we can free it all at once if we want. */
! 77: #define obstack_chunk_alloc xmalloc
! 78: #define obstack_chunk_free free
! 79:
! 80: /* The resource building obstack. */
! 81: static struct obstack res_obstack;
! 82:
! 83: /* Flag variables. */
! 84: /* Set by -C. Set the default code page to be used for input text file. */
! 85: static rc_uint_type mcset_codepage_in = 0;
! 86:
! 87: /* Set by -O. Set the default code page to be used for output text files. */
! 88: static rc_uint_type mcset_codepage_out = 0;
! 89:
! 90: /* Set by -b. .BIN filename should have .mc filename_ included for uniqueness. */
! 91: static int mcset_prefix_bin = 0;
! 92:
! 93: /* The base name of the .mc file. */
! 94: static const char *mcset_mc_basename = "unknown";
! 95:
! 96: /* Set by -e <ext>. Specify the extension for the header file. */
! 97: static const char *mcset_header_ext = ".h";
! 98:
! 99: /* Set by -h <path>. Gives the path of where to create the C include file. */
! 100: static const char *mcset_header_dir = "./";
! 101:
! 102: /* Set by -r <path>. Gives the path of where to create the RC include file
! 103: and the binary message resource files it includes. */
! 104: static const char *mcset_rc_dir = "./";
! 105:
! 106: /* Modified by -a & -u. By -u input file is unicode, by -a is ASCII (default). */
! 107: static int mcset_text_in_is_unicode = 0;
! 108:
! 109: /* Modified by -A & -U. By -U bin file is unicode (default), by -A is ASCII. */
! 110: static int mcset_bin_out_is_unicode = 1;
! 111:
! 112: /* Set by -c. Sets the Customer bit in all the message ID's. */
! 113: int mcset_custom_bit = 0;
! 114:
! 115: /* Set by -o. Generate OLE2 header file. Use HRESULT definition instead of
! 116: status code definition. */
! 117: static int mcset_use_hresult = 0;
! 118:
! 119: /* Set by -m <msglen>. Generate a warning if the size of any message exceeds
! 120: maxmsglen characters. */
! 121: rc_uint_type mcset_max_message_length = 0;
! 122:
! 123: /* Set by -d. Sets message values in header to decimal initially. */
! 124: int mcset_out_values_are_decimal = 0;
! 125:
! 126: /* Set by -n. terminates all strings with null's in the message tables. */
! 127: static int mcset_automatic_null_termination = 0;
! 128:
! 129: /* The type used for message id output in header. */
! 130: unichar *mcset_msg_id_typedef = NULL;
! 131:
! 132: /* Set by -x path. Geberated debug C file for mapping ID's to text. */
! 133: static const char *mcset_dbg_dir = NULL;
! 134:
! 135: /* getopt long name definitions. */
! 136: static const struct option long_options[] =
! 137: {
! 138: {"binprefix", no_argument, 0, 'b'},
! 139: {"target", required_argument, 0, 'F'},
! 140: {"extension", required_argument, 0, 'e'},
! 141: {"headerdir", required_argument, 0, 'h'},
! 142: {"rcdir", required_argument, 0, 'r'},
! 143: {"verbose", no_argument, 0, 'v'},
! 144: {"codepage_in", required_argument, 0, 'C'},
! 145: {"codepage_out", required_argument, 0, 'O'},
! 146: {"maxlength", required_argument, 0, 'm'},
! 147: {"ascii_in", no_argument, 0, 'a'},
! 148: {"ascii_out", no_argument, 0, 'A'},
! 149: {"unicode_in", no_argument, 0, 'u'},
! 150: {"unicode_out", no_argument, 0, 'U'},
! 151: {"customflag", no_argument, 0, 'c'},
! 152: {"decimal_values", no_argument, 0, 'd'},
! 153: {"hresult_use", no_argument, 0, 'o'},
! 154: {"nullterminate", no_argument, 0, 'n'},
! 155: {"xdbg", required_argument, 0, 'x'},
! 156: {"version", no_argument, 0, 'V'},
! 157: {"help", no_argument, 0, 'H'},
! 158: {0, no_argument, 0, 0}
! 159: };
! 160:
! 161:
! 162: /* Initialize the resource building obstack. */
! 163: static void
! 164: res_init (void)
! 165: {
! 166: obstack_init (&res_obstack);
! 167: }
! 168:
! 169: /* Allocate space on the resource building obstack. */
! 170: void *
! 171: res_alloc (rc_uint_type bytes)
! 172: {
! 173: return obstack_alloc (&res_obstack, (size_t) bytes);
! 174: }
! 175:
! 176: static FILE *
! 177: mc_create_path_text_file (const char *path, const char *ext)
! 178: {
! 179: FILE *ret;
! 180: size_t len = 1;
! 181: char *hsz;
! 182:
! 183: len += (path != NULL ? strlen (path) : 0);
! 184: len += strlen (mcset_mc_basename);
! 185: len += (ext != NULL ? strlen (ext) : 0);
! 186: hsz = xmalloc (len);
! 187: sprintf (hsz, "%s%s%s", (path != NULL ? path : ""), mcset_mc_basename,
! 188: (ext != NULL ? ext : ""));
! 189: if ((ret = fopen (hsz, "wb")) == NULL)
! 190: fatal (_("can't create %s file `%s' for output.\n"), (ext ? ext : "text"), hsz);
! 191: free (hsz);
! 192: return ret;
! 193: }
! 194:
! 195: static void
! 196: usage (FILE *stream, int status)
! 197: {
! 198: fprintf (stream, _("Usage: %s [option(s)] [input-file]\n"),
! 199: program_name);
! 200: fprintf (stream, _(" The options are:\n\
! 201: -a --ascii_in Read input file as ASCII file\n\
! 202: -A --ascii_out Write binary messages as ASCII\n\
! 203: -b --binprefix .bin filename is prefixed by .mc filename_ for uniqueness.\n\
! 204: -c --customflag Set custom flags for messages\n\
! 205: -C --codepage_in=<val> Set codepage when reading mc text file\n\
! 206: -d --decimal_values Print values to text files decimal\n\
! 207: -e --extension=<extension> Set header extension used on export header file\n\
! 208: -F --target <target> Specify output target for endianness.\n\
! 209: -h --headerdir=<directory> Set the export directory for headers\n\
! 210: -u --unicode_in Read input file as UTF16 file\n\
! 211: -U --unicode_out Write binary messages as UFT16\n\
! 212: -m --maxlength=<val> Set the maximal allowed message length\n\
! 213: -n --nullterminate Automatic add a zero termination to strings\n\
! 214: -o --hresult_use Use HRESULT definition instead of status code definition\n\
! 215: -O --codepage_out=<val> Set codepage used for writing text file\n\
! 216: -r --rcdir=<directory> Set the export directory for rc files\n\
! 217: -x --xdbg=<directory> Where to create the .dbg C include file\n\
! 218: that maps message ID's to their symbolic name.\n\
! 219: "));
! 220: fprintf (stream, _("\
! 221: -H --help Print this help message\n\
! 222: -v --verbose Verbose - tells you what it's doing\n\
! 223: -V --version Print version information\n"));
! 224:
! 225: list_supported_targets (program_name, stream);
! 226:
! 227: if (REPORT_BUGS_TO[0] && status == 0)
! 228: fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
! 229:
! 230: exit (status);
! 231: }
! 232:
! 233: static void
! 234: set_endianness (bfd *abfd, const char *target)
! 235: {
! 236: const bfd_target *target_vec;
! 237:
! 238: def_target_arch = NULL;
! 239: target_vec = bfd_get_target_info (target, abfd, &target_is_bigendian, NULL,
! 240: &def_target_arch);
! 241: if (! target_vec)
! 242: fatal ("Can't detect target endianness and architecture.");
! 243: if (! def_target_arch)
! 244: fatal ("Can't detect architecture.");
! 245: }
! 246:
! 247: static int
! 248: probe_codepage (rc_uint_type *cp, int *is_uni, const char *pswitch, int defmode)
! 249: {
! 250: if (*is_uni == -1)
! 251: {
! 252: if (*cp != CP_UTF16)
! 253: *is_uni = defmode;
! 254: else
! 255: *is_uni = 1;
! 256: }
! 257: if (*is_uni)
! 258: {
! 259: if (*cp != 0 && *cp != CP_UTF16)
! 260: {
! 261: fprintf (stderr, _("%s: warning: "), program_name);
! 262: fprintf (stderr, _("A codepage was specified switch `%s' and UTF16.\n"), pswitch);
! 263: fprintf (stderr, _("\tcodepage settings are ignored.\n"));
! 264: }
! 265: *cp = CP_UTF16;
! 266: return 1;
! 267: }
! 268: if (*cp == CP_UTF16)
! 269: {
! 270: *is_uni = 1;
! 271: return 1;
! 272: }
! 273: if (*cp == 0)
! 274: *cp = 1252;
! 275: if (! unicode_is_valid_codepage (*cp))
! 276: fatal ("Code page 0x%x is unknown.", (unsigned int) *cp);
! 277: *is_uni = 0;
! 278: return 1;
! 279: }
! 280:
! 281: mc_node *
! 282: mc_add_node (void)
! 283: {
! 284: mc_node *ret;
! 285:
! 286: ret = res_alloc (sizeof (mc_node));
! 287: memset (ret, 0, sizeof (mc_node));
! 288: if (! mc_nodes)
! 289: mc_nodes = ret;
! 290: else
! 291: {
! 292: mc_node *h = mc_nodes;
! 293:
! 294: while (h->next != NULL)
! 295: h = h->next;
! 296: h->next = ret;
! 297: }
! 298: return ret;
! 299: }
! 300:
! 301: mc_node_lang *
! 302: mc_add_node_lang (mc_node *root, const mc_keyword *lang, rc_uint_type vid)
! 303: {
! 304: mc_node_lang *ret, *h, *p;
! 305:
! 306: if (! lang || ! root)
! 307: fatal (_("try to add a ill language."));
! 308: ret = res_alloc (sizeof (mc_node_lang));
! 309: memset (ret, 0, sizeof (mc_node_lang));
! 310: ret->lang = lang;
! 311: ret->vid = vid;
! 312: if ((h = root->sub) == NULL)
! 313: root->sub = ret;
! 314: else
! 315: {
! 316: p = NULL;
! 317: while (h != NULL)
! 318: {
! 319: if (h->lang->nval > lang->nval)
! 320: break;
! 321: if (h->lang->nval == lang->nval)
! 322: {
! 323: if (h->vid > vid)
! 324: break;
! 325: if (h->vid == vid)
! 326: fatal ("double defined message id %ld.\n", (long) vid);
! 327: }
! 328: h = (p = h)->next;
! 329: }
! 330: ret->next = h;
! 331: if (! p)
! 332: root->sub = ret;
! 333: else
! 334: p->next = ret;
! 335: }
! 336: return ret;
! 337: }
! 338:
! 339: static char *
! 340: convert_unicode_to_ACP (const unichar *usz)
! 341: {
! 342: char *s;
! 343: rc_uint_type l;
! 344:
! 345: if (! usz)
! 346: return NULL;
! 347: codepage_from_unicode (&l, usz, &s, mcset_codepage_out);
! 348: if (! s)
! 349: fatal ("unicode string not mappable to ASCII codepage 0x%lx.\n",
! 350: (unsigned long) mcset_codepage_out);
! 351: return s;
! 352: }
! 353:
! 354: static void
! 355: write_dbg_define (FILE *fp, const unichar *sym_name, const unichar *typecast)
! 356: {
! 357: char *sym;
! 358:
! 359: if (!sym_name || sym_name[0] == 0)
! 360: return;
! 361: sym = convert_unicode_to_ACP (sym_name);
! 362: fprintf (fp, " {(");
! 363: if (typecast)
! 364: unicode_print (fp, typecast, unichar_len (typecast));
! 365: else
! 366: fprintf (fp, "DWORD");
! 367: fprintf (fp, ") %s, \"%s\" },\n", sym, sym);
! 368: }
! 369:
! 370: static void
! 371: write_header_define (FILE *fp, const unichar *sym_name, rc_uint_type vid, const unichar *typecast, mc_node_lang *nl)
! 372: {
! 373: char *sym;
! 374: char *tdef = NULL;
! 375:
! 376: if (!sym_name || sym_name[0] == 0)
! 377: {
! 378: if (nl != NULL)
! 379: {
! 380: if (mcset_out_values_are_decimal)
! 381: fprintf (fp, "//\n// MessageId: 0x%lu\n//\n", (unsigned long) vid);
! 382: else
! 383: fprintf (fp, "//\n// MessageId: 0x%lx\n//\n", (unsigned long) vid);
! 384: }
! 385: return;
! 386: }
! 387: sym = convert_unicode_to_ACP (sym_name);
! 388: if (typecast && typecast[0] != 0)
! 389: tdef = convert_unicode_to_ACP (typecast);
! 390: fprintf (fp, "//\n// MessageId: %s\n//\n", sym);
! 391: if (! mcset_out_values_are_decimal)
! 392: fprintf (fp, "#define %s %s%s%s 0x%lx\n\n", sym,
! 393: (tdef ? "(" : ""), (tdef ? tdef : ""), (tdef ? ")" : ""),
! 394: (unsigned long) vid);
! 395: else
! 396: fprintf (fp, "#define %s %s%s%s 0x%lu\n\n", sym,
! 397: (tdef ? "(" : ""), (tdef ? tdef : ""), (tdef ? ")" : ""),
! 398: (unsigned long) vid);
! 399: }
! 400:
! 401: static int
! 402: sort_mc_node_lang (const void *l, const void *r)
! 403: {
! 404: const mc_node_lang *l1 = *((const mc_node_lang **)l);
! 405: const mc_node_lang *r1 = *((const mc_node_lang **)r);
! 406:
! 407: if (l == r)
! 408: return 0;
! 409: if (l1->lang != r1->lang)
! 410: {
! 411: if (l1->lang->nval < r1->lang->nval)
! 412: return -1;
! 413: return 1;
! 414: }
! 415: if (l1->vid == r1->vid)
! 416: return 0;
! 417: if (l1->vid < r1->vid)
! 418: return -1;
! 419: return 1;
! 420: }
! 421:
! 422: static int
! 423: sort_keyword_by_nval (const void *l, const void *r)
! 424: {
! 425: const mc_keyword *l1 = *((const mc_keyword **)l);
! 426: const mc_keyword *r1 = *((const mc_keyword **)r);
! 427: rc_uint_type len1, len2;
! 428: int e;
! 429:
! 430: if (l == r)
! 431: return 0;
! 432: if (l1->nval != r1->nval)
! 433: {
! 434: if (l1->nval < r1->nval)
! 435: return -1;
! 436: return 1;
! 437: }
! 438: len1 = unichar_len (l1->usz);
! 439: len2 = unichar_len (r1->usz);
! 440: if (len1 <= len2)
! 441: e = memcmp (l1->usz, r1->usz, sizeof (unichar) * len1);
! 442: else
! 443: e = memcmp (l1->usz, r1->usz, sizeof (unichar) * len2);
! 444: if (e)
! 445: return e;
! 446: if (len1 < len2)
! 447: return -1;
! 448: else if (len1 > len2)
! 449: return 1;
! 450: return 0;
! 451: }
! 452:
! 453: static void
! 454: do_sorts (void)
! 455: {
! 456: mc_node *h;
! 457: mc_node_lang *n;
! 458: const mc_keyword *k;
! 459: int i;
! 460:
! 461: /* Sort message by their language and id ascending. */
! 462: mc_nodes_lang_count = 0;
! 463:
! 464: h = mc_nodes;
! 465: while (h != NULL)
! 466: {
! 467: n = h->sub;
! 468: while (n != NULL)
! 469: {
! 470: mc_nodes_lang_count +=1;
! 471: n = n->next;
! 472: }
! 473: h = h->next;
! 474: }
! 475:
! 476: if (mc_nodes_lang_count != 0)
! 477: {
! 478: h = mc_nodes;
! 479: i = 0;
! 480: mc_nodes_lang = xmalloc (sizeof (mc_node_lang *) * mc_nodes_lang_count);
! 481:
! 482: while (h != NULL)
! 483: {
! 484: n = h->sub;
! 485: while (n != NULL)
! 486: {
! 487: mc_nodes_lang[i++] = n;
! 488: n = n->next;
! 489: }
! 490: h = h->next;
! 491: }
! 492: qsort (mc_nodes_lang, (size_t) mc_nodes_lang_count, sizeof (mc_node_lang *), sort_mc_node_lang);
! 493: }
! 494: /* Sort facility code definitions by there id ascending. */
! 495: i = 0;
! 496: while ((k = enum_facility (i)) != NULL)
! 497: ++i;
! 498: mc_facility_codes_count = i;
! 499: if (i != 0)
! 500: {
! 501: mc_facility_codes = xmalloc (sizeof (mc_keyword *) * i);
! 502: i = 0;
! 503: while ((k = enum_facility (i)) != NULL)
! 504: mc_facility_codes[i++] = (mc_keyword *) k;
! 505: qsort (mc_facility_codes, (size_t) mc_facility_codes_count, sizeof (mc_keyword *), sort_keyword_by_nval);
! 506: }
! 507:
! 508: /* Sort severity code definitions by there id ascending. */
! 509: i = 0;
! 510: while ((k = enum_severity (i)) != NULL)
! 511: ++i;
! 512: mc_severity_codes_count = i;
! 513: if (i != 0)
! 514: {
! 515: mc_severity_codes = xmalloc (sizeof (mc_keyword *) * i);
! 516: i = 0;
! 517: while ((k = enum_severity (i)) != NULL)
! 518: mc_severity_codes[i++] = (mc_keyword *) k;
! 519: qsort (mc_severity_codes, (size_t) mc_severity_codes_count, sizeof (mc_keyword *), sort_keyword_by_nval);
! 520: }
! 521: }
! 522:
! 523: static int
! 524: mc_get_block_count (mc_node_lang **nl, int elems)
! 525: {
! 526: rc_uint_type exid;
! 527: int i, ret;
! 528:
! 529: if (! nl)
! 530: return 0;
! 531: i = 0;
! 532: ret = 0;
! 533: while (i < elems)
! 534: {
! 535: ret++;
! 536: exid = nl[i++]->vid;
! 537: while (i < elems && nl[i]->vid == exid + 1)
! 538: exid = nl[i++]->vid;
! 539: }
! 540: return ret;
! 541: }
! 542:
! 543: static bfd *
! 544: windmc_open_as_binary (const char *filename)
! 545: {
! 546: bfd *abfd;
! 547:
! 548: abfd = bfd_openw (filename, "binary");
! 549: if (! abfd)
! 550: fatal ("can't open `%s' for output", filename);
! 551:
! 552: return abfd;
! 553: }
! 554:
! 555: static void
! 556: target_put_16 (void *p, rc_uint_type value)
! 557: {
! 558: assert (!! p);
! 559:
! 560: if (target_is_bigendian)
! 561: bfd_putb16 (value, p);
! 562: else
! 563: bfd_putl16 (value, p);
! 564: }
! 565:
! 566: static void
! 567: target_put_32 (void *p, rc_uint_type value)
! 568: {
! 569: assert (!! p);
! 570:
! 571: if (target_is_bigendian)
! 572: bfd_putb32 (value, p);
! 573: else
! 574: bfd_putl32 (value, p);
! 575: }
! 576:
! 577: static struct bin_messagetable_item *
! 578: mc_generate_bin_item (mc_node_lang *n, rc_uint_type *res_len)
! 579: {
! 580: struct bin_messagetable_item *ret = NULL;
! 581: rc_uint_type len;
! 582:
! 583: *res_len = 0;
! 584: if (mcset_bin_out_is_unicode == 1)
! 585: {
! 586: unichar *ht = n->message;
! 587: rc_uint_type txt_len;
! 588:
! 589: txt_len = unichar_len (n->message);
! 590: if (mcset_automatic_null_termination && txt_len != 0)
! 591: {
! 592: while (txt_len > 0 && ht[txt_len - 1] > 0 && ht[txt_len - 1] < 0x20)
! 593: ht[--txt_len] = 0;
! 594: }
! 595: txt_len *= sizeof (unichar);
! 596: len = BIN_MESSAGETABLE_ITEM_SIZE + txt_len + sizeof (unichar);
! 597: ret = res_alloc ((len + 3) & ~3);
! 598: memset (ret, 0, (len + 3) & ~3);
! 599: target_put_16 (ret->length, (len + 3) & ~3);
! 600: target_put_16 (ret->flags, MESSAGE_RESOURCE_UNICODE);
! 601: txt_len = 0;
! 602: while (*ht != 0)
! 603: {
! 604: target_put_16 (ret->data + txt_len, *ht++);
! 605: txt_len += 2;
! 606: }
! 607: }
! 608: else
! 609: {
! 610: rc_uint_type txt_len, l;
! 611: char *cvt_txt;
! 612:
! 613: codepage_from_unicode( &l, n->message, &cvt_txt, n->lang->lang_info.wincp);
! 614: if (! cvt_txt)
! 615: fatal ("Failed to convert message to language codepage.\n");
! 616: txt_len = strlen (cvt_txt);
! 617: if (mcset_automatic_null_termination && txt_len > 0)
! 618: {
! 619: while (txt_len > 0 && cvt_txt[txt_len - 1] > 0 && cvt_txt[txt_len - 1] < 0x20)
! 620: cvt_txt[--txt_len] = 0;
! 621: }
! 622: len = BIN_MESSAGETABLE_ITEM_SIZE + txt_len + 1;
! 623: ret = res_alloc ((len + 3) & ~3);
! 624: memset (ret, 0, (len + 3) & ~3);
! 625: target_put_16 (ret->length, (len + 3) & ~3);
! 626: target_put_16 (ret->flags, 0);
! 627: strcpy ((char *) ret->data, cvt_txt);
! 628: }
! 629: *res_len = (len + 3) & ~3;
! 630: return ret;
! 631: }
! 632:
! 633: static void
! 634: mc_write_blocks (struct bin_messagetable *mtbl, mc_node_lang **nl, mc_msg_item *ml, int elems)
! 635: {
! 636: int i, idx = 0;
! 637: rc_uint_type exid;
! 638:
! 639: if (! nl)
! 640: return;
! 641: i = 0;
! 642: while (i < elems)
! 643: {
! 644: target_put_32 (mtbl->items[idx].lowid, nl[i]->vid);
! 645: target_put_32 (mtbl->items[idx].highid, nl[i]->vid);
! 646: target_put_32 (mtbl->items[idx].offset, ml[i].res_off);
! 647: exid = nl[i++]->vid;
! 648: while (i < elems && nl[i]->vid == exid + 1)
! 649: {
! 650: target_put_32 (mtbl->items[idx].highid, nl[i]->vid);
! 651: exid = nl[i++]->vid;
! 652: }
! 653: ++idx;
! 654: }
! 655: }
! 656:
! 657: static void
! 658: set_windmc_bfd_content (const void *data, rc_uint_type off, rc_uint_type length)
! 659: {
! 660: if (! bfd_set_section_contents (mc_bfd.abfd, mc_bfd.sec, data, off, length))
! 661: bfd_fatal ("bfd_set_section_contents");
! 662: }
! 663:
! 664: static void
! 665: windmc_write_bin (const char *filename, mc_node_lang **nl, int elems)
! 666: {
! 667: unsigned long sec_length = 1;
! 668: int block_count, i;
! 669: mc_msg_item *mi;
! 670: struct bin_messagetable *mtbl;
! 671: rc_uint_type dta_off, dta_start;
! 672:
! 673: if (elems <= 0)
! 674: return;
! 675: mc_bfd.abfd = windmc_open_as_binary (filename);
! 676: mc_bfd.sec = bfd_make_section_with_flags (mc_bfd.abfd, ".data",
! 677: (SEC_HAS_CONTENTS | SEC_ALLOC
! 678: | SEC_LOAD | SEC_DATA));
! 679: if (mc_bfd.sec == NULL)
! 680: bfd_fatal ("bfd_make_section");
! 681: /* Requiring this is probably a bug in BFD. */
! 682: mc_bfd.sec->output_section = mc_bfd.sec;
! 683:
! 684: block_count = mc_get_block_count (nl, elems);
! 685:
! 686: dta_off = (rc_uint_type) ((BIN_MESSAGETABLE_BLOCK_SIZE * block_count) + BIN_MESSAGETABLE_SIZE - 4);
! 687: dta_start = dta_off = (dta_off + 3) & ~3;
! 688: mi = xmalloc (sizeof (mc_msg_item) * elems);
! 689: mtbl = xmalloc (dta_start);
! 690:
! 691: /* Clear header region. */
! 692: memset (mtbl, 0, dta_start);
! 693: target_put_32 (mtbl->cblocks, block_count);
! 694: /* Prepare items section for output. */
! 695: for (i = 0; i < elems; i++)
! 696: {
! 697: mi[i].res_off = dta_off;
! 698: mi[i].res = mc_generate_bin_item (nl[i], &mi[i].res_len);
! 699: dta_off += mi[i].res_len;
! 700: }
! 701: sec_length = (dta_off + 3) & ~3;
! 702: if (! bfd_set_section_size (mc_bfd.abfd, mc_bfd.sec, sec_length))
! 703: bfd_fatal ("bfd_set_section_size");
! 704: /* Make sure we write the complete block. */
! 705: set_windmc_bfd_content ("\0", sec_length - 1, 1);
! 706:
! 707: /* Write block information. */
! 708: mc_write_blocks (mtbl, nl, mi, elems);
! 709:
! 710: set_windmc_bfd_content (mtbl, 0, dta_start);
! 711:
! 712: /* Write items. */
! 713: for (i = 0; i < elems; i++)
! 714: set_windmc_bfd_content (mi[i].res, mi[i].res_off, mi[i].res_len);
! 715:
! 716: free (mtbl);
! 717: free (mi);
! 718: bfd_close (mc_bfd.abfd);
! 719: mc_bfd.abfd = NULL;
! 720: mc_bfd.sec = NULL;
! 721: }
! 722:
! 723: static void
! 724: write_bin (void)
! 725: {
! 726: mc_node_lang *n = NULL;
! 727: int i, c;
! 728:
! 729: if (! mc_nodes_lang_count)
! 730: return;
! 731:
! 732: i = 0;
! 733: while (i < mc_nodes_lang_count)
! 734: {
! 735: char *nd;
! 736: char *filename;
! 737:
! 738: if (n && n->lang == mc_nodes_lang[i]->lang)
! 739: {
! 740: i++;
! 741: continue;
! 742: }
! 743: n = mc_nodes_lang[i];
! 744: c = i + 1;
! 745: while (c < mc_nodes_lang_count && n->lang == mc_nodes_lang[c]->lang)
! 746: c++;
! 747: nd = convert_unicode_to_ACP (n->lang->sval);
! 748:
! 749: /* Prepare filename for binary output. */
! 750: filename = xmalloc (strlen (nd) + 4 + 1 + strlen (mcset_mc_basename) + 1 + strlen (mcset_rc_dir));
! 751: strcpy (filename, mcset_rc_dir);
! 752: if (mcset_prefix_bin)
! 753: sprintf (filename + strlen (filename), "%s_", mcset_mc_basename);
! 754: strcat (filename, nd);
! 755: strcat (filename, ".bin");
! 756:
! 757: /* Write message file. */
! 758: windmc_write_bin (filename, &mc_nodes_lang[i], (c - i));
! 759:
! 760: free (filename);
! 761: i = c;
! 762: }
! 763: }
! 764:
! 765: static void
! 766: write_rc (FILE *fp)
! 767: {
! 768: mc_node_lang *n;
! 769: int i, l;
! 770:
! 771: fprintf (fp,
! 772: "/* Do not edit this file manually.\n"
! 773: " This file is autogenerated by windmc. */\n\n");
! 774: if (! mc_nodes_lang_count)
! 775: return;
! 776: n = NULL;
! 777: i = 0;
! 778: for (l = 0; l < mc_nodes_lang_count; l++)
! 779: {
! 780: if (n && n->lang == mc_nodes_lang[l]->lang)
! 781: continue;
! 782: ++i;
! 783: n = mc_nodes_lang[l];
! 784: fprintf (fp, "\n// Country: %s\n// Language: %s\n#pragma code_page(%u)\n",
! 785: n->lang->lang_info.country, n->lang->lang_info.name,
! 786: (unsigned) n->lang->lang_info.wincp);
! 787: fprintf (fp, "LANGUAGE 0x%lx, 0x%lx\n",
! 788: (unsigned long) (n->lang->nval & 0x3ff),
! 789: (unsigned long) ((n->lang->nval & 0xffff) >> 10));
! 790: fprintf (fp, "1 MESSAGETABLE \"");
! 791: if (mcset_prefix_bin)
! 792: fprintf (fp, "%s_", mcset_mc_basename);
! 793: unicode_print (fp, n->lang->sval, unichar_len (n->lang->sval));
! 794: fprintf (fp, ".bin\"\n");
! 795: }
! 796: }
! 797:
! 798: static void
! 799: write_dbg (FILE *fp)
! 800: {
! 801: mc_node *h;
! 802:
! 803: fprintf (fp,
! 804: "/* Do not edit this file manually.\n"
! 805: " This file is autogenerated by windmc.\n\n"
! 806: " This file maps each message ID value in to a text string that contains\n"
! 807: " the symbolic name used for it. */\n\n");
! 808:
! 809: fprintf (fp,
! 810: "struct %sSymbolicName\n"
! 811: "{\n ", mcset_mc_basename);
! 812: if (mcset_msg_id_typedef)
! 813: unicode_print (fp, mcset_msg_id_typedef, unichar_len (mcset_msg_id_typedef));
! 814: else
! 815: fprintf (fp, "DWORD");
! 816: fprintf (fp,
! 817: " MessageId;\n"
! 818: " char *SymbolicName;\n"
! 819: "} %sSymbolicNames[] =\n"
! 820: "{\n", mcset_mc_basename);
! 821: h = mc_nodes;
! 822: while (h != NULL)
! 823: {
! 824: if (h->symbol)
! 825: write_dbg_define (fp, h->symbol, mcset_msg_id_typedef);
! 826: h = h->next;
! 827: }
! 828: fprintf (fp, " { (");
! 829: if (mcset_msg_id_typedef)
! 830: unicode_print (fp, mcset_msg_id_typedef, unichar_len (mcset_msg_id_typedef));
! 831: else
! 832: fprintf (fp, "DWORD");
! 833: fprintf (fp,
! 834: ") 0xffffffff, NULL }\n"
! 835: "};\n");
! 836: }
! 837:
! 838: static void
! 839: write_header (FILE *fp)
! 840: {
! 841: char *s;
! 842: int i;
! 843: const mc_keyword *key;
! 844: mc_node *h;
! 845:
! 846: fprintf (fp,
! 847: "/* Do not edit this file manually.\n"
! 848: " This file is autogenerated by windmc. */\n\n"
! 849: "//\n// The values are 32 bit layed out as follows:\n//\n"
! 850: "// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1\n"
! 851: "// 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"
! 852: "// +---+-+-+-----------------------+-------------------------------+\n"
! 853: "// |Sev|C|R| Facility | Code |\n"
! 854: "// +---+-+-+-----------------------+-------------------------------+\n//\n"
! 855: "// where\n//\n"
! 856: "// C - is the Customer code flag\n//\n"
! 857: "// R - is a reserved bit\n//\n"
! 858: "// Code - is the facility's status code\n//\n");
! 859:
! 860: h = mc_nodes;
! 861:
! 862: fprintf (fp, "// Sev - is the severity code\n//\n");
! 863: if (mc_severity_codes_count != 0)
! 864: {
! 865: for (i = 0; i < mc_severity_codes_count; i++)
! 866: {
! 867: key = mc_severity_codes[i];
! 868: fprintf (fp, "// %s - %02lx\n", convert_unicode_to_ACP (key->usz),
! 869: (unsigned long) key->nval);
! 870: if (key->sval && key->sval[0] != 0)
! 871: {
! 872: if (! mcset_out_values_are_decimal)
! 873: fprintf (fp, "#define %s 0x%lx\n", convert_unicode_to_ACP (key->sval),
! 874: (unsigned long) key->nval);
! 875: else
! 876: fprintf (fp, "#define %s 0x%lu\n", convert_unicode_to_ACP (key->sval),
! 877: (unsigned long) key->nval);
! 878: }
! 879: }
! 880: fprintf (fp, "//\n");
! 881: }
! 882: fprintf (fp, "// Facility - is the facility code\n//\n");
! 883: if (mc_facility_codes_count != 0)
! 884: {
! 885: for (i = 0; i < mc_facility_codes_count; i++)
! 886: {
! 887: key = mc_facility_codes[i];
! 888: fprintf (fp, "// %s - %04lx\n", convert_unicode_to_ACP (key->usz),
! 889: (unsigned long) key->nval);
! 890: if (key->sval && key->sval[0] != 0)
! 891: {
! 892: if (! mcset_out_values_are_decimal)
! 893: fprintf (fp, "#define %s 0x%lx\n", convert_unicode_to_ACP (key->sval),
! 894: (unsigned long) key->nval);
! 895: else
! 896: fprintf (fp, "#define %s 0x%lu\n", convert_unicode_to_ACP (key->sval),
! 897: (unsigned long) key->nval);
! 898: }
! 899: }
! 900: fprintf (fp, "//\n");
! 901: }
! 902: fprintf (fp, "\n");
! 903: while (h != NULL)
! 904: {
! 905: if (h->user_text)
! 906: {
! 907: s = convert_unicode_to_ACP (h->user_text);
! 908: if (s)
! 909: fprintf (fp, "%s", s);
! 910: }
! 911: if (h->symbol)
! 912: write_header_define (fp, h->symbol, h->vid, mcset_msg_id_typedef, h->sub);
! 913: h = h->next;
! 914: }
! 915: }
! 916:
! 917: static const char *
! 918: mc_unify_path (const char *path)
! 919: {
! 920: char *end;
! 921: char *hsz;
! 922:
! 923: if (! path || *path == 0)
! 924: return "./";
! 925: hsz = xmalloc (strlen (path) + 2);
! 926: strcpy (hsz, path);
! 927: end = hsz + strlen (hsz);
! 928: if (hsz[-1] != '/' && hsz[-1] != '\\')
! 929: strcpy (end, "/");
! 930: while ((end = strchr (hsz, '\\')) != NULL)
! 931: *end = '/';
! 932: return hsz;
! 933: }
! 934:
! 935: int main (int, char **);
! 936:
! 937: int
! 938: main (int argc, char **argv)
! 939: {
! 940: FILE *h_fp;
! 941: int c;
! 942: char *target, *input_filename;
! 943: int verbose;
! 944:
! 945: #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
! 946: setlocale (LC_MESSAGES, "");
! 947: #endif
! 948: #if defined (HAVE_SETLOCALE)
! 949: setlocale (LC_CTYPE, "");
! 950: #endif
! 951: bindtextdomain (PACKAGE, LOCALEDIR);
! 952: textdomain (PACKAGE);
! 953:
! 954: program_name = argv[0];
! 955: xmalloc_set_program_name (program_name);
! 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:
! 1057: set_endianness (NULL, target);
! 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;
! 1112: bfd_size_type flen;
! 1113: FILE *fp = fopen (input_filename, "rb");
! 1114:
! 1115: if (!fp)
! 1116: fatal (_("unable to open file `%s' for input.\n"), input_filename);
! 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);
! 1123: if (fread (buff, 1, flen, fp) < flen)
! 1124: fatal (_("unable to read contents of %s"), input_filename);
! 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: }
CVSweb <webmaster@jp.NetBSD.org>