~ubuntu-branches/ubuntu/hoary/binutils/hoary

« back to all changes in this revision

Viewing changes to binutils/windres.c

  • Committer: Bazaar Package Importer
  • Author(s): James Troup
  • Date: 2004-05-19 10:35:44 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040519103544-17h3o6e8pwndydrg
Tags: 2.14.90.0.7-8
debian/rules: don't use gcc-2.95 on m68k.  Thanks to Adam Conrad for
pointing this out.

Show diffs side-by-side

added added

removed removed

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