1 /* windres.c -- a program to manipulate Windows resources 2 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 3 Free Software Foundation, Inc. 4 Written by Ian Lance Taylor, Cygnus Support. 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 2 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 /* This program can read and write Windows resources in various 24 formats. In particular, it can act like the rc resource compiler 25 program, and it can act like the cvtres res to COFF conversion 26 program. 27 28 It is based on information taken from the following sources: 29 30 * Microsoft documentation. 31 32 * The rcl program, written by Gunther Ebert 33 <gunther.ebert@ixos-leipzig.de>. 34 35 * The res2coff program, written by Pedro A. Aranda <paag@tid.es>. */ 36 37 #include "config.h" 38 #ifdef HAVE_UNISTD_H 39 #include <unistd.h> 40 #endif 41 #include <assert.h> 42 #include <time.h> 43 #include "bfd.h" 44 #include "getopt.h" 45 #include "bucomm.h" 46 #include "libiberty.h" 47 #include "safe-ctype.h" 48 #include "obstack.h" 49 #include "windres.h" 50 51 /* Used by resrc.c at least. */ 52 53 int verbose = 0; 54 55 /* An enumeration of format types. */ 56 57 enum res_format 58 { 59 /* Unknown format. */ 60 RES_FORMAT_UNKNOWN, 61 /* Textual RC file. */ 62 RES_FORMAT_RC, 63 /* Binary RES file. */ 64 RES_FORMAT_RES, 65 /* COFF file. */ 66 RES_FORMAT_COFF 67 }; 68 69 /* A structure used to map between format types and strings. */ 70 71 struct format_map 72 { 73 const char *name; 74 enum res_format format; 75 }; 76 77 /* A mapping between names and format types. */ 78 79 static const struct format_map format_names[] = 80 { 81 { "rc", RES_FORMAT_RC }, 82 { "res", RES_FORMAT_RES }, 83 { "coff", RES_FORMAT_COFF }, 84 { NULL, RES_FORMAT_UNKNOWN } 85 }; 86 87 /* A mapping from file extensions to format types. */ 88 89 static const struct format_map format_fileexts[] = 90 { 91 { "rc", RES_FORMAT_RC }, 92 { "res", RES_FORMAT_RES }, 93 { "exe", RES_FORMAT_COFF }, 94 { "obj", RES_FORMAT_COFF }, 95 { "o", RES_FORMAT_COFF }, 96 { NULL, RES_FORMAT_UNKNOWN } 97 }; 98 99 /* A list of include directories. */ 100 101 struct include_dir 102 { 103 struct include_dir *next; 104 char *dir; 105 }; 106 107 static struct include_dir *include_dirs; 108 109 /* Static functions. */ 110 111 static void res_init (void); 112 static int extended_menuitems (const struct menuitem *); 113 static enum res_format format_from_name (const char *, int); 114 static enum res_format format_from_filename (const char *, int); 115 static void usage (FILE *, int); 116 static int cmp_res_entry (const void *, const void *); 117 static struct res_directory *sort_resources (struct res_directory *); 118 static void reswr_init (void); 119 static const char * quot (const char *); 120 121 /* When we are building a resource tree, we allocate everything onto 122 an obstack, so that we can free it all at once if we want. */ 123 124 #define obstack_chunk_alloc xmalloc 125 #define obstack_chunk_free free 126 127 /* The resource building obstack. */ 128 129 static struct obstack res_obstack; 130 131 /* Initialize the resource building obstack. */ 132 133 static void 134 res_init (void) 135 { 136 obstack_init (&res_obstack); 137 } 138 139 /* Allocate space on the resource building obstack. */ 140 141 void * 142 res_alloc (size_t bytes) 143 { 144 return (void *) obstack_alloc (&res_obstack, bytes); 145 } 146 147 /* We also use an obstack to save memory used while writing out a set 148 of resources. */ 149 150 static struct obstack reswr_obstack; 151 152 /* Initialize the resource writing obstack. */ 153 154 static void 155 reswr_init (void) 156 { 157 obstack_init (&reswr_obstack); 158 } 159 160 /* Allocate space on the resource writing obstack. */ 161 162 void * 163 reswr_alloc (size_t bytes) 164 { 165 return (void *) obstack_alloc (&reswr_obstack, bytes); 166 } 167 168 /* Open a file using the include directory search list. */ 169 170 FILE * 171 open_file_search (const char *filename, const char *mode, const char *errmsg, 172 char **real_filename) 173 { 174 FILE *e; 175 struct include_dir *d; 176 177 e = fopen (filename, mode); 178 if (e != NULL) 179 { 180 *real_filename = xstrdup (filename); 181 return e; 182 } 183 184 if (errno == ENOENT) 185 { 186 for (d = include_dirs; d != NULL; d = d->next) 187 { 188 char *n; 189 190 n = (char *) xmalloc (strlen (d->dir) + strlen (filename) + 2); 191 sprintf (n, "%s/%s", d->dir, filename); 192 e = fopen (n, mode); 193 if (e != NULL) 194 { 195 *real_filename = n; 196 return e; 197 } 198 199 if (errno != ENOENT) 200 break; 201 } 202 } 203 204 fatal (_("can't open %s `%s': %s"), errmsg, filename, strerror (errno)); 205 206 /* Return a value to avoid a compiler warning. */ 207 return NULL; 208 } 209 210 /* Compare two resource ID's. We consider name entries to come before 211 numeric entries, because that is how they appear in the COFF .rsrc 212 section. */ 213 214 int 215 res_id_cmp (struct res_id a, struct res_id b) 216 { 217 if (! a.named) 218 { 219 if (b.named) 220 return 1; 221 if (a.u.id > b.u.id) 222 return 1; 223 else if (a.u.id < b.u.id) 224 return -1; 225 else 226 return 0; 227 } 228 else 229 { 230 unichar *as, *ase, *bs, *bse; 231 232 if (! b.named) 233 return -1; 234 235 as = a.u.n.name; 236 ase = as + a.u.n.length; 237 bs = b.u.n.name; 238 bse = bs + b.u.n.length; 239 240 while (as < ase) 241 { 242 int i; 243 244 if (bs >= bse) 245 return 1; 246 i = (int) *as - (int) *bs; 247 if (i != 0) 248 return i; 249 ++as; 250 ++bs; 251 } 252 253 if (bs < bse) 254 return -1; 255 256 return 0; 257 } 258 } 259 260 /* Print a resource ID. */ 261 262 void 263 res_id_print (FILE *stream, struct res_id id, int quote) 264 { 265 if (! id.named) 266 fprintf (stream, "%lu", id.u.id); 267 else 268 { 269 if (quote) 270 putc ('"', stream); 271 unicode_print (stream, id.u.n.name, id.u.n.length); 272 if (quote) 273 putc ('"', stream); 274 } 275 } 276 277 /* Print a list of resource ID's. */ 278 279 void 280 res_ids_print (FILE *stream, int cids, const struct res_id *ids) 281 { 282 int i; 283 284 for (i = 0; i < cids; i++) 285 { 286 res_id_print (stream, ids[i], 1); 287 if (i + 1 < cids) 288 fprintf (stream, ": "); 289 } 290 } 291 292 /* Convert an ASCII string to a resource ID. */ 293 294 void 295 res_string_to_id (struct res_id *res_id, const char *string) 296 { 297 res_id->named = 1; 298 unicode_from_ascii (&res_id->u.n.length, &res_id->u.n.name, string); 299 } 300 301 /* Define a resource. The arguments are the resource tree, RESOURCES, 302 and the location at which to put it in the tree, CIDS and IDS. 303 This returns a newly allocated res_resource structure, which the 304 caller is expected to initialize. If DUPOK is non-zero, then if a 305 resource with this ID exists, it is returned. Otherwise, a warning 306 is issued, and a new resource is created replacing the existing 307 one. */ 308 309 struct res_resource * 310 define_resource (struct res_directory **resources, int cids, 311 const struct res_id *ids, int dupok) 312 { 313 struct res_entry *re = NULL; 314 int i; 315 316 assert (cids > 0); 317 for (i = 0; i < cids; i++) 318 { 319 struct res_entry **pp; 320 321 if (*resources == NULL) 322 { 323 static unsigned long timeval; 324 325 /* Use the same timestamp for every resource created in a 326 single run. */ 327 if (timeval == 0) 328 timeval = time (NULL); 329 330 *resources = ((struct res_directory *) 331 res_alloc (sizeof **resources)); 332 (*resources)->characteristics = 0; 333 (*resources)->time = timeval; 334 (*resources)->major = 0; 335 (*resources)->minor = 0; 336 (*resources)->entries = NULL; 337 } 338 339 for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next) 340 if (res_id_cmp ((*pp)->id, ids[i]) == 0) 341 break; 342 343 if (*pp != NULL) 344 re = *pp; 345 else 346 { 347 re = (struct res_entry *) res_alloc (sizeof *re); 348 re->next = NULL; 349 re->id = ids[i]; 350 if ((i + 1) < cids) 351 { 352 re->subdir = 1; 353 re->u.dir = NULL; 354 } 355 else 356 { 357 re->subdir = 0; 358 re->u.res = NULL; 359 } 360 361 *pp = re; 362 } 363 364 if ((i + 1) < cids) 365 { 366 if (! re->subdir) 367 { 368 fprintf (stderr, "%s: ", program_name); 369 res_ids_print (stderr, i, ids); 370 fprintf (stderr, _(": expected to be a directory\n")); 371 xexit (1); 372 } 373 374 resources = &re->u.dir; 375 } 376 } 377 378 if (re->subdir) 379 { 380 fprintf (stderr, "%s: ", program_name); 381 res_ids_print (stderr, cids, ids); 382 fprintf (stderr, _(": expected to be a leaf\n")); 383 xexit (1); 384 } 385 386 if (re->u.res != NULL) 387 { 388 if (dupok) 389 return re->u.res; 390 391 fprintf (stderr, _("%s: warning: "), program_name); 392 res_ids_print (stderr, cids, ids); 393 fprintf (stderr, _(": duplicate value\n")); 394 } 395 396 re->u.res = ((struct res_resource *) 397 res_alloc (sizeof (struct res_resource))); 398 memset (re->u.res, 0, sizeof (struct res_resource)); 399 400 re->u.res->type = RES_TYPE_UNINITIALIZED; 401 return re->u.res; 402 } 403 404 /* Define a standard resource. This is a version of define_resource 405 that just takes type, name, and language arguments. */ 406 407 struct res_resource * 408 define_standard_resource (struct res_directory **resources, int type, 409 struct res_id name, int language, int dupok) 410 { 411 struct res_id a[3]; 412 413 a[0].named = 0; 414 a[0].u.id = type; 415 a[1] = name; 416 a[2].named = 0; 417 a[2].u.id = language; 418 return define_resource (resources, 3, a, dupok); 419 } 420 421 /* Comparison routine for resource sorting. */ 422 423 static int 424 cmp_res_entry (const void *p1, const void *p2) 425 { 426 const struct res_entry **re1, **re2; 427 428 re1 = (const struct res_entry **) p1; 429 re2 = (const struct res_entry **) p2; 430 return res_id_cmp ((*re1)->id, (*re2)->id); 431 } 432 433 /* Sort the resources. */ 434 435 static struct res_directory * 436 sort_resources (struct res_directory *resdir) 437 { 438 int c, i; 439 struct res_entry *re; 440 struct res_entry **a; 441 442 if (resdir->entries == NULL) 443 return resdir; 444 445 c = 0; 446 for (re = resdir->entries; re != NULL; re = re->next) 447 ++c; 448 449 /* This is a recursive routine, so using xmalloc is probably better 450 than alloca. */ 451 a = (struct res_entry **) xmalloc (c * sizeof (struct res_entry *)); 452 453 for (i = 0, re = resdir->entries; re != NULL; re = re->next, i++) 454 a[i] = re; 455 456 qsort (a, c, sizeof (struct res_entry *), cmp_res_entry); 457 458 resdir->entries = a[0]; 459 for (i = 0; i < c - 1; i++) 460 a[i]->next = a[i + 1]; 461 a[i]->next = NULL; 462 463 free (a); 464 465 /* Now sort the subdirectories. */ 466 467 for (re = resdir->entries; re != NULL; re = re->next) 468 if (re->subdir) 469 re->u.dir = sort_resources (re->u.dir); 470 471 return resdir; 472 } 473 474 /* Return whether the dialog resource DIALOG is a DIALOG or a 475 DIALOGEX. */ 476 477 int 478 extended_dialog (const struct dialog *dialog) 479 { 480 const struct dialog_control *c; 481 482 if (dialog->ex != NULL) 483 return 1; 484 485 for (c = dialog->controls; c != NULL; c = c->next) 486 if (c->data != NULL || c->help != 0) 487 return 1; 488 489 return 0; 490 } 491 492 /* Return whether MENUITEMS are a MENU or a MENUEX. */ 493 494 int 495 extended_menu (const struct menu *menu) 496 { 497 return extended_menuitems (menu->items); 498 } 499 500 static int 501 extended_menuitems (const struct menuitem *menuitems) 502 { 503 const struct menuitem *mi; 504 505 for (mi = menuitems; mi != NULL; mi = mi->next) 506 { 507 if (mi->help != 0 || mi->state != 0) 508 return 1; 509 if (mi->popup != NULL && mi->id != 0) 510 return 1; 511 if ((mi->type 512 & ~ (MENUITEM_CHECKED 513 | MENUITEM_GRAYED 514 | MENUITEM_HELP 515 | MENUITEM_INACTIVE 516 | MENUITEM_MENUBARBREAK 517 | MENUITEM_MENUBREAK)) 518 != 0) 519 return 1; 520 if (mi->popup != NULL) 521 { 522 if (extended_menuitems (mi->popup)) 523 return 1; 524 } 525 } 526 527 return 0; 528 } 529 530 /* Convert a string to a format type, or exit if it can't be done. */ 531 532 static enum res_format 533 format_from_name (const char *name, int exit_on_error) 534 { 535 const struct format_map *m; 536 537 for (m = format_names; m->name != NULL; m++) 538 if (strcasecmp (m->name, name) == 0) 539 break; 540 541 if (m->name == NULL && exit_on_error) 542 { 543 non_fatal (_("unknown format type `%s'"), name); 544 fprintf (stderr, _("%s: supported formats:"), program_name); 545 for (m = format_names; m->name != NULL; m++) 546 fprintf (stderr, " %s", m->name); 547 fprintf (stderr, "\n"); 548 xexit (1); 549 } 550 551 return m->format; 552 } 553 554 /* Work out a format type given a file name. If INPUT is non-zero, 555 it's OK to look at the file itself. */ 556 557 static enum res_format 558 format_from_filename (const char *filename, int input) 559 { 560 const char *ext; 561 FILE *e; 562 unsigned char b1, b2, b3, b4, b5; 563 int magic; 564 565 /* If we have an extension, see if we recognize it as implying a 566 particular format. */ 567 ext = strrchr (filename, '.'); 568 if (ext != NULL) 569 { 570 const struct format_map *m; 571 572 ++ext; 573 for (m = format_fileexts; m->name != NULL; m++) 574 if (strcasecmp (m->name, ext) == 0) 575 return m->format; 576 } 577 578 /* If we don't recognize the name of an output file, assume it's a 579 COFF file. */ 580 if (! input) 581 return RES_FORMAT_COFF; 582 583 /* Read the first few bytes of the file to see if we can guess what 584 it is. */ 585 e = fopen (filename, FOPEN_RB); 586 if (e == NULL) 587 fatal ("%s: %s", filename, strerror (errno)); 588 589 b1 = getc (e); 590 b2 = getc (e); 591 b3 = getc (e); 592 b4 = getc (e); 593 b5 = getc (e); 594 595 fclose (e); 596 597 /* A PE executable starts with 0x4d 0x5a. */ 598 if (b1 == 0x4d && b2 == 0x5a) 599 return RES_FORMAT_COFF; 600 601 /* A COFF .o file starts with a COFF magic number. */ 602 magic = (b2 << 8) | b1; 603 switch (magic) 604 { 605 case 0x14c: /* i386 */ 606 case 0x166: /* MIPS */ 607 case 0x184: /* Alpha */ 608 case 0x268: /* 68k */ 609 case 0x1f0: /* PowerPC */ 610 case 0x290: /* PA */ 611 return RES_FORMAT_COFF; 612 } 613 614 /* A RES file starts with 0x0 0x0 0x0 0x0 0x20 0x0 0x0 0x0. */ 615 if (b1 == 0 && b2 == 0 && b3 == 0 && b4 == 0 && b5 == 0x20) 616 return RES_FORMAT_RES; 617 618 /* If every character is printable or space, assume it's an RC file. */ 619 if ((ISPRINT (b1) || ISSPACE (b1)) 620 && (ISPRINT (b2) || ISSPACE (b2)) 621 && (ISPRINT (b3) || ISSPACE (b3)) 622 && (ISPRINT (b4) || ISSPACE (b4)) 623 && (ISPRINT (b5) || ISSPACE (b5))) 624 return RES_FORMAT_RC; 625 626 /* Otherwise, we give up. */ 627 fatal (_("can not determine type of file `%s'; use the -J option"), 628 filename); 629 630 /* Return something to silence the compiler warning. */ 631 return RES_FORMAT_UNKNOWN; 632 } 633 634 /* Print a usage message and exit. */ 635 636 static void 637 usage (FILE *stream, int status) 638 { 639 fprintf (stream, _("Usage: %s [option(s)] [input-file] [output-file]\n"), 640 program_name); 641 fprintf (stream, _(" The options are:\n\ 642 -i --input=<file> Name input file\n\ 643 -o --output=<file> Name output file\n\ 644 -J --input-format=<format> Specify input format\n\ 645 -O --output-format=<format> Specify output format\n\ 646 -F --target=<target> Specify COFF target\n\ 647 --preprocessor=<program> Program to use to preprocess rc file\n\ 648 -I --include-dir=<dir> Include directory when preprocessing rc file\n\ 649 -D --define <sym>[=<val>] Define SYM when preprocessing rc file\n\ 650 -U --undefine <sym> Undefine SYM when preprocessing rc file\n\ 651 -v --verbose Verbose - tells you what it's doing\n\ 652 -l --language=<val> Set language when reading rc file\n\ 653 --use-temp-file Use a temporary file instead of popen to read\n\ 654 the preprocessor output\n\ 655 --no-use-temp-file Use popen (default)\n")); 656 #ifdef YYDEBUG 657 fprintf (stream, _("\ 658 --yydebug Turn on parser debugging\n")); 659 #endif 660 fprintf (stream, _("\ 661 -r Ignored for compatibility with rc\n\ 662 @<file> Read options from <file>\n\ 663 -h --help Print this help message\n\ 664 -V --version Print version information\n")); 665 fprintf (stream, _("\ 666 FORMAT is one of rc, res, or coff, and is deduced from the file name\n\ 667 extension if not specified. A single file name is an input file.\n\ 668 No input-file is stdin, default rc. No output-file is stdout, default rc.\n")); 669 670 list_supported_targets (program_name, stream); 671 672 if (status == 0) 673 fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO); 674 675 exit (status); 676 } 677 678 /* Quote characters that will confuse the shell when we run the preprocessor. */ 679 680 static const char * 681 quot (const char *string) 682 { 683 static char *buf = 0; 684 static int buflen = 0; 685 int slen = strlen (string); 686 const char *src; 687 char *dest; 688 689 if ((buflen < slen * 2 + 2) || !buf) 690 { 691 buflen = slen * 2 + 2; 692 if (buf) 693 free (buf); 694 buf = (char *) xmalloc (buflen); 695 } 696 697 for (src=string, dest=buf; *src; src++, dest++) 698 { 699 if (*src == '(' || *src == ')' || *src == ' ') 700 *dest++ = '\\'; 701 *dest = *src; 702 } 703 *dest = 0; 704 return buf; 705 } 706 707 /* Long options. */ 708 709 /* 150 isn't special; it's just an arbitrary non-ASCII char value. */ 710 711 #define OPTION_PREPROCESSOR 150 712 #define OPTION_USE_TEMP_FILE (OPTION_PREPROCESSOR + 1) 713 #define OPTION_NO_USE_TEMP_FILE (OPTION_USE_TEMP_FILE + 1) 714 #define OPTION_YYDEBUG (OPTION_NO_USE_TEMP_FILE + 1) 715 716 static const struct option long_options[] = 717 { 718 {"input", required_argument, 0, 'i'}, 719 {"output", required_argument, 0, 'o'}, 720 {"input-format", required_argument, 0, 'J'}, 721 {"output-format", required_argument, 0, 'O'}, 722 {"target", required_argument, 0, 'F'}, 723 {"preprocessor", required_argument, 0, OPTION_PREPROCESSOR}, 724 {"include-dir", required_argument, 0, 'I'}, 725 {"define", required_argument, 0, 'D'}, 726 {"undefine", required_argument, 0, 'U'}, 727 {"verbose", no_argument, 0, 'v'}, 728 {"language", required_argument, 0, 'l'}, 729 {"use-temp-file", no_argument, 0, OPTION_USE_TEMP_FILE}, 730 {"no-use-temp-file", no_argument, 0, OPTION_NO_USE_TEMP_FILE}, 731 {"yydebug", no_argument, 0, OPTION_YYDEBUG}, 732 {"version", no_argument, 0, 'V'}, 733 {"help", no_argument, 0, 'h'}, 734 {0, no_argument, 0, 0} 735 }; 736 737 /* This keeps gcc happy when using -Wmissing-prototypes -Wstrict-prototypes. */ 738 int main (int, char **); 739 740 /* The main function. */ 741 742 int 743 main (int argc, char **argv) 744 { 745 int c; 746 char *input_filename; 747 char *output_filename; 748 enum res_format input_format; 749 enum res_format input_format_tmp; 750 enum res_format output_format; 751 char *target; 752 char *preprocessor; 753 char *preprocargs; 754 const char *quotedarg; 755 int language; 756 struct res_directory *resources; 757 int use_temp_file; 758 759 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) 760 setlocale (LC_MESSAGES, ""); 761 #endif 762 #if defined (HAVE_SETLOCALE) 763 setlocale (LC_CTYPE, ""); 764 #endif 765 bindtextdomain (PACKAGE, LOCALEDIR); 766 textdomain (PACKAGE); 767 768 program_name = argv[0]; 769 xmalloc_set_program_name (program_name); 770 771 expandargv (&argc, &argv); 772 773 bfd_init (); 774 set_default_bfd_target (); 775 776 res_init (); 777 778 input_filename = NULL; 779 output_filename = NULL; 780 input_format = RES_FORMAT_UNKNOWN; 781 output_format = RES_FORMAT_UNKNOWN; 782 target = NULL; 783 preprocessor = NULL; 784 preprocargs = NULL; 785 language = 0x409; /* LANG_ENGLISH, SUBLANG_ENGLISH_US. */ 786 use_temp_file = 0; 787 788 while ((c = getopt_long (argc, argv, "f:i:l:o:I:J:O:F:D:U:rhHvV", long_options, 789 (int *) 0)) != EOF) 790 { 791 switch (c) 792 { 793 case 'i': 794 input_filename = optarg; 795 break; 796 797 case 'f': 798 /* For compatibility with rc we accept "-fo <name>" as being the 799 equivalent of "-o <name>". We do not advertise this fact 800 though, as we do not want users to use non-GNU like command 801 line switches. */ 802 if (*optarg != 'o') 803 fatal (_("invalid option -f\n")); 804 optarg++; 805 if (* optarg == 0) 806 { 807 if (optind == argc) 808 fatal (_("No filename following the -fo option.\n")); 809 optarg = argv [optind++]; 810 } 811 /* Fall through. */ 812 813 case 'o': 814 output_filename = optarg; 815 break; 816 817 case 'J': 818 input_format = format_from_name (optarg, 1); 819 break; 820 821 case 'O': 822 output_format = format_from_name (optarg, 1); 823 break; 824 825 case 'F': 826 target = optarg; 827 break; 828 829 case OPTION_PREPROCESSOR: 830 preprocessor = optarg; 831 break; 832 833 case 'D': 834 case 'U': 835 if (preprocargs == NULL) 836 { 837 quotedarg = quot (optarg); 838 preprocargs = xmalloc (strlen (quotedarg) + 3); 839 sprintf (preprocargs, "-%c%s", c, quotedarg); 840 } 841 else 842 { 843 char *n; 844 845 quotedarg = quot (optarg); 846 n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4); 847 sprintf (n, "%s -%c%s", preprocargs, c, quotedarg); 848 free (preprocargs); 849 preprocargs = n; 850 } 851 break; 852 853 case 'r': 854 /* Ignored for compatibility with rc. */ 855 break; 856 857 case 'v': 858 verbose ++; 859 break; 860 861 case 'I': 862 /* For backward compatibility, should be removed in the future. */ 863 input_format_tmp = format_from_name (optarg, 0); 864 if (input_format_tmp != RES_FORMAT_UNKNOWN) 865 { 866 fprintf (stderr, _("Option -I is deprecated for setting the input format, please use -J instead.\n")); 867 input_format = input_format_tmp; 868 break; 869 } 870 871 if (preprocargs == NULL) 872 { 873 quotedarg = quot (optarg); 874 preprocargs = xmalloc (strlen (quotedarg) + 3); 875 sprintf (preprocargs, "-I%s", quotedarg); 876 } 877 else 878 { 879 char *n; 880 881 quotedarg = quot (optarg); 882 n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4); 883 sprintf (n, "%s -I%s", preprocargs, quotedarg); 884 free (preprocargs); 885 preprocargs = n; 886 } 887 888 { 889 struct include_dir *n, **pp; 890 891 n = (struct include_dir *) xmalloc (sizeof *n); 892 n->next = NULL; 893 n->dir = optarg; 894 895 for (pp = &include_dirs; *pp != NULL; pp = &(*pp)->next) 896 ; 897 *pp = n; 898 } 899 900 break; 901 902 case 'l': 903 language = strtol (optarg, (char **) NULL, 16); 904 break; 905 906 case OPTION_USE_TEMP_FILE: 907 use_temp_file = 1; 908 break; 909 910 case OPTION_NO_USE_TEMP_FILE: 911 use_temp_file = 0; 912 break; 913 914 #ifdef YYDEBUG 915 case OPTION_YYDEBUG: 916 yydebug = 1; 917 break; 918 #endif 919 920 case 'h': 921 case 'H': 922 usage (stdout, 0); 923 break; 924 925 case 'V': 926 print_version ("windres"); 927 break; 928 929 default: 930 usage (stderr, 1); 931 break; 932 } 933 } 934 935 if (input_filename == NULL && optind < argc) 936 { 937 input_filename = argv[optind]; 938 ++optind; 939 } 940 941 if (output_filename == NULL && optind < argc) 942 { 943 output_filename = argv[optind]; 944 ++optind; 945 } 946 947 if (argc != optind) 948 usage (stderr, 1); 949 950 if (input_format == RES_FORMAT_UNKNOWN) 951 { 952 if (input_filename == NULL) 953 input_format = RES_FORMAT_RC; 954 else 955 input_format = format_from_filename (input_filename, 1); 956 } 957 958 if (output_format == RES_FORMAT_UNKNOWN) 959 { 960 if (output_filename == NULL) 961 output_format = RES_FORMAT_RC; 962 else 963 output_format = format_from_filename (output_filename, 0); 964 } 965 966 /* Read the input file. */ 967 switch (input_format) 968 { 969 default: 970 abort (); 971 case RES_FORMAT_RC: 972 resources = read_rc_file (input_filename, preprocessor, preprocargs, 973 language, use_temp_file); 974 break; 975 case RES_FORMAT_RES: 976 resources = read_res_file (input_filename); 977 break; 978 case RES_FORMAT_COFF: 979 resources = read_coff_rsrc (input_filename, target); 980 break; 981 } 982 983 if (resources == NULL) 984 fatal (_("no resources")); 985 986 /* Sort the resources. This is required for COFF, convenient for 987 rc, and unimportant for res. */ 988 resources = sort_resources (resources); 989 990 /* Write the output file. */ 991 reswr_init (); 992 993 switch (output_format) 994 { 995 default: 996 abort (); 997 case RES_FORMAT_RC: 998 write_rc_file (output_filename, resources); 999 break; 1000 case RES_FORMAT_RES: 1001 write_res_file (output_filename, resources); 1002 break; 1003 case RES_FORMAT_COFF: 1004 write_coff_file (output_filename, target, resources); 1005 break; 1006 } 1007 1008 xexit (0); 1009 return 0; 1010 } 1011