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