1ed0d50c3Schristos /* windres.c -- a program to manipulate Windows resources
2*b88e3e88Schristos Copyright (C) 1997-2020 Free Software Foundation, Inc.
3ed0d50c3Schristos Written by Ian Lance Taylor, Cygnus Support.
4ed0d50c3Schristos Rewritten by Kai Tietz, Onevision.
5ed0d50c3Schristos
6ed0d50c3Schristos This file is part of GNU Binutils.
7ed0d50c3Schristos
8ed0d50c3Schristos This program is free software; you can redistribute it and/or modify
9ed0d50c3Schristos it under the terms of the GNU General Public License as published by
10ed0d50c3Schristos the Free Software Foundation; either version 3 of the License, or
11ed0d50c3Schristos (at your option) any later version.
12ed0d50c3Schristos
13ed0d50c3Schristos This program is distributed in the hope that it will be useful,
14ed0d50c3Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
15ed0d50c3Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16ed0d50c3Schristos GNU General Public License for more details.
17ed0d50c3Schristos
18ed0d50c3Schristos You should have received a copy of the GNU General Public License
19ed0d50c3Schristos along with this program; if not, write to the Free Software
20ed0d50c3Schristos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
21ed0d50c3Schristos 02110-1301, USA. */
22ed0d50c3Schristos
23ed0d50c3Schristos /* This program can read and write Windows resources in various
24ed0d50c3Schristos formats. In particular, it can act like the rc resource compiler
25ed0d50c3Schristos program, and it can act like the cvtres res to COFF conversion
26ed0d50c3Schristos program.
27ed0d50c3Schristos
28ed0d50c3Schristos It is based on information taken from the following sources:
29ed0d50c3Schristos
30ed0d50c3Schristos * Microsoft documentation.
31ed0d50c3Schristos
32ed0d50c3Schristos * The rcl program, written by Gunther Ebert
33ed0d50c3Schristos <gunther.ebert@ixos-leipzig.de>.
34ed0d50c3Schristos
35ed0d50c3Schristos * The res2coff program, written by Pedro A. Aranda <paag@tid.es>. */
36ed0d50c3Schristos
37ed0d50c3Schristos #include "sysdep.h"
38ed0d50c3Schristos #include <assert.h>
39ed0d50c3Schristos #include "bfd.h"
40ed0d50c3Schristos #include "getopt.h"
41ed0d50c3Schristos #include "bucomm.h"
42ed0d50c3Schristos #include "libiberty.h"
43ed0d50c3Schristos #include "safe-ctype.h"
44ed0d50c3Schristos #include "obstack.h"
45ed0d50c3Schristos #include "windres.h"
46ed0d50c3Schristos
47ed0d50c3Schristos /* Used by resrc.c at least. */
48ed0d50c3Schristos
49ed0d50c3Schristos int verbose = 0;
50ed0d50c3Schristos
51ed0d50c3Schristos int target_is_bigendian = 0;
52ed0d50c3Schristos const char *def_target_arch;
53ed0d50c3Schristos
54ed0d50c3Schristos static void set_endianness (bfd *, const char *);
55ed0d50c3Schristos
56ed0d50c3Schristos /* An enumeration of format types. */
57ed0d50c3Schristos
58ed0d50c3Schristos enum res_format
59ed0d50c3Schristos {
60ed0d50c3Schristos /* Unknown format. */
61ed0d50c3Schristos RES_FORMAT_UNKNOWN,
62ed0d50c3Schristos /* Textual RC file. */
63ed0d50c3Schristos RES_FORMAT_RC,
64ed0d50c3Schristos /* Binary RES file. */
65ed0d50c3Schristos RES_FORMAT_RES,
66ed0d50c3Schristos /* COFF file. */
67ed0d50c3Schristos RES_FORMAT_COFF
68ed0d50c3Schristos };
69ed0d50c3Schristos
70ed0d50c3Schristos /* A structure used to map between format types and strings. */
71ed0d50c3Schristos
72ed0d50c3Schristos struct format_map
73ed0d50c3Schristos {
74ed0d50c3Schristos const char *name;
75ed0d50c3Schristos enum res_format format;
76ed0d50c3Schristos };
77ed0d50c3Schristos
78ed0d50c3Schristos /* A mapping between names and format types. */
79ed0d50c3Schristos
80ed0d50c3Schristos static const struct format_map format_names[] =
81ed0d50c3Schristos {
82ed0d50c3Schristos { "rc", RES_FORMAT_RC },
83ed0d50c3Schristos { "res", RES_FORMAT_RES },
84ed0d50c3Schristos { "coff", RES_FORMAT_COFF },
85ed0d50c3Schristos { NULL, RES_FORMAT_UNKNOWN }
86ed0d50c3Schristos };
87ed0d50c3Schristos
88ed0d50c3Schristos /* A mapping from file extensions to format types. */
89ed0d50c3Schristos
90ed0d50c3Schristos static const struct format_map format_fileexts[] =
91ed0d50c3Schristos {
92ed0d50c3Schristos { "rc", RES_FORMAT_RC },
93ed0d50c3Schristos { "res", RES_FORMAT_RES },
94ed0d50c3Schristos { "exe", RES_FORMAT_COFF },
95ed0d50c3Schristos { "obj", RES_FORMAT_COFF },
96ed0d50c3Schristos { "o", RES_FORMAT_COFF },
97ed0d50c3Schristos { NULL, RES_FORMAT_UNKNOWN }
98ed0d50c3Schristos };
99ed0d50c3Schristos
100ed0d50c3Schristos /* A list of include directories. */
101ed0d50c3Schristos
102ed0d50c3Schristos struct include_dir
103ed0d50c3Schristos {
104ed0d50c3Schristos struct include_dir *next;
105ed0d50c3Schristos char *dir;
106ed0d50c3Schristos };
107ed0d50c3Schristos
108ed0d50c3Schristos static struct include_dir *include_dirs;
109ed0d50c3Schristos
110ed0d50c3Schristos /* Static functions. */
111ed0d50c3Schristos
112ed0d50c3Schristos static void res_init (void);
113ed0d50c3Schristos static int extended_menuitems (const rc_menuitem *);
114ed0d50c3Schristos static enum res_format format_from_name (const char *, int);
115ed0d50c3Schristos static enum res_format format_from_filename (const char *, int);
116ed0d50c3Schristos static void usage (FILE *, int);
117ed0d50c3Schristos static int cmp_res_entry (const void *, const void *);
118ed0d50c3Schristos static rc_res_directory *sort_resources (rc_res_directory *);
119ed0d50c3Schristos static void reswr_init (void);
120ed0d50c3Schristos static const char * quot (const char *);
121ed0d50c3Schristos
122ed0d50c3Schristos static rc_uint_type target_get_8 (const void *, rc_uint_type);
123ed0d50c3Schristos static void target_put_8 (void *, rc_uint_type);
124ed0d50c3Schristos static rc_uint_type target_get_16 (const void *, rc_uint_type);
125ed0d50c3Schristos static void target_put_16 (void *, rc_uint_type);
126ed0d50c3Schristos static rc_uint_type target_get_32 (const void *, rc_uint_type);
127ed0d50c3Schristos static void target_put_32 (void *, rc_uint_type);
128ed0d50c3Schristos
129ed0d50c3Schristos
130ed0d50c3Schristos /* When we are building a resource tree, we allocate everything onto
131ed0d50c3Schristos an obstack, so that we can free it all at once if we want. */
132ed0d50c3Schristos
133ed0d50c3Schristos #define obstack_chunk_alloc xmalloc
134ed0d50c3Schristos #define obstack_chunk_free free
135ed0d50c3Schristos
136ed0d50c3Schristos /* The resource building obstack. */
137ed0d50c3Schristos
138ed0d50c3Schristos static struct obstack res_obstack;
139ed0d50c3Schristos
140ed0d50c3Schristos /* Initialize the resource building obstack. */
141ed0d50c3Schristos
142ed0d50c3Schristos static void
res_init(void)143ed0d50c3Schristos res_init (void)
144ed0d50c3Schristos {
145ed0d50c3Schristos obstack_init (&res_obstack);
146ed0d50c3Schristos }
147ed0d50c3Schristos
148ed0d50c3Schristos /* Allocate space on the resource building obstack. */
149ed0d50c3Schristos
150ed0d50c3Schristos void *
res_alloc(rc_uint_type bytes)151ed0d50c3Schristos res_alloc (rc_uint_type bytes)
152ed0d50c3Schristos {
153ed0d50c3Schristos return obstack_alloc (&res_obstack, (size_t) bytes);
154ed0d50c3Schristos }
155ed0d50c3Schristos
156ed0d50c3Schristos /* We also use an obstack to save memory used while writing out a set
157ed0d50c3Schristos of resources. */
158ed0d50c3Schristos
159ed0d50c3Schristos static struct obstack reswr_obstack;
160ed0d50c3Schristos
161ed0d50c3Schristos /* Initialize the resource writing obstack. */
162ed0d50c3Schristos
163ed0d50c3Schristos static void
reswr_init(void)164ed0d50c3Schristos reswr_init (void)
165ed0d50c3Schristos {
166ed0d50c3Schristos obstack_init (&reswr_obstack);
167ed0d50c3Schristos }
168ed0d50c3Schristos
169ed0d50c3Schristos /* Allocate space on the resource writing obstack. */
170ed0d50c3Schristos
171ed0d50c3Schristos void *
reswr_alloc(rc_uint_type bytes)172ed0d50c3Schristos reswr_alloc (rc_uint_type bytes)
173ed0d50c3Schristos {
174ed0d50c3Schristos return obstack_alloc (&reswr_obstack, (size_t) bytes);
175ed0d50c3Schristos }
176ed0d50c3Schristos
177ed0d50c3Schristos /* Open a file using the include directory search list. */
178ed0d50c3Schristos
179ed0d50c3Schristos FILE *
open_file_search(const char * filename,const char * mode,const char * errmsg,char ** real_filename)180ed0d50c3Schristos open_file_search (const char *filename, const char *mode, const char *errmsg,
181ed0d50c3Schristos char **real_filename)
182ed0d50c3Schristos {
183ed0d50c3Schristos FILE *e;
184ed0d50c3Schristos struct include_dir *d;
185ed0d50c3Schristos
186ed0d50c3Schristos e = fopen (filename, mode);
187ed0d50c3Schristos if (e != NULL)
188ed0d50c3Schristos {
189ed0d50c3Schristos *real_filename = xstrdup (filename);
190ed0d50c3Schristos return e;
191ed0d50c3Schristos }
192ed0d50c3Schristos
193ed0d50c3Schristos if (errno == ENOENT)
194ed0d50c3Schristos {
195ed0d50c3Schristos for (d = include_dirs; d != NULL; d = d->next)
196ed0d50c3Schristos {
197ed0d50c3Schristos char *n;
198ed0d50c3Schristos
199ed0d50c3Schristos n = (char *) xmalloc (strlen (d->dir) + strlen (filename) + 2);
200ed0d50c3Schristos sprintf (n, "%s/%s", d->dir, filename);
201ed0d50c3Schristos e = fopen (n, mode);
202ed0d50c3Schristos if (e != NULL)
203ed0d50c3Schristos {
204ed0d50c3Schristos *real_filename = n;
205ed0d50c3Schristos return e;
206ed0d50c3Schristos }
207ed0d50c3Schristos free (n);
208ed0d50c3Schristos
209ed0d50c3Schristos if (errno != ENOENT)
210ed0d50c3Schristos break;
211ed0d50c3Schristos }
212ed0d50c3Schristos }
213ed0d50c3Schristos
214ed0d50c3Schristos fatal (_("can't open %s `%s': %s"), errmsg, filename, strerror (errno));
215ed0d50c3Schristos
216ed0d50c3Schristos /* Return a value to avoid a compiler warning. */
217ed0d50c3Schristos return NULL;
218ed0d50c3Schristos }
219ed0d50c3Schristos
220ed0d50c3Schristos /* Compare two resource ID's. We consider name entries to come before
221ed0d50c3Schristos numeric entries, because that is how they appear in the COFF .rsrc
222ed0d50c3Schristos section. */
223ed0d50c3Schristos
224ed0d50c3Schristos int
res_id_cmp(rc_res_id a,rc_res_id b)225ed0d50c3Schristos res_id_cmp (rc_res_id a, rc_res_id b)
226ed0d50c3Schristos {
227ed0d50c3Schristos if (! a.named)
228ed0d50c3Schristos {
229ed0d50c3Schristos if (b.named)
230ed0d50c3Schristos return 1;
231ed0d50c3Schristos if (a.u.id > b.u.id)
232ed0d50c3Schristos return 1;
233ed0d50c3Schristos else if (a.u.id < b.u.id)
234ed0d50c3Schristos return -1;
235ed0d50c3Schristos else
236ed0d50c3Schristos return 0;
237ed0d50c3Schristos }
238ed0d50c3Schristos else
239ed0d50c3Schristos {
240ed0d50c3Schristos unichar *as, *ase, *bs, *bse;
241ed0d50c3Schristos
242ed0d50c3Schristos if (! b.named)
243ed0d50c3Schristos return -1;
244ed0d50c3Schristos
245ed0d50c3Schristos as = a.u.n.name;
246ed0d50c3Schristos ase = as + a.u.n.length;
247ed0d50c3Schristos bs = b.u.n.name;
248ed0d50c3Schristos bse = bs + b.u.n.length;
249ed0d50c3Schristos
250ed0d50c3Schristos while (as < ase)
251ed0d50c3Schristos {
252ed0d50c3Schristos int i;
253ed0d50c3Schristos
254ed0d50c3Schristos if (bs >= bse)
255ed0d50c3Schristos return 1;
256ed0d50c3Schristos i = (int) *as - (int) *bs;
257ed0d50c3Schristos if (i != 0)
258ed0d50c3Schristos return i;
259ed0d50c3Schristos ++as;
260ed0d50c3Schristos ++bs;
261ed0d50c3Schristos }
262ed0d50c3Schristos
263ed0d50c3Schristos if (bs < bse)
264ed0d50c3Schristos return -1;
265ed0d50c3Schristos
266ed0d50c3Schristos return 0;
267ed0d50c3Schristos }
268ed0d50c3Schristos }
269ed0d50c3Schristos
270ed0d50c3Schristos /* Print a resource ID. */
271ed0d50c3Schristos
272ed0d50c3Schristos void
res_id_print(FILE * stream,rc_res_id id,int quote)273ed0d50c3Schristos res_id_print (FILE *stream, rc_res_id id, int quote)
274ed0d50c3Schristos {
275ed0d50c3Schristos if (! id.named)
276ed0d50c3Schristos fprintf (stream, "%u", (int) id.u.id);
277ed0d50c3Schristos else
278ed0d50c3Schristos {
279ed0d50c3Schristos if (quote)
280ed0d50c3Schristos unicode_print_quoted (stream, id.u.n.name, id.u.n.length);
281ed0d50c3Schristos else
282ed0d50c3Schristos unicode_print (stream, id.u.n.name, id.u.n.length);
283ed0d50c3Schristos }
284ed0d50c3Schristos }
285ed0d50c3Schristos
286ed0d50c3Schristos /* Print a list of resource ID's. */
287ed0d50c3Schristos
288ed0d50c3Schristos void
res_ids_print(FILE * stream,int cids,const rc_res_id * ids)289ed0d50c3Schristos res_ids_print (FILE *stream, int cids, const rc_res_id *ids)
290ed0d50c3Schristos {
291ed0d50c3Schristos int i;
292ed0d50c3Schristos
293ed0d50c3Schristos for (i = 0; i < cids; i++)
294ed0d50c3Schristos {
295ed0d50c3Schristos res_id_print (stream, ids[i], 1);
296ed0d50c3Schristos if (i + 1 < cids)
297ed0d50c3Schristos fprintf (stream, ": ");
298ed0d50c3Schristos }
299ed0d50c3Schristos }
300ed0d50c3Schristos
301ed0d50c3Schristos /* Convert an ASCII string to a resource ID. */
302ed0d50c3Schristos
303ed0d50c3Schristos void
res_string_to_id(rc_res_id * res_id,const char * string)304ed0d50c3Schristos res_string_to_id (rc_res_id *res_id, const char *string)
305ed0d50c3Schristos {
306ed0d50c3Schristos res_id->named = 1;
307ed0d50c3Schristos unicode_from_ascii (&res_id->u.n.length, &res_id->u.n.name, string);
308ed0d50c3Schristos }
309ed0d50c3Schristos
310ed0d50c3Schristos /* Convert an unicode string to a resource ID. */
311ed0d50c3Schristos void
res_unistring_to_id(rc_res_id * res_id,const unichar * u)312ed0d50c3Schristos res_unistring_to_id (rc_res_id *res_id, const unichar *u)
313ed0d50c3Schristos {
314ed0d50c3Schristos res_id->named = 1;
315ed0d50c3Schristos res_id->u.n.length = unichar_len (u);
316ed0d50c3Schristos res_id->u.n.name = unichar_dup_uppercase (u);
317ed0d50c3Schristos }
318ed0d50c3Schristos
319ed0d50c3Schristos /* Define a resource. The arguments are the resource tree, RESOURCES,
320ed0d50c3Schristos and the location at which to put it in the tree, CIDS and IDS.
321ed0d50c3Schristos This returns a newly allocated rc_res_resource structure, which the
322ed0d50c3Schristos caller is expected to initialize. If DUPOK is non-zero, then if a
323ed0d50c3Schristos resource with this ID exists, it is returned. Otherwise, a warning
324ed0d50c3Schristos is issued, and a new resource is created replacing the existing
325ed0d50c3Schristos one. */
326ed0d50c3Schristos
327ed0d50c3Schristos rc_res_resource *
define_resource(rc_res_directory ** resources,int cids,const rc_res_id * ids,int dupok)328ed0d50c3Schristos define_resource (rc_res_directory **resources, int cids,
329ed0d50c3Schristos const rc_res_id *ids, int dupok)
330ed0d50c3Schristos {
331ed0d50c3Schristos rc_res_entry *re = NULL;
332ed0d50c3Schristos int i;
333ed0d50c3Schristos
334ed0d50c3Schristos assert (cids > 0);
335ed0d50c3Schristos for (i = 0; i < cids; i++)
336ed0d50c3Schristos {
337ed0d50c3Schristos rc_res_entry **pp;
338ed0d50c3Schristos
339ed0d50c3Schristos if (*resources == NULL)
340ed0d50c3Schristos {
341ed0d50c3Schristos *resources = ((rc_res_directory *)
342ed0d50c3Schristos res_alloc (sizeof (rc_res_directory)));
343ed0d50c3Schristos (*resources)->characteristics = 0;
344ed0d50c3Schristos /* Using a real timestamp only serves to create non-deterministic
345ed0d50c3Schristos results. Use zero instead. */
346ed0d50c3Schristos (*resources)->time = 0;
347ed0d50c3Schristos (*resources)->major = 0;
348ed0d50c3Schristos (*resources)->minor = 0;
349ed0d50c3Schristos (*resources)->entries = NULL;
350ed0d50c3Schristos }
351ed0d50c3Schristos
352ed0d50c3Schristos for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next)
353ed0d50c3Schristos if (res_id_cmp ((*pp)->id, ids[i]) == 0)
354ed0d50c3Schristos break;
355ed0d50c3Schristos
356ed0d50c3Schristos if (*pp != NULL)
357ed0d50c3Schristos re = *pp;
358ed0d50c3Schristos else
359ed0d50c3Schristos {
360ed0d50c3Schristos re = (rc_res_entry *) res_alloc (sizeof (rc_res_entry));
361ed0d50c3Schristos re->next = NULL;
362ed0d50c3Schristos re->id = ids[i];
363ed0d50c3Schristos if ((i + 1) < cids)
364ed0d50c3Schristos {
365ed0d50c3Schristos re->subdir = 1;
366ed0d50c3Schristos re->u.dir = NULL;
367ed0d50c3Schristos }
368ed0d50c3Schristos else
369ed0d50c3Schristos {
370ed0d50c3Schristos re->subdir = 0;
371ed0d50c3Schristos re->u.res = NULL;
372ed0d50c3Schristos }
373ed0d50c3Schristos
374ed0d50c3Schristos *pp = re;
375ed0d50c3Schristos }
376ed0d50c3Schristos
377ed0d50c3Schristos if ((i + 1) < cids)
378ed0d50c3Schristos {
379ed0d50c3Schristos if (! re->subdir)
380ed0d50c3Schristos {
381ed0d50c3Schristos fprintf (stderr, "%s: ", program_name);
382ed0d50c3Schristos res_ids_print (stderr, i, ids);
383ed0d50c3Schristos fprintf (stderr, _(": expected to be a directory\n"));
384ed0d50c3Schristos xexit (1);
385ed0d50c3Schristos }
386ed0d50c3Schristos
387ed0d50c3Schristos resources = &re->u.dir;
388ed0d50c3Schristos }
389ed0d50c3Schristos }
390ed0d50c3Schristos
391ed0d50c3Schristos if (re->subdir)
392ed0d50c3Schristos {
393ed0d50c3Schristos fprintf (stderr, "%s: ", program_name);
394ed0d50c3Schristos res_ids_print (stderr, cids, ids);
395ed0d50c3Schristos fprintf (stderr, _(": expected to be a leaf\n"));
396ed0d50c3Schristos xexit (1);
397ed0d50c3Schristos }
398ed0d50c3Schristos
399ed0d50c3Schristos if (re->u.res != NULL)
400ed0d50c3Schristos {
401ed0d50c3Schristos if (dupok)
402ed0d50c3Schristos return re->u.res;
403ed0d50c3Schristos
404ed0d50c3Schristos fprintf (stderr, _("%s: warning: "), program_name);
405ed0d50c3Schristos res_ids_print (stderr, cids, ids);
406ed0d50c3Schristos fprintf (stderr, _(": duplicate value\n"));
407ed0d50c3Schristos }
408ed0d50c3Schristos
409ed0d50c3Schristos re->u.res = ((rc_res_resource *)
410ed0d50c3Schristos res_alloc (sizeof (rc_res_resource)));
411ed0d50c3Schristos memset (re->u.res, 0, sizeof (rc_res_resource));
412ed0d50c3Schristos
413ed0d50c3Schristos re->u.res->type = RES_TYPE_UNINITIALIZED;
414ed0d50c3Schristos return re->u.res;
415ed0d50c3Schristos }
416ed0d50c3Schristos
417ed0d50c3Schristos /* Define a standard resource. This is a version of define_resource
418ed0d50c3Schristos that just takes type, name, and language arguments. */
419ed0d50c3Schristos
420ed0d50c3Schristos rc_res_resource *
define_standard_resource(rc_res_directory ** resources,int type,rc_res_id name,rc_uint_type language,int dupok)421ed0d50c3Schristos define_standard_resource (rc_res_directory **resources, int type,
422ed0d50c3Schristos rc_res_id name, rc_uint_type language, int dupok)
423ed0d50c3Schristos {
424ed0d50c3Schristos rc_res_id a[3];
425ed0d50c3Schristos
426ed0d50c3Schristos a[0].named = 0;
427ed0d50c3Schristos a[0].u.id = type;
428ed0d50c3Schristos a[1] = name;
429ed0d50c3Schristos a[2].named = 0;
430ed0d50c3Schristos a[2].u.id = language;
431ed0d50c3Schristos return define_resource (resources, 3, a, dupok);
432ed0d50c3Schristos }
433ed0d50c3Schristos
434ed0d50c3Schristos /* Comparison routine for resource sorting. */
435ed0d50c3Schristos
436ed0d50c3Schristos static int
cmp_res_entry(const void * p1,const void * p2)437ed0d50c3Schristos cmp_res_entry (const void *p1, const void *p2)
438ed0d50c3Schristos {
439ed0d50c3Schristos const rc_res_entry **re1, **re2;
440ed0d50c3Schristos
441ed0d50c3Schristos re1 = (const rc_res_entry **) p1;
442ed0d50c3Schristos re2 = (const rc_res_entry **) p2;
443ed0d50c3Schristos return res_id_cmp ((*re1)->id, (*re2)->id);
444ed0d50c3Schristos }
445ed0d50c3Schristos
446ed0d50c3Schristos /* Sort the resources. */
447ed0d50c3Schristos
448ed0d50c3Schristos static rc_res_directory *
sort_resources(rc_res_directory * resdir)449ed0d50c3Schristos sort_resources (rc_res_directory *resdir)
450ed0d50c3Schristos {
451ed0d50c3Schristos int c, i;
452ed0d50c3Schristos rc_res_entry *re;
453ed0d50c3Schristos rc_res_entry **a;
454ed0d50c3Schristos
455ed0d50c3Schristos if (resdir->entries == NULL)
456ed0d50c3Schristos return resdir;
457ed0d50c3Schristos
458ed0d50c3Schristos c = 0;
459ed0d50c3Schristos for (re = resdir->entries; re != NULL; re = re->next)
460ed0d50c3Schristos ++c;
461ed0d50c3Schristos
462ed0d50c3Schristos /* This is a recursive routine, so using xmalloc is probably better
463ed0d50c3Schristos than alloca. */
464ed0d50c3Schristos a = (rc_res_entry **) xmalloc (c * sizeof (rc_res_entry *));
465ed0d50c3Schristos
466ed0d50c3Schristos for (i = 0, re = resdir->entries; re != NULL; re = re->next, i++)
467ed0d50c3Schristos a[i] = re;
468ed0d50c3Schristos
469ed0d50c3Schristos qsort (a, c, sizeof (rc_res_entry *), cmp_res_entry);
470ed0d50c3Schristos
471ed0d50c3Schristos resdir->entries = a[0];
472ed0d50c3Schristos for (i = 0; i < c - 1; i++)
473ed0d50c3Schristos a[i]->next = a[i + 1];
474ed0d50c3Schristos a[i]->next = NULL;
475ed0d50c3Schristos
476ed0d50c3Schristos free (a);
477ed0d50c3Schristos
478ed0d50c3Schristos /* Now sort the subdirectories. */
479ed0d50c3Schristos
480ed0d50c3Schristos for (re = resdir->entries; re != NULL; re = re->next)
481ed0d50c3Schristos if (re->subdir)
482ed0d50c3Schristos re->u.dir = sort_resources (re->u.dir);
483ed0d50c3Schristos
484ed0d50c3Schristos return resdir;
485ed0d50c3Schristos }
486ed0d50c3Schristos
487ed0d50c3Schristos /* Return whether the dialog resource DIALOG is a DIALOG or a
488ed0d50c3Schristos DIALOGEX. */
489ed0d50c3Schristos
490ed0d50c3Schristos int
extended_dialog(const rc_dialog * dialog)491ed0d50c3Schristos extended_dialog (const rc_dialog *dialog)
492ed0d50c3Schristos {
493ed0d50c3Schristos const rc_dialog_control *c;
494ed0d50c3Schristos
495ed0d50c3Schristos if (dialog->ex != NULL)
496ed0d50c3Schristos return 1;
497ed0d50c3Schristos
498ed0d50c3Schristos for (c = dialog->controls; c != NULL; c = c->next)
499ed0d50c3Schristos if (c->data != NULL || c->help != 0)
500ed0d50c3Schristos return 1;
501ed0d50c3Schristos
502ed0d50c3Schristos return 0;
503ed0d50c3Schristos }
504ed0d50c3Schristos
505ed0d50c3Schristos /* Return whether MENUITEMS are a MENU or a MENUEX. */
506ed0d50c3Schristos
507ed0d50c3Schristos int
extended_menu(const rc_menu * menu)508ed0d50c3Schristos extended_menu (const rc_menu *menu)
509ed0d50c3Schristos {
510ed0d50c3Schristos return extended_menuitems (menu->items);
511ed0d50c3Schristos }
512ed0d50c3Schristos
513ed0d50c3Schristos static int
extended_menuitems(const rc_menuitem * menuitems)514ed0d50c3Schristos extended_menuitems (const rc_menuitem *menuitems)
515ed0d50c3Schristos {
516ed0d50c3Schristos const rc_menuitem *mi;
517ed0d50c3Schristos
518ed0d50c3Schristos for (mi = menuitems; mi != NULL; mi = mi->next)
519ed0d50c3Schristos {
520ed0d50c3Schristos if (mi->help != 0 || mi->state != 0)
521ed0d50c3Schristos return 1;
522ed0d50c3Schristos if (mi->popup != NULL && mi->id != 0)
523ed0d50c3Schristos return 1;
524ed0d50c3Schristos if ((mi->type
525ed0d50c3Schristos & ~ (MENUITEM_CHECKED
526ed0d50c3Schristos | MENUITEM_GRAYED
527ed0d50c3Schristos | MENUITEM_HELP
528ed0d50c3Schristos | MENUITEM_INACTIVE
529ed0d50c3Schristos | MENUITEM_MENUBARBREAK
530ed0d50c3Schristos | MENUITEM_MENUBREAK))
531ed0d50c3Schristos != 0)
532ed0d50c3Schristos return 1;
533ed0d50c3Schristos if (mi->popup != NULL)
534ed0d50c3Schristos {
535ed0d50c3Schristos if (extended_menuitems (mi->popup))
536ed0d50c3Schristos return 1;
537ed0d50c3Schristos }
538ed0d50c3Schristos }
539ed0d50c3Schristos
540ed0d50c3Schristos return 0;
541ed0d50c3Schristos }
542ed0d50c3Schristos
543ed0d50c3Schristos /* Convert a string to a format type, or exit if it can't be done. */
544ed0d50c3Schristos
545ed0d50c3Schristos static enum res_format
format_from_name(const char * name,int exit_on_error)546ed0d50c3Schristos format_from_name (const char *name, int exit_on_error)
547ed0d50c3Schristos {
548ed0d50c3Schristos const struct format_map *m;
549ed0d50c3Schristos
550ed0d50c3Schristos for (m = format_names; m->name != NULL; m++)
551ed0d50c3Schristos if (strcasecmp (m->name, name) == 0)
552ed0d50c3Schristos break;
553ed0d50c3Schristos
554ed0d50c3Schristos if (m->name == NULL && exit_on_error)
555ed0d50c3Schristos {
556ed0d50c3Schristos non_fatal (_("unknown format type `%s'"), name);
557ed0d50c3Schristos fprintf (stderr, _("%s: supported formats:"), program_name);
558ed0d50c3Schristos for (m = format_names; m->name != NULL; m++)
559ed0d50c3Schristos fprintf (stderr, " %s", m->name);
560ed0d50c3Schristos fprintf (stderr, "\n");
561ed0d50c3Schristos xexit (1);
562ed0d50c3Schristos }
563ed0d50c3Schristos
564ed0d50c3Schristos return m->format;
565ed0d50c3Schristos }
566ed0d50c3Schristos
567ed0d50c3Schristos /* Work out a format type given a file name. If INPUT is non-zero,
568ed0d50c3Schristos it's OK to look at the file itself. */
569ed0d50c3Schristos
570ed0d50c3Schristos static enum res_format
format_from_filename(const char * filename,int input)571ed0d50c3Schristos format_from_filename (const char *filename, int input)
572ed0d50c3Schristos {
573ed0d50c3Schristos const char *ext;
574ed0d50c3Schristos FILE *e;
575ed0d50c3Schristos bfd_byte b1, b2, b3, b4, b5;
576ed0d50c3Schristos int magic;
577ed0d50c3Schristos
578ed0d50c3Schristos /* If we have an extension, see if we recognize it as implying a
579ed0d50c3Schristos particular format. */
580ed0d50c3Schristos ext = strrchr (filename, '.');
581ed0d50c3Schristos if (ext != NULL)
582ed0d50c3Schristos {
583ed0d50c3Schristos const struct format_map *m;
584ed0d50c3Schristos
585ed0d50c3Schristos ++ext;
586ed0d50c3Schristos for (m = format_fileexts; m->name != NULL; m++)
587ed0d50c3Schristos if (strcasecmp (m->name, ext) == 0)
588ed0d50c3Schristos return m->format;
589ed0d50c3Schristos }
590ed0d50c3Schristos
591ed0d50c3Schristos /* If we don't recognize the name of an output file, assume it's a
592ed0d50c3Schristos COFF file. */
593ed0d50c3Schristos if (! input)
594ed0d50c3Schristos return RES_FORMAT_COFF;
595ed0d50c3Schristos
596ed0d50c3Schristos /* Read the first few bytes of the file to see if we can guess what
597ed0d50c3Schristos it is. */
598ed0d50c3Schristos e = fopen (filename, FOPEN_RB);
599ed0d50c3Schristos if (e == NULL)
600ed0d50c3Schristos fatal ("%s: %s", filename, strerror (errno));
601ed0d50c3Schristos
602ed0d50c3Schristos b1 = getc (e);
603ed0d50c3Schristos b2 = getc (e);
604ed0d50c3Schristos b3 = getc (e);
605ed0d50c3Schristos b4 = getc (e);
606ed0d50c3Schristos b5 = getc (e);
607ed0d50c3Schristos
608ed0d50c3Schristos fclose (e);
609ed0d50c3Schristos
610ed0d50c3Schristos /* A PE executable starts with 0x4d 0x5a. */
611ed0d50c3Schristos if (b1 == 0x4d && b2 == 0x5a)
612ed0d50c3Schristos return RES_FORMAT_COFF;
613ed0d50c3Schristos
614ed0d50c3Schristos /* A COFF .o file starts with a COFF magic number. */
615ed0d50c3Schristos magic = (b2 << 8) | b1;
616ed0d50c3Schristos switch (magic)
617ed0d50c3Schristos {
618ed0d50c3Schristos case 0x14c: /* i386 */
619ed0d50c3Schristos case 0x166: /* MIPS */
620ed0d50c3Schristos case 0x184: /* Alpha */
621ed0d50c3Schristos case 0x268: /* 68k */
622ed0d50c3Schristos case 0x1f0: /* PowerPC */
623ed0d50c3Schristos case 0x290: /* PA */
624ed0d50c3Schristos return RES_FORMAT_COFF;
625ed0d50c3Schristos }
626ed0d50c3Schristos
627ed0d50c3Schristos /* A RES file starts with 0x0 0x0 0x0 0x0 0x20 0x0 0x0 0x0. */
628ed0d50c3Schristos if (b1 == 0 && b2 == 0 && b3 == 0 && b4 == 0 && b5 == 0x20)
629ed0d50c3Schristos return RES_FORMAT_RES;
630ed0d50c3Schristos
631ed0d50c3Schristos /* If every character is printable or space, assume it's an RC file. */
632ed0d50c3Schristos if ((ISPRINT (b1) || ISSPACE (b1))
633ed0d50c3Schristos && (ISPRINT (b2) || ISSPACE (b2))
634ed0d50c3Schristos && (ISPRINT (b3) || ISSPACE (b3))
635ed0d50c3Schristos && (ISPRINT (b4) || ISSPACE (b4))
636ed0d50c3Schristos && (ISPRINT (b5) || ISSPACE (b5)))
637ed0d50c3Schristos return RES_FORMAT_RC;
638ed0d50c3Schristos
639ed0d50c3Schristos /* Otherwise, we give up. */
640ed0d50c3Schristos fatal (_("can not determine type of file `%s'; use the -J option"),
641ed0d50c3Schristos filename);
642ed0d50c3Schristos
643ed0d50c3Schristos /* Return something to silence the compiler warning. */
644ed0d50c3Schristos return RES_FORMAT_UNKNOWN;
645ed0d50c3Schristos }
646ed0d50c3Schristos
647ed0d50c3Schristos /* Print a usage message and exit. */
648ed0d50c3Schristos
649ed0d50c3Schristos static void
usage(FILE * stream,int status)650ed0d50c3Schristos usage (FILE *stream, int status)
651ed0d50c3Schristos {
652ed0d50c3Schristos fprintf (stream, _("Usage: %s [option(s)] [input-file] [output-file]\n"),
653ed0d50c3Schristos program_name);
654ed0d50c3Schristos fprintf (stream, _(" The options are:\n\
655ed0d50c3Schristos -i --input=<file> Name input file\n\
656ed0d50c3Schristos -o --output=<file> Name output file\n\
657ed0d50c3Schristos -J --input-format=<format> Specify input format\n\
658ed0d50c3Schristos -O --output-format=<format> Specify output format\n\
659ed0d50c3Schristos -F --target=<target> Specify COFF target\n\
660ed0d50c3Schristos --preprocessor=<program> Program to use to preprocess rc file\n\
661ed0d50c3Schristos --preprocessor-arg=<arg> Additional preprocessor argument\n\
662ed0d50c3Schristos -I --include-dir=<dir> Include directory when preprocessing rc file\n\
663ed0d50c3Schristos -D --define <sym>[=<val>] Define SYM when preprocessing rc file\n\
664ed0d50c3Schristos -U --undefine <sym> Undefine SYM when preprocessing rc file\n\
665ed0d50c3Schristos -v --verbose Verbose - tells you what it's doing\n\
666ed0d50c3Schristos -c --codepage=<codepage> Specify default codepage\n\
667ed0d50c3Schristos -l --language=<val> Set language when reading rc file\n\
668ed0d50c3Schristos --use-temp-file Use a temporary file instead of popen to read\n\
669ed0d50c3Schristos the preprocessor output\n\
670ed0d50c3Schristos --no-use-temp-file Use popen (default)\n"));
671ed0d50c3Schristos #ifdef YYDEBUG
672ed0d50c3Schristos fprintf (stream, _("\
673ed0d50c3Schristos --yydebug Turn on parser debugging\n"));
674ed0d50c3Schristos #endif
675ed0d50c3Schristos fprintf (stream, _("\
676ed0d50c3Schristos -r Ignored for compatibility with rc\n\
677ed0d50c3Schristos @<file> Read options from <file>\n\
678ed0d50c3Schristos -h --help Print this help message\n\
679ed0d50c3Schristos -V --version Print version information\n"));
680ed0d50c3Schristos fprintf (stream, _("\
681ed0d50c3Schristos FORMAT is one of rc, res, or coff, and is deduced from the file name\n\
682ed0d50c3Schristos extension if not specified. A single file name is an input file.\n\
683ed0d50c3Schristos No input-file is stdin, default rc. No output-file is stdout, default rc.\n"));
684ed0d50c3Schristos
685ed0d50c3Schristos list_supported_targets (program_name, stream);
686ed0d50c3Schristos
687ed0d50c3Schristos if (REPORT_BUGS_TO[0] && status == 0)
688ed0d50c3Schristos fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
689ed0d50c3Schristos
690ed0d50c3Schristos exit (status);
691ed0d50c3Schristos }
692ed0d50c3Schristos
693ed0d50c3Schristos /* Quote characters that will confuse the shell when we run the preprocessor. */
694ed0d50c3Schristos
695ed0d50c3Schristos static const char *
quot(const char * string)696ed0d50c3Schristos quot (const char *string)
697ed0d50c3Schristos {
698ed0d50c3Schristos static char *buf = 0;
699ed0d50c3Schristos static int buflen = 0;
700ed0d50c3Schristos int slen = strlen (string);
701ed0d50c3Schristos const char *src;
702ed0d50c3Schristos char *dest;
703ed0d50c3Schristos
704ed0d50c3Schristos if ((buflen < slen * 2 + 2) || ! buf)
705ed0d50c3Schristos {
706ed0d50c3Schristos buflen = slen * 2 + 2;
707ed0d50c3Schristos if (buf)
708ed0d50c3Schristos free (buf);
709ed0d50c3Schristos buf = (char *) xmalloc (buflen);
710ed0d50c3Schristos }
711ed0d50c3Schristos
712ed0d50c3Schristos for (src=string, dest=buf; *src; src++, dest++)
713ed0d50c3Schristos {
714ed0d50c3Schristos if (*src == '(' || *src == ')' || *src == ' ')
715ed0d50c3Schristos *dest++ = '\\';
716ed0d50c3Schristos *dest = *src;
717ed0d50c3Schristos }
718ed0d50c3Schristos *dest = 0;
719ed0d50c3Schristos return buf;
720ed0d50c3Schristos }
721ed0d50c3Schristos
722ed0d50c3Schristos /* Long options. */
723ed0d50c3Schristos
724ed0d50c3Schristos enum option_values
725ed0d50c3Schristos {
726ed0d50c3Schristos /* 150 isn't special; it's just an arbitrary non-ASCII char value. */
727ed0d50c3Schristos OPTION_PREPROCESSOR = 150,
728ed0d50c3Schristos OPTION_USE_TEMP_FILE,
729ed0d50c3Schristos OPTION_NO_USE_TEMP_FILE,
730ed0d50c3Schristos OPTION_YYDEBUG,
731ed0d50c3Schristos OPTION_INCLUDE_DIR,
732ed0d50c3Schristos OPTION_PREPROCESSOR_ARG
733ed0d50c3Schristos };
734ed0d50c3Schristos
735ed0d50c3Schristos static const struct option long_options[] =
736ed0d50c3Schristos {
737ed0d50c3Schristos {"input", required_argument, 0, 'i'},
738ed0d50c3Schristos {"output", required_argument, 0, 'o'},
739ed0d50c3Schristos {"input-format", required_argument, 0, 'J'},
740ed0d50c3Schristos {"output-format", required_argument, 0, 'O'},
741ed0d50c3Schristos {"target", required_argument, 0, 'F'},
742ed0d50c3Schristos {"preprocessor", required_argument, 0, OPTION_PREPROCESSOR},
743ed0d50c3Schristos {"preprocessor-arg", required_argument, 0, OPTION_PREPROCESSOR_ARG},
744ed0d50c3Schristos {"include-dir", required_argument, 0, OPTION_INCLUDE_DIR},
745ed0d50c3Schristos {"define", required_argument, 0, 'D'},
746ed0d50c3Schristos {"undefine", required_argument, 0, 'U'},
747ed0d50c3Schristos {"verbose", no_argument, 0, 'v'},
748ed0d50c3Schristos {"codepage", required_argument, 0, 'c'},
749ed0d50c3Schristos {"language", required_argument, 0, 'l'},
750ed0d50c3Schristos {"use-temp-file", no_argument, 0, OPTION_USE_TEMP_FILE},
751ed0d50c3Schristos {"no-use-temp-file", no_argument, 0, OPTION_NO_USE_TEMP_FILE},
752ed0d50c3Schristos {"yydebug", no_argument, 0, OPTION_YYDEBUG},
753ed0d50c3Schristos {"version", no_argument, 0, 'V'},
754ed0d50c3Schristos {"help", no_argument, 0, 'h'},
755ed0d50c3Schristos {0, no_argument, 0, 0}
756ed0d50c3Schristos };
757ed0d50c3Schristos
758ed0d50c3Schristos void
windres_add_include_dir(const char * p)759ed0d50c3Schristos windres_add_include_dir (const char *p)
760ed0d50c3Schristos {
761ed0d50c3Schristos struct include_dir *n, **pp;
762ed0d50c3Schristos
763ed0d50c3Schristos /* Computing paths is often complicated and error prone.
764ed0d50c3Schristos The easiest way to check for mistakes is at the time
765ed0d50c3Schristos we add them to include_dirs. */
766ed0d50c3Schristos assert (p != NULL);
767ed0d50c3Schristos assert (*p != '\0');
768ed0d50c3Schristos
769ed0d50c3Schristos n = xmalloc (sizeof *n);
770ed0d50c3Schristos n->next = NULL;
771ed0d50c3Schristos n->dir = (char * ) p;
772ed0d50c3Schristos
773ed0d50c3Schristos for (pp = &include_dirs; *pp != NULL; pp = &(*pp)->next)
774ed0d50c3Schristos ;
775ed0d50c3Schristos *pp = n;
776ed0d50c3Schristos }
777ed0d50c3Schristos
778ed0d50c3Schristos /* This keeps gcc happy when using -Wmissing-prototypes -Wstrict-prototypes. */
779ed0d50c3Schristos int main (int, char **);
780ed0d50c3Schristos
781ed0d50c3Schristos /* The main function. */
782ed0d50c3Schristos
783ed0d50c3Schristos int
main(int argc,char ** argv)784ed0d50c3Schristos main (int argc, char **argv)
785ed0d50c3Schristos {
786ed0d50c3Schristos int c;
787ed0d50c3Schristos char *input_filename;
788ed0d50c3Schristos char *output_filename;
789ed0d50c3Schristos enum res_format input_format;
790ed0d50c3Schristos enum res_format input_format_tmp;
791ed0d50c3Schristos enum res_format output_format;
792ed0d50c3Schristos char *target;
793ed0d50c3Schristos char *preprocessor;
794ed0d50c3Schristos char *preprocargs;
795ed0d50c3Schristos const char *quotedarg;
796ed0d50c3Schristos int language;
797ed0d50c3Schristos rc_res_directory *resources;
798ed0d50c3Schristos int use_temp_file;
799ed0d50c3Schristos
800ed0d50c3Schristos #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
801ed0d50c3Schristos setlocale (LC_MESSAGES, "");
802ed0d50c3Schristos #endif
803ed0d50c3Schristos #if defined (HAVE_SETLOCALE)
804ed0d50c3Schristos setlocale (LC_CTYPE, "");
805ed0d50c3Schristos #endif
806ed0d50c3Schristos bindtextdomain (PACKAGE, LOCALEDIR);
807ed0d50c3Schristos textdomain (PACKAGE);
808ed0d50c3Schristos
809ed0d50c3Schristos program_name = argv[0];
810ed0d50c3Schristos xmalloc_set_program_name (program_name);
811ed0d50c3Schristos bfd_set_error_program_name (program_name);
812ed0d50c3Schristos
813ed0d50c3Schristos expandargv (&argc, &argv);
814ed0d50c3Schristos
815*b88e3e88Schristos if (bfd_init () != BFD_INIT_MAGIC)
816*b88e3e88Schristos fatal (_("fatal error: libbfd ABI mismatch"));
817ed0d50c3Schristos set_default_bfd_target ();
818ed0d50c3Schristos
819ed0d50c3Schristos res_init ();
820ed0d50c3Schristos
821ed0d50c3Schristos input_filename = NULL;
822ed0d50c3Schristos output_filename = NULL;
823ed0d50c3Schristos input_format = RES_FORMAT_UNKNOWN;
824ed0d50c3Schristos output_format = RES_FORMAT_UNKNOWN;
825ed0d50c3Schristos target = NULL;
826ed0d50c3Schristos preprocessor = NULL;
827ed0d50c3Schristos preprocargs = NULL;
828ed0d50c3Schristos language = 0x409; /* LANG_ENGLISH, SUBLANG_ENGLISH_US. */
829ed0d50c3Schristos use_temp_file = 0;
830ed0d50c3Schristos
831ed0d50c3Schristos while ((c = getopt_long (argc, argv, "c:f:i:l:o:I:J:O:F:D:U:rhHvV", long_options,
832ed0d50c3Schristos (int *) 0)) != EOF)
833ed0d50c3Schristos {
834ed0d50c3Schristos switch (c)
835ed0d50c3Schristos {
836ed0d50c3Schristos case 'c':
837ed0d50c3Schristos {
838ed0d50c3Schristos rc_uint_type ncp;
839ed0d50c3Schristos
840ed0d50c3Schristos if (optarg[0] == '0' && (optarg[1] == 'x' || optarg[1] == 'X'))
841ed0d50c3Schristos ncp = (rc_uint_type) strtol (optarg + 2, NULL, 16);
842ed0d50c3Schristos else
843ed0d50c3Schristos ncp = (rc_uint_type) strtol (optarg, NULL, 10);
844ed0d50c3Schristos if (ncp == CP_UTF16 || ! unicode_is_valid_codepage (ncp))
845ed0d50c3Schristos fatal (_("invalid codepage specified.\n"));
846ed0d50c3Schristos wind_default_codepage = wind_current_codepage = ncp;
847ed0d50c3Schristos }
848ed0d50c3Schristos break;
849ed0d50c3Schristos
850ed0d50c3Schristos case 'i':
851ed0d50c3Schristos input_filename = optarg;
852ed0d50c3Schristos break;
853ed0d50c3Schristos
854ed0d50c3Schristos case 'f':
855ed0d50c3Schristos /* For compatibility with rc we accept "-fo <name>" as being the
856ed0d50c3Schristos equivalent of "-o <name>". We do not advertise this fact
857ed0d50c3Schristos though, as we do not want users to use non-GNU like command
858ed0d50c3Schristos line switches. */
859ed0d50c3Schristos if (*optarg != 'o')
860ed0d50c3Schristos fatal (_("invalid option -f\n"));
861ed0d50c3Schristos optarg++;
862ed0d50c3Schristos if (* optarg == 0)
863ed0d50c3Schristos {
864ed0d50c3Schristos if (optind == argc)
865ed0d50c3Schristos fatal (_("No filename following the -fo option.\n"));
866ed0d50c3Schristos optarg = argv [optind++];
867ed0d50c3Schristos }
868ed0d50c3Schristos /* Fall through. */
869ed0d50c3Schristos
870ed0d50c3Schristos case 'o':
871ed0d50c3Schristos output_filename = optarg;
872ed0d50c3Schristos break;
873ed0d50c3Schristos
874ed0d50c3Schristos case 'J':
875ed0d50c3Schristos input_format = format_from_name (optarg, 1);
876ed0d50c3Schristos break;
877ed0d50c3Schristos
878ed0d50c3Schristos case 'O':
879ed0d50c3Schristos output_format = format_from_name (optarg, 1);
880ed0d50c3Schristos break;
881ed0d50c3Schristos
882ed0d50c3Schristos case 'F':
883ed0d50c3Schristos target = optarg;
884ed0d50c3Schristos break;
885ed0d50c3Schristos
886ed0d50c3Schristos case OPTION_PREPROCESSOR:
887ed0d50c3Schristos preprocessor = optarg;
888ed0d50c3Schristos break;
889ed0d50c3Schristos
890ed0d50c3Schristos case OPTION_PREPROCESSOR_ARG:
891ed0d50c3Schristos if (preprocargs == NULL)
892ed0d50c3Schristos {
893ed0d50c3Schristos quotedarg = quot (optarg);
894ed0d50c3Schristos preprocargs = xstrdup (quotedarg);
895ed0d50c3Schristos }
896ed0d50c3Schristos else
897ed0d50c3Schristos {
898ed0d50c3Schristos char *n;
899ed0d50c3Schristos
900ed0d50c3Schristos quotedarg = quot (optarg);
901ed0d50c3Schristos n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 2);
902ed0d50c3Schristos sprintf (n, "%s %s", preprocargs, quotedarg);
903ed0d50c3Schristos free (preprocargs);
904ed0d50c3Schristos preprocargs = n;
905ed0d50c3Schristos }
906ed0d50c3Schristos break;
907ed0d50c3Schristos
908ed0d50c3Schristos case 'D':
909ed0d50c3Schristos case 'U':
910ed0d50c3Schristos if (preprocargs == NULL)
911ed0d50c3Schristos {
912ed0d50c3Schristos quotedarg = quot (optarg);
913ed0d50c3Schristos preprocargs = xmalloc (strlen (quotedarg) + 3);
914ed0d50c3Schristos sprintf (preprocargs, "-%c%s", c, quotedarg);
915ed0d50c3Schristos }
916ed0d50c3Schristos else
917ed0d50c3Schristos {
918ed0d50c3Schristos char *n;
919ed0d50c3Schristos
920ed0d50c3Schristos quotedarg = quot (optarg);
921ed0d50c3Schristos n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
922ed0d50c3Schristos sprintf (n, "%s -%c%s", preprocargs, c, quotedarg);
923ed0d50c3Schristos free (preprocargs);
924ed0d50c3Schristos preprocargs = n;
925ed0d50c3Schristos }
926ed0d50c3Schristos break;
927ed0d50c3Schristos
928ed0d50c3Schristos case 'r':
929ed0d50c3Schristos /* Ignored for compatibility with rc. */
930ed0d50c3Schristos break;
931ed0d50c3Schristos
932ed0d50c3Schristos case 'v':
933ed0d50c3Schristos verbose ++;
934ed0d50c3Schristos break;
935ed0d50c3Schristos
936ed0d50c3Schristos case 'I':
937ed0d50c3Schristos /* For backward compatibility, should be removed in the future. */
938ed0d50c3Schristos input_format_tmp = format_from_name (optarg, 0);
939ed0d50c3Schristos if (input_format_tmp != RES_FORMAT_UNKNOWN)
940ed0d50c3Schristos {
941ed0d50c3Schristos struct stat statbuf;
942ed0d50c3Schristos char modebuf[11];
943ed0d50c3Schristos
944ed0d50c3Schristos if (stat (optarg, & statbuf) == 0
945ed0d50c3Schristos /* Coded this way to avoid importing knowledge of S_ISDIR into this file. */
946ed0d50c3Schristos && (mode_string (statbuf.st_mode, modebuf), modebuf[0] == 'd'))
947ed0d50c3Schristos /* We have a -I option with a directory name that just happens
948ed0d50c3Schristos to match a format name as well. eg: -I res Assume that the
949ed0d50c3Schristos user knows what they are doing and do not complain. */
950ed0d50c3Schristos ;
951ed0d50c3Schristos else
952ed0d50c3Schristos {
953ed0d50c3Schristos fprintf (stderr,
954ed0d50c3Schristos _("Option -I is deprecated for setting the input format, please use -J instead.\n"));
955ed0d50c3Schristos input_format = input_format_tmp;
956ed0d50c3Schristos break;
957ed0d50c3Schristos }
958ed0d50c3Schristos }
959ed0d50c3Schristos /* Fall through. */
960ed0d50c3Schristos
961ed0d50c3Schristos case OPTION_INCLUDE_DIR:
962ed0d50c3Schristos if (preprocargs == NULL)
963ed0d50c3Schristos {
964ed0d50c3Schristos quotedarg = quot (optarg);
965ed0d50c3Schristos preprocargs = xmalloc (strlen (quotedarg) + 3);
966ed0d50c3Schristos sprintf (preprocargs, "-I%s", quotedarg);
967ed0d50c3Schristos }
968ed0d50c3Schristos else
969ed0d50c3Schristos {
970ed0d50c3Schristos char *n;
971ed0d50c3Schristos
972ed0d50c3Schristos quotedarg = quot (optarg);
973ed0d50c3Schristos n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
974ed0d50c3Schristos sprintf (n, "%s -I%s", preprocargs, quotedarg);
975ed0d50c3Schristos free (preprocargs);
976ed0d50c3Schristos preprocargs = n;
977ed0d50c3Schristos }
978ed0d50c3Schristos
979ed0d50c3Schristos windres_add_include_dir (optarg);
980ed0d50c3Schristos
981ed0d50c3Schristos break;
982ed0d50c3Schristos
983ed0d50c3Schristos case 'l':
984ed0d50c3Schristos language = strtol (optarg, (char **) NULL, 16);
985ed0d50c3Schristos break;
986ed0d50c3Schristos
987ed0d50c3Schristos case OPTION_USE_TEMP_FILE:
988ed0d50c3Schristos use_temp_file = 1;
989ed0d50c3Schristos break;
990ed0d50c3Schristos
991ed0d50c3Schristos case OPTION_NO_USE_TEMP_FILE:
992ed0d50c3Schristos use_temp_file = 0;
993ed0d50c3Schristos break;
994ed0d50c3Schristos
995ed0d50c3Schristos #ifdef YYDEBUG
996ed0d50c3Schristos case OPTION_YYDEBUG:
997ed0d50c3Schristos yydebug = 1;
998ed0d50c3Schristos break;
999ed0d50c3Schristos #endif
1000ed0d50c3Schristos
1001ed0d50c3Schristos case 'h':
1002ed0d50c3Schristos case 'H':
1003ed0d50c3Schristos usage (stdout, 0);
1004ed0d50c3Schristos break;
1005ed0d50c3Schristos
1006ed0d50c3Schristos case 'V':
1007ed0d50c3Schristos print_version ("windres");
1008ed0d50c3Schristos break;
1009ed0d50c3Schristos
1010ed0d50c3Schristos default:
1011ed0d50c3Schristos usage (stderr, 1);
1012ed0d50c3Schristos break;
1013ed0d50c3Schristos }
1014ed0d50c3Schristos }
1015ed0d50c3Schristos
1016ed0d50c3Schristos if (input_filename == NULL && optind < argc)
1017ed0d50c3Schristos {
1018ed0d50c3Schristos input_filename = argv[optind];
1019ed0d50c3Schristos ++optind;
1020ed0d50c3Schristos }
1021ed0d50c3Schristos
1022ed0d50c3Schristos if (output_filename == NULL && optind < argc)
1023ed0d50c3Schristos {
1024ed0d50c3Schristos output_filename = argv[optind];
1025ed0d50c3Schristos ++optind;
1026ed0d50c3Schristos }
1027ed0d50c3Schristos
1028ed0d50c3Schristos if (argc != optind)
1029ed0d50c3Schristos usage (stderr, 1);
1030ed0d50c3Schristos
1031ed0d50c3Schristos if (input_format == RES_FORMAT_UNKNOWN)
1032ed0d50c3Schristos {
1033ed0d50c3Schristos if (input_filename == NULL)
1034ed0d50c3Schristos input_format = RES_FORMAT_RC;
1035ed0d50c3Schristos else
1036ed0d50c3Schristos input_format = format_from_filename (input_filename, 1);
1037ed0d50c3Schristos }
1038ed0d50c3Schristos
1039ed0d50c3Schristos if (output_format == RES_FORMAT_UNKNOWN)
1040ed0d50c3Schristos {
1041ed0d50c3Schristos if (output_filename == NULL)
1042ed0d50c3Schristos output_format = RES_FORMAT_RC;
1043ed0d50c3Schristos else
1044ed0d50c3Schristos output_format = format_from_filename (output_filename, 0);
1045ed0d50c3Schristos }
1046ed0d50c3Schristos
1047ed0d50c3Schristos set_endianness (NULL, target);
1048ed0d50c3Schristos
1049ed0d50c3Schristos /* Read the input file. */
1050ed0d50c3Schristos switch (input_format)
1051ed0d50c3Schristos {
1052ed0d50c3Schristos default:
1053ed0d50c3Schristos abort ();
1054ed0d50c3Schristos case RES_FORMAT_RC:
1055ed0d50c3Schristos resources = read_rc_file (input_filename, preprocessor, preprocargs,
1056ed0d50c3Schristos language, use_temp_file);
1057ed0d50c3Schristos break;
1058ed0d50c3Schristos case RES_FORMAT_RES:
1059ed0d50c3Schristos resources = read_res_file (input_filename);
1060ed0d50c3Schristos break;
1061ed0d50c3Schristos case RES_FORMAT_COFF:
1062ed0d50c3Schristos resources = read_coff_rsrc (input_filename, target);
1063ed0d50c3Schristos break;
1064ed0d50c3Schristos }
1065ed0d50c3Schristos
1066ed0d50c3Schristos if (resources == NULL)
1067ed0d50c3Schristos fatal (_("no resources"));
1068ed0d50c3Schristos
1069ed0d50c3Schristos /* Sort the resources. This is required for COFF, convenient for
1070ed0d50c3Schristos rc, and unimportant for res. */
1071ed0d50c3Schristos resources = sort_resources (resources);
1072ed0d50c3Schristos
1073ed0d50c3Schristos /* Write the output file. */
1074ed0d50c3Schristos reswr_init ();
1075ed0d50c3Schristos
1076ed0d50c3Schristos switch (output_format)
1077ed0d50c3Schristos {
1078ed0d50c3Schristos default:
1079ed0d50c3Schristos abort ();
1080ed0d50c3Schristos case RES_FORMAT_RC:
1081ed0d50c3Schristos write_rc_file (output_filename, resources);
1082ed0d50c3Schristos break;
1083ed0d50c3Schristos case RES_FORMAT_RES:
1084ed0d50c3Schristos write_res_file (output_filename, resources);
1085ed0d50c3Schristos break;
1086ed0d50c3Schristos case RES_FORMAT_COFF:
1087ed0d50c3Schristos write_coff_file (output_filename, target, resources);
1088ed0d50c3Schristos break;
1089ed0d50c3Schristos }
1090ed0d50c3Schristos
1091ed0d50c3Schristos xexit (0);
1092ed0d50c3Schristos return 0;
1093ed0d50c3Schristos }
1094ed0d50c3Schristos
1095ed0d50c3Schristos static void
set_endianness(bfd * abfd,const char * target)1096ed0d50c3Schristos set_endianness (bfd *abfd, const char *target)
1097ed0d50c3Schristos {
1098ed0d50c3Schristos const bfd_target *target_vec;
1099ed0d50c3Schristos
1100ed0d50c3Schristos def_target_arch = NULL;
1101ed0d50c3Schristos target_vec = bfd_get_target_info (target, abfd, &target_is_bigendian, NULL,
1102ed0d50c3Schristos &def_target_arch);
1103ed0d50c3Schristos if (! target_vec)
1104ed0d50c3Schristos fatal ("Can't detect target endianness and architecture.");
1105ed0d50c3Schristos if (! def_target_arch)
1106ed0d50c3Schristos fatal ("Can't detect architecture.");
1107ed0d50c3Schristos }
1108ed0d50c3Schristos
1109ed0d50c3Schristos bfd *
windres_open_as_binary(const char * filename,int rdmode)1110ed0d50c3Schristos windres_open_as_binary (const char *filename, int rdmode)
1111ed0d50c3Schristos {
1112ed0d50c3Schristos bfd *abfd;
1113ed0d50c3Schristos
1114ed0d50c3Schristos abfd = (rdmode ? bfd_openr (filename, "binary") : bfd_openw (filename, "binary"));
1115ed0d50c3Schristos if (! abfd)
1116ed0d50c3Schristos fatal ("can't open `%s' for %s", filename, (rdmode ? "input" : "output"));
1117ed0d50c3Schristos
1118ed0d50c3Schristos if (rdmode && ! bfd_check_format (abfd, bfd_object))
1119ed0d50c3Schristos fatal ("can't open `%s' for input.", filename);
1120ed0d50c3Schristos
1121ed0d50c3Schristos return abfd;
1122ed0d50c3Schristos }
1123ed0d50c3Schristos
1124ed0d50c3Schristos void
set_windres_bfd_endianness(windres_bfd * wrbfd,int is_bigendian)1125ed0d50c3Schristos set_windres_bfd_endianness (windres_bfd *wrbfd, int is_bigendian)
1126ed0d50c3Schristos {
1127ed0d50c3Schristos assert (!! wrbfd);
1128ed0d50c3Schristos switch (WR_KIND(wrbfd))
1129ed0d50c3Schristos {
1130ed0d50c3Schristos case WR_KIND_BFD_BIN_L:
1131ed0d50c3Schristos if (is_bigendian)
1132ed0d50c3Schristos WR_KIND(wrbfd) = WR_KIND_BFD_BIN_B;
1133ed0d50c3Schristos break;
1134ed0d50c3Schristos case WR_KIND_BFD_BIN_B:
1135ed0d50c3Schristos if (! is_bigendian)
1136ed0d50c3Schristos WR_KIND(wrbfd) = WR_KIND_BFD_BIN_L;
1137ed0d50c3Schristos break;
1138ed0d50c3Schristos default:
1139ed0d50c3Schristos /* only binary bfd can be overriden. */
1140ed0d50c3Schristos abort ();
1141ed0d50c3Schristos }
1142ed0d50c3Schristos }
1143ed0d50c3Schristos
1144ed0d50c3Schristos void
set_windres_bfd(windres_bfd * wrbfd,bfd * abfd,asection * sec,rc_uint_type kind)1145ed0d50c3Schristos set_windres_bfd (windres_bfd *wrbfd, bfd *abfd, asection *sec, rc_uint_type kind)
1146ed0d50c3Schristos {
1147ed0d50c3Schristos assert (!! wrbfd);
1148ed0d50c3Schristos switch (kind)
1149ed0d50c3Schristos {
1150ed0d50c3Schristos case WR_KIND_TARGET:
1151ed0d50c3Schristos abfd = NULL;
1152ed0d50c3Schristos sec = NULL;
1153ed0d50c3Schristos break;
1154ed0d50c3Schristos case WR_KIND_BFD:
1155ed0d50c3Schristos case WR_KIND_BFD_BIN_L:
1156ed0d50c3Schristos case WR_KIND_BFD_BIN_B:
1157ed0d50c3Schristos assert (!! abfd);
1158ed0d50c3Schristos assert (!!sec);
1159ed0d50c3Schristos break;
1160ed0d50c3Schristos default:
1161ed0d50c3Schristos abort ();
1162ed0d50c3Schristos }
1163ed0d50c3Schristos WR_KIND(wrbfd) = kind;
1164ed0d50c3Schristos WR_BFD(wrbfd) = abfd;
1165ed0d50c3Schristos WR_SECTION(wrbfd) = sec;
1166ed0d50c3Schristos }
1167ed0d50c3Schristos
1168ed0d50c3Schristos void
set_windres_bfd_content(windres_bfd * wrbfd,const void * data,rc_uint_type off,rc_uint_type length)1169ed0d50c3Schristos set_windres_bfd_content (windres_bfd *wrbfd, const void *data, rc_uint_type off,
1170ed0d50c3Schristos rc_uint_type length)
1171ed0d50c3Schristos {
1172ed0d50c3Schristos if (WR_KIND(wrbfd) != WR_KIND_TARGET)
1173ed0d50c3Schristos {
1174ed0d50c3Schristos if (! bfd_set_section_contents (WR_BFD(wrbfd), WR_SECTION(wrbfd), data, off, length))
1175ed0d50c3Schristos bfd_fatal ("bfd_set_section_contents");
1176ed0d50c3Schristos }
1177ed0d50c3Schristos else
1178ed0d50c3Schristos abort ();
1179ed0d50c3Schristos }
1180ed0d50c3Schristos
1181ed0d50c3Schristos void
get_windres_bfd_content(windres_bfd * wrbfd,void * data,rc_uint_type off,rc_uint_type length)1182ed0d50c3Schristos get_windres_bfd_content (windres_bfd *wrbfd, void *data, rc_uint_type off,
1183ed0d50c3Schristos rc_uint_type length)
1184ed0d50c3Schristos {
1185ed0d50c3Schristos if (WR_KIND(wrbfd) != WR_KIND_TARGET)
1186ed0d50c3Schristos {
1187ed0d50c3Schristos if (! bfd_get_section_contents (WR_BFD(wrbfd), WR_SECTION(wrbfd), data, off, length))
1188ed0d50c3Schristos bfd_fatal ("bfd_get_section_contents");
1189ed0d50c3Schristos }
1190ed0d50c3Schristos else
1191ed0d50c3Schristos abort ();
1192ed0d50c3Schristos }
1193ed0d50c3Schristos
1194ed0d50c3Schristos void
windres_put_8(windres_bfd * wrbfd,void * p,rc_uint_type value)1195ed0d50c3Schristos windres_put_8 (windres_bfd *wrbfd, void *p, rc_uint_type value)
1196ed0d50c3Schristos {
1197ed0d50c3Schristos switch (WR_KIND(wrbfd))
1198ed0d50c3Schristos {
1199ed0d50c3Schristos case WR_KIND_TARGET:
1200ed0d50c3Schristos target_put_8 (p, value);
1201ed0d50c3Schristos break;
1202ed0d50c3Schristos case WR_KIND_BFD:
1203ed0d50c3Schristos case WR_KIND_BFD_BIN_L:
1204ed0d50c3Schristos case WR_KIND_BFD_BIN_B:
1205ed0d50c3Schristos bfd_put_8 (WR_BFD(wrbfd), value, p);
1206ed0d50c3Schristos break;
1207ed0d50c3Schristos default:
1208ed0d50c3Schristos abort ();
1209ed0d50c3Schristos }
1210ed0d50c3Schristos }
1211ed0d50c3Schristos
1212ed0d50c3Schristos void
windres_put_16(windres_bfd * wrbfd,void * data,rc_uint_type value)1213ed0d50c3Schristos windres_put_16 (windres_bfd *wrbfd, void *data, rc_uint_type value)
1214ed0d50c3Schristos {
1215ed0d50c3Schristos switch (WR_KIND(wrbfd))
1216ed0d50c3Schristos {
1217ed0d50c3Schristos case WR_KIND_TARGET:
1218ed0d50c3Schristos target_put_16 (data, value);
1219ed0d50c3Schristos break;
1220ed0d50c3Schristos case WR_KIND_BFD:
1221ed0d50c3Schristos case WR_KIND_BFD_BIN_B:
1222ed0d50c3Schristos bfd_put_16 (WR_BFD(wrbfd), value, data);
1223ed0d50c3Schristos break;
1224ed0d50c3Schristos case WR_KIND_BFD_BIN_L:
1225ed0d50c3Schristos bfd_putl16 (value, data);
1226ed0d50c3Schristos break;
1227ed0d50c3Schristos default:
1228ed0d50c3Schristos abort ();
1229ed0d50c3Schristos }
1230ed0d50c3Schristos }
1231ed0d50c3Schristos
1232ed0d50c3Schristos void
windres_put_32(windres_bfd * wrbfd,void * data,rc_uint_type value)1233ed0d50c3Schristos windres_put_32 (windres_bfd *wrbfd, void *data, rc_uint_type value)
1234ed0d50c3Schristos {
1235ed0d50c3Schristos switch (WR_KIND(wrbfd))
1236ed0d50c3Schristos {
1237ed0d50c3Schristos case WR_KIND_TARGET:
1238ed0d50c3Schristos target_put_32 (data, value);
1239ed0d50c3Schristos break;
1240ed0d50c3Schristos case WR_KIND_BFD:
1241ed0d50c3Schristos case WR_KIND_BFD_BIN_B:
1242ed0d50c3Schristos bfd_put_32 (WR_BFD(wrbfd), value, data);
1243ed0d50c3Schristos break;
1244ed0d50c3Schristos case WR_KIND_BFD_BIN_L:
1245ed0d50c3Schristos bfd_putl32 (value, data);
1246ed0d50c3Schristos break;
1247ed0d50c3Schristos default:
1248ed0d50c3Schristos abort ();
1249ed0d50c3Schristos }
1250ed0d50c3Schristos }
1251ed0d50c3Schristos
1252ed0d50c3Schristos rc_uint_type
windres_get_8(windres_bfd * wrbfd,const void * data,rc_uint_type length)1253ed0d50c3Schristos windres_get_8 (windres_bfd *wrbfd, const void *data, rc_uint_type length)
1254ed0d50c3Schristos {
1255ed0d50c3Schristos if (length < 1)
1256ed0d50c3Schristos fatal ("windres_get_8: unexpected eob.");
1257ed0d50c3Schristos switch (WR_KIND(wrbfd))
1258ed0d50c3Schristos {
1259ed0d50c3Schristos case WR_KIND_TARGET:
1260ed0d50c3Schristos return target_get_8 (data, length);
1261ed0d50c3Schristos case WR_KIND_BFD:
1262ed0d50c3Schristos case WR_KIND_BFD_BIN_B:
1263ed0d50c3Schristos case WR_KIND_BFD_BIN_L:
1264ed0d50c3Schristos return bfd_get_8 (WR_BFD(wrbfd), data);
1265ed0d50c3Schristos default:
1266ed0d50c3Schristos abort ();
1267ed0d50c3Schristos }
1268ed0d50c3Schristos return 0;
1269ed0d50c3Schristos }
1270ed0d50c3Schristos
1271ed0d50c3Schristos rc_uint_type
windres_get_16(windres_bfd * wrbfd,const void * data,rc_uint_type length)1272ed0d50c3Schristos windres_get_16 (windres_bfd *wrbfd, const void *data, rc_uint_type length)
1273ed0d50c3Schristos {
1274ed0d50c3Schristos if (length < 2)
1275ed0d50c3Schristos fatal ("windres_get_16: unexpected eob.");
1276ed0d50c3Schristos switch (WR_KIND(wrbfd))
1277ed0d50c3Schristos {
1278ed0d50c3Schristos case WR_KIND_TARGET:
1279ed0d50c3Schristos return target_get_16 (data, length);
1280ed0d50c3Schristos case WR_KIND_BFD:
1281ed0d50c3Schristos case WR_KIND_BFD_BIN_B:
1282ed0d50c3Schristos return bfd_get_16 (WR_BFD(wrbfd), data);
1283ed0d50c3Schristos case WR_KIND_BFD_BIN_L:
1284ed0d50c3Schristos return bfd_getl16 (data);
1285ed0d50c3Schristos default:
1286ed0d50c3Schristos abort ();
1287ed0d50c3Schristos }
1288ed0d50c3Schristos return 0;
1289ed0d50c3Schristos }
1290ed0d50c3Schristos
1291ed0d50c3Schristos rc_uint_type
windres_get_32(windres_bfd * wrbfd,const void * data,rc_uint_type length)1292ed0d50c3Schristos windres_get_32 (windres_bfd *wrbfd, const void *data, rc_uint_type length)
1293ed0d50c3Schristos {
1294ed0d50c3Schristos if (length < 4)
1295ed0d50c3Schristos fatal ("windres_get_32: unexpected eob.");
1296ed0d50c3Schristos switch (WR_KIND(wrbfd))
1297ed0d50c3Schristos {
1298ed0d50c3Schristos case WR_KIND_TARGET:
1299ed0d50c3Schristos return target_get_32 (data, length);
1300ed0d50c3Schristos case WR_KIND_BFD:
1301ed0d50c3Schristos case WR_KIND_BFD_BIN_B:
1302ed0d50c3Schristos return bfd_get_32 (WR_BFD(wrbfd), data);
1303ed0d50c3Schristos case WR_KIND_BFD_BIN_L:
1304ed0d50c3Schristos return bfd_getl32 (data);
1305ed0d50c3Schristos default:
1306ed0d50c3Schristos abort ();
1307ed0d50c3Schristos }
1308ed0d50c3Schristos return 0;
1309ed0d50c3Schristos }
1310ed0d50c3Schristos
1311ed0d50c3Schristos static rc_uint_type
target_get_8(const void * p,rc_uint_type length)1312ed0d50c3Schristos target_get_8 (const void *p, rc_uint_type length)
1313ed0d50c3Schristos {
1314ed0d50c3Schristos rc_uint_type ret;
1315ed0d50c3Schristos
1316ed0d50c3Schristos if (length < 1)
1317ed0d50c3Schristos fatal ("Resource too small for getting 8-bit value.");
1318ed0d50c3Schristos
1319ed0d50c3Schristos ret = (rc_uint_type) *((const bfd_byte *) p);
1320ed0d50c3Schristos return ret & 0xff;
1321ed0d50c3Schristos }
1322ed0d50c3Schristos
1323ed0d50c3Schristos static rc_uint_type
target_get_16(const void * p,rc_uint_type length)1324ed0d50c3Schristos target_get_16 (const void *p, rc_uint_type length)
1325ed0d50c3Schristos {
1326ed0d50c3Schristos if (length < 2)
1327ed0d50c3Schristos fatal ("Resource too small for getting 16-bit value.");
1328ed0d50c3Schristos
1329ed0d50c3Schristos if (target_is_bigendian)
1330ed0d50c3Schristos return bfd_getb16 (p);
1331ed0d50c3Schristos else
1332ed0d50c3Schristos return bfd_getl16 (p);
1333ed0d50c3Schristos }
1334ed0d50c3Schristos
1335ed0d50c3Schristos static rc_uint_type
target_get_32(const void * p,rc_uint_type length)1336ed0d50c3Schristos target_get_32 (const void *p, rc_uint_type length)
1337ed0d50c3Schristos {
1338ed0d50c3Schristos if (length < 4)
1339ed0d50c3Schristos fatal ("Resource too small for getting 32-bit value.");
1340ed0d50c3Schristos
1341ed0d50c3Schristos if (target_is_bigendian)
1342ed0d50c3Schristos return bfd_getb32 (p);
1343ed0d50c3Schristos else
1344ed0d50c3Schristos return bfd_getl32 (p);
1345ed0d50c3Schristos }
1346ed0d50c3Schristos
1347ed0d50c3Schristos static void
target_put_8(void * p,rc_uint_type value)1348ed0d50c3Schristos target_put_8 (void *p, rc_uint_type value)
1349ed0d50c3Schristos {
1350ed0d50c3Schristos assert (!! p);
1351ed0d50c3Schristos *((bfd_byte *) p)=(bfd_byte) value;
1352ed0d50c3Schristos }
1353ed0d50c3Schristos
1354ed0d50c3Schristos static void
target_put_16(void * p,rc_uint_type value)1355ed0d50c3Schristos target_put_16 (void *p, rc_uint_type value)
1356ed0d50c3Schristos {
1357ed0d50c3Schristos assert (!! p);
1358ed0d50c3Schristos
1359ed0d50c3Schristos if (target_is_bigendian)
1360ed0d50c3Schristos bfd_putb16 (value, p);
1361ed0d50c3Schristos else
1362ed0d50c3Schristos bfd_putl16 (value, p);
1363ed0d50c3Schristos }
1364ed0d50c3Schristos
1365ed0d50c3Schristos static void
target_put_32(void * p,rc_uint_type value)1366ed0d50c3Schristos target_put_32 (void *p, rc_uint_type value)
1367ed0d50c3Schristos {
1368ed0d50c3Schristos assert (!! p);
1369ed0d50c3Schristos
1370ed0d50c3Schristos if (target_is_bigendian)
1371ed0d50c3Schristos bfd_putb32 (value, p);
1372ed0d50c3Schristos else
1373ed0d50c3Schristos bfd_putl32 (value, p);
1374ed0d50c3Schristos }
1375ed0d50c3Schristos
1376ed0d50c3Schristos static int isInComment = 0;
1377ed0d50c3Schristos
wr_printcomment(FILE * e,const char * fmt,...)1378ed0d50c3Schristos int wr_printcomment (FILE *e, const char *fmt, ...)
1379ed0d50c3Schristos {
1380ed0d50c3Schristos va_list arg;
1381ed0d50c3Schristos int r = 0;
1382ed0d50c3Schristos
1383ed0d50c3Schristos if (isInComment)
1384ed0d50c3Schristos r += fprintf (e, "\n ");
1385ed0d50c3Schristos else
1386ed0d50c3Schristos fprintf (e, "/* ");
1387ed0d50c3Schristos isInComment = 1;
1388ed0d50c3Schristos if (fmt == NULL)
1389ed0d50c3Schristos return r;
1390ed0d50c3Schristos va_start (arg, fmt);
1391ed0d50c3Schristos r += vfprintf (e, fmt, arg);
1392ed0d50c3Schristos va_end (arg);
1393ed0d50c3Schristos return r;
1394ed0d50c3Schristos }
1395ed0d50c3Schristos
wr_print(FILE * e,const char * fmt,...)1396ed0d50c3Schristos int wr_print (FILE *e, const char *fmt, ...)
1397ed0d50c3Schristos {
1398ed0d50c3Schristos va_list arg;
1399ed0d50c3Schristos int r = 0;
1400ed0d50c3Schristos if (isInComment)
1401ed0d50c3Schristos r += fprintf (e, ". */\n");
1402ed0d50c3Schristos isInComment = 0;
1403ed0d50c3Schristos if (! fmt)
1404ed0d50c3Schristos return r;
1405ed0d50c3Schristos va_start (arg, fmt);
1406ed0d50c3Schristos r += vfprintf (e, fmt, arg);
1407ed0d50c3Schristos va_end (arg);
1408ed0d50c3Schristos return r;
1409ed0d50c3Schristos }
1410