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