gdb/
[deliverable/binutils-gdb.git] / binutils / resres.c
1 /* resres.c: read_res_file and write_res_file implementation for windres.
2 Copyright 1998, 1999, 2001, 2002, 2005, 2007, 2008, 2011
3 Free Software Foundation, Inc.
4 Written by Anders Norlander <anorland@hem2.passagen.se>.
5 Rewritten by Kai Tietz, Onevision.
6
7 This file is part of GNU Binutils.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
22 02110-1301, USA. */
23
24 /* FIXME: This file does not work correctly in a cross configuration.
25 It assumes that it can use fread and fwrite to read and write
26 integers. It does no swapping. */
27
28 #include "sysdep.h"
29 #include "bfd.h"
30 #include "bucomm.h"
31 #include "libiberty.h"
32 #include "windres.h"
33
34 #include <assert.h>
35 #include <time.h>
36
37 static rc_uint_type write_res_directory (windres_bfd *, rc_uint_type,
38 const rc_res_directory *, const rc_res_id *,
39 const rc_res_id *, rc_uint_type *, int);
40 static rc_uint_type write_res_resource (windres_bfd *, rc_uint_type,const rc_res_id *,
41 const rc_res_id *, const rc_res_resource *,
42 rc_uint_type *);
43 static rc_uint_type write_res_bin (windres_bfd *, rc_uint_type, const rc_res_resource *,
44 const rc_res_id *, const rc_res_id *,
45 const rc_res_res_info *);
46
47 static rc_uint_type write_res_id (windres_bfd *, rc_uint_type, const rc_res_id *);
48 static rc_uint_type write_res_info (windres_bfd *, rc_uint_type, const rc_res_res_info *);
49 static rc_uint_type write_res_data_hdr (windres_bfd *, rc_uint_type, res_hdr *);
50
51 static rc_uint_type write_res_header (windres_bfd *, rc_uint_type, rc_uint_type,
52 const rc_res_id *, const rc_res_id *,
53 const rc_res_res_info *);
54
55 static int read_resource_entry (windres_bfd *, rc_uint_type *, rc_uint_type);
56 static void read_res_data (windres_bfd *, rc_uint_type *, rc_uint_type, void *,
57 rc_uint_type);
58 static void read_res_data_hdr (windres_bfd *, rc_uint_type *, rc_uint_type, res_hdr *);
59 static void read_res_id (windres_bfd *, rc_uint_type *, rc_uint_type, rc_res_id *);
60 static unichar *read_unistring (windres_bfd *, rc_uint_type *, rc_uint_type, rc_uint_type *);
61 static void skip_null_resource (windres_bfd *, rc_uint_type *, rc_uint_type);
62 static int probe_binary (windres_bfd *wrbfd, rc_uint_type);
63
64 static unsigned long get_id_size (const rc_res_id *);
65
66 static void res_add_resource (rc_res_resource *, const rc_res_id *,
67 const rc_res_id *, rc_uint_type, int);
68
69 static void res_append_resource (rc_res_directory **, rc_res_resource *,
70 int, const rc_res_id *, int);
71
72 static rc_res_directory *resources = NULL;
73
74 static const char *filename;
75
76 extern char *program_name;
77
78 /* Read resource file */
79 rc_res_directory *
80 read_res_file (const char *fn)
81 {
82 rc_uint_type off, flen;
83 windres_bfd wrbfd;
84 bfd *abfd;
85 asection *sec;
86 filename = fn;
87
88 flen = (rc_uint_type) get_file_size (filename);
89 if (! flen)
90 fatal ("can't open '%s' for input.", filename);
91 abfd = windres_open_as_binary (filename, 1);
92 sec = bfd_get_section_by_name (abfd, ".data");
93 if (sec == NULL)
94 bfd_fatal ("bfd_get_section_by_name");
95 set_windres_bfd (&wrbfd, abfd, sec,
96 (target_is_bigendian ? WR_KIND_BFD_BIN_B
97 : WR_KIND_BFD_BIN_L));
98 off = 0;
99
100 if (! probe_binary (&wrbfd, flen))
101 set_windres_bfd_endianness (&wrbfd, ! target_is_bigendian);
102
103 skip_null_resource (&wrbfd, &off, flen);
104
105 while (read_resource_entry (&wrbfd, &off, flen))
106 ;
107
108 bfd_close (abfd);
109
110 return resources;
111 }
112
113 /* Write resource file */
114 void
115 write_res_file (const char *fn,const rc_res_directory *resdir)
116 {
117 asection *sec;
118 rc_uint_type language;
119 bfd *abfd;
120 windres_bfd wrbfd;
121 unsigned long sec_length = 0,sec_length_wrote;
122 static const bfd_byte sign[] =
123 {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
124 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
127
128 filename = fn;
129
130 abfd = windres_open_as_binary (filename, 0);
131 sec = bfd_make_section_with_flags (abfd, ".data",
132 (SEC_HAS_CONTENTS | SEC_ALLOC
133 | SEC_LOAD | SEC_DATA));
134 if (sec == NULL)
135 bfd_fatal ("bfd_make_section");
136 /* Requiring this is probably a bug in BFD. */
137 sec->output_section = sec;
138
139 set_windres_bfd (&wrbfd, abfd, sec,
140 (target_is_bigendian ? WR_KIND_BFD_BIN_B
141 : WR_KIND_BFD_BIN_L));
142
143 language = -1;
144 sec_length = write_res_directory ((windres_bfd *) NULL, 0x20UL, resdir,
145 (const rc_res_id *) NULL,
146 (const rc_res_id *) NULL, &language, 1);
147 if (! bfd_set_section_size (abfd, sec, (sec_length + 3) & ~3))
148 bfd_fatal ("bfd_set_section_size");
149 if ((sec_length & 3) != 0)
150 set_windres_bfd_content (&wrbfd, sign, sec_length, 4-(sec_length & 3));
151 set_windres_bfd_content (&wrbfd, sign, 0, sizeof (sign));
152 language = -1;
153 sec_length_wrote = write_res_directory (&wrbfd, 0x20UL, resdir,
154 (const rc_res_id *) NULL,
155 (const rc_res_id *) NULL,
156 &language, 1);
157 if (sec_length != sec_length_wrote)
158 fatal ("res write failed with different sizes (%lu/%lu).",
159 (unsigned long) sec_length, (unsigned long) sec_length_wrote);
160
161 bfd_close (abfd);
162 return;
163 }
164
165 /* Read a resource entry, returns 0 when all resources are read */
166 static int
167 read_resource_entry (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax)
168 {
169 rc_res_id type;
170 rc_res_id name;
171 rc_res_res_info resinfo;
172 res_hdr reshdr;
173 void *buff;
174
175 rc_res_resource *r;
176 struct bin_res_info l;
177
178 off[0] = (off[0] + 3) & ~3;
179
180 /* Read header */
181 if ((off[0] + 8) > omax)
182 return 0;
183 read_res_data_hdr (wrbfd, off, omax, &reshdr);
184
185 /* read resource type */
186 read_res_id (wrbfd, off, omax, &type);
187 /* read resource id */
188 read_res_id (wrbfd, off, omax, &name);
189
190 off[0] = (off[0] + 3) & ~3;
191
192 /* Read additional resource header */
193 read_res_data (wrbfd, off, omax, &l, BIN_RES_INFO_SIZE);
194 resinfo.version = windres_get_32 (wrbfd, l.version, 4);
195 resinfo.memflags = windres_get_16 (wrbfd, l.memflags, 2);
196 resinfo.language = windres_get_16 (wrbfd, l.language, 2);
197 /* resinfo.version2 = windres_get_32 (wrbfd, l.version2, 4); */
198 resinfo.characteristics = windres_get_32 (wrbfd, l.characteristics, 4);
199
200 off[0] = (off[0] + 3) & ~3;
201
202 /* Allocate buffer for data */
203 buff = res_alloc (reshdr.data_size);
204 /* Read data */
205 read_res_data (wrbfd, off, omax, buff, reshdr.data_size);
206 /* Convert binary data to resource */
207 r = bin_to_res (wrbfd, type, buff, reshdr.data_size);
208 r->res_info = resinfo;
209 /* Add resource to resource directory */
210 res_add_resource (r, &type, &name, resinfo.language, 0);
211
212 return 1;
213 }
214
215 /* write resource directory to binary resource file */
216 static rc_uint_type
217 write_res_directory (windres_bfd *wrbfd, rc_uint_type off, const rc_res_directory *rd,
218 const rc_res_id *type, const rc_res_id *name, rc_uint_type *language,
219 int level)
220 {
221 const rc_res_entry *re;
222
223 for (re = rd->entries; re != NULL; re = re->next)
224 {
225 switch (level)
226 {
227 case 1:
228 /* If we're at level 1, the key of this resource is the
229 type. This normally duplicates the information we have
230 stored with the resource itself, but we need to remember
231 the type if this is a user define resource type. */
232 type = &re->id;
233 break;
234
235 case 2:
236 /* If we're at level 2, the key of this resource is the name
237 we are going to use in the rc printout. */
238 name = &re->id;
239 break;
240
241 case 3:
242 /* If we're at level 3, then this key represents a language.
243 Use it to update the current language. */
244 if (! re->id.named
245 && re->id.u.id != (unsigned long) *language
246 && (re->id.u.id & 0xffff) == re->id.u.id)
247 {
248 *language = re->id.u.id;
249 }
250 break;
251
252 default:
253 break;
254 }
255
256 if (re->subdir)
257 off = write_res_directory (wrbfd, off, re->u.dir, type, name, language,
258 level + 1);
259 else
260 {
261 if (level == 3)
262 {
263 /* This is the normal case: the three levels are
264 TYPE/NAME/LANGUAGE. NAME will have been set at level
265 2, and represents the name to use. We probably just
266 set LANGUAGE, and it will probably match what the
267 resource itself records if anything. */
268 off = write_res_resource (wrbfd, off, type, name, re->u.res,
269 language);
270 }
271 else
272 {
273 fprintf (stderr, "// Resource at unexpected level %d\n", level);
274 off = write_res_resource (wrbfd, off, type, (rc_res_id *) NULL,
275 re->u.res, language);
276 }
277 }
278 }
279
280 return off;
281 }
282
283 static rc_uint_type
284 write_res_resource (windres_bfd *wrbfd, rc_uint_type off, const rc_res_id *type,
285 const rc_res_id *name, const rc_res_resource *res,
286 rc_uint_type *language ATTRIBUTE_UNUSED)
287 {
288 int rt;
289
290 switch (res->type)
291 {
292 default:
293 abort ();
294
295 case RES_TYPE_ACCELERATOR:
296 rt = RT_ACCELERATOR;
297 break;
298
299 case RES_TYPE_BITMAP:
300 rt = RT_BITMAP;
301 break;
302
303 case RES_TYPE_CURSOR:
304 rt = RT_CURSOR;
305 break;
306
307 case RES_TYPE_GROUP_CURSOR:
308 rt = RT_GROUP_CURSOR;
309 break;
310
311 case RES_TYPE_DIALOG:
312 rt = RT_DIALOG;
313 break;
314
315 case RES_TYPE_FONT:
316 rt = RT_FONT;
317 break;
318
319 case RES_TYPE_FONTDIR:
320 rt = RT_FONTDIR;
321 break;
322
323 case RES_TYPE_ICON:
324 rt = RT_ICON;
325 break;
326
327 case RES_TYPE_GROUP_ICON:
328 rt = RT_GROUP_ICON;
329 break;
330
331 case RES_TYPE_MENU:
332 rt = RT_MENU;
333 break;
334
335 case RES_TYPE_MESSAGETABLE:
336 rt = RT_MESSAGETABLE;
337 break;
338
339 case RES_TYPE_RCDATA:
340 rt = RT_RCDATA;
341 break;
342
343 case RES_TYPE_STRINGTABLE:
344 rt = RT_STRING;
345 break;
346
347 case RES_TYPE_USERDATA:
348 rt = 0;
349 break;
350
351 case RES_TYPE_VERSIONINFO:
352 rt = RT_VERSION;
353 break;
354
355 case RES_TYPE_TOOLBAR:
356 rt = RT_TOOLBAR;
357 break;
358 }
359
360 if (rt != 0
361 && type != NULL
362 && (type->named || type->u.id != (unsigned long) rt))
363 {
364 fprintf (stderr, "// Unexpected resource type mismatch: ");
365 res_id_print (stderr, *type, 1);
366 fprintf (stderr, " != %d", rt);
367 abort ();
368 }
369
370 return write_res_bin (wrbfd, off, res, type, name, &res->res_info);
371 }
372
373 /* Write a resource in binary resource format */
374 static rc_uint_type
375 write_res_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res,
376 const rc_res_id *type, const rc_res_id *name,
377 const rc_res_res_info *resinfo)
378 {
379 rc_uint_type noff;
380 rc_uint_type datasize = 0;
381
382 noff = res_to_bin ((windres_bfd *) NULL, off, res);
383 datasize = noff - off;
384
385 off = write_res_header (wrbfd, off, datasize, type, name, resinfo);
386 return res_to_bin (wrbfd, off, res);
387 }
388
389 /* Get number of bytes needed to store an id in binary format */
390 static unsigned long
391 get_id_size (id)
392 const rc_res_id *id;
393 {
394 if (id->named)
395 return sizeof (unichar) * (id->u.n.length + 1);
396 else
397 return sizeof (unichar) * 2;
398 }
399
400 /* Write a resource header */
401 static rc_uint_type
402 write_res_header (windres_bfd *wrbfd, rc_uint_type off, rc_uint_type datasize,
403 const rc_res_id *type, const rc_res_id *name,
404 const rc_res_res_info *resinfo)
405 {
406 res_hdr reshdr;
407 reshdr.data_size = datasize;
408 reshdr.header_size = 24 + get_id_size (type) + get_id_size (name);
409
410 reshdr.header_size = (reshdr.header_size + 3) & ~3;
411
412 off = (off + 3) & ~3;
413
414 off = write_res_data_hdr (wrbfd, off, &reshdr);
415 off = write_res_id (wrbfd, off, type);
416 off = write_res_id (wrbfd, off, name);
417
418 off = (off + 3) & ~3;
419
420 off = write_res_info (wrbfd, off, resinfo);
421 off = (off + 3) & ~3;
422 return off;
423 }
424
425 static rc_uint_type
426 write_res_data_hdr (windres_bfd *wrbfd, rc_uint_type off, res_hdr *hdr)
427 {
428 if (wrbfd)
429 {
430 struct bin_res_hdr brh;
431 windres_put_32 (wrbfd, brh.data_size, hdr->data_size);
432 windres_put_32 (wrbfd, brh.header_size, hdr->header_size);
433 set_windres_bfd_content (wrbfd, &brh, off, BIN_RES_HDR_SIZE);
434 }
435 return off + BIN_RES_HDR_SIZE;
436 }
437
438 static void
439 read_res_data_hdr (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax,
440 res_hdr *reshdr)
441 {
442 struct bin_res_hdr brh;
443
444 if ((off[0] + BIN_RES_HDR_SIZE) > omax)
445 fatal ("%s: unexpected end of file %ld/%ld", filename,(long) off[0], (long) omax);
446
447 get_windres_bfd_content (wrbfd, &brh, off[0], BIN_RES_HDR_SIZE);
448 reshdr->data_size = windres_get_32 (wrbfd, brh.data_size, 4);
449 reshdr->header_size = windres_get_32 (wrbfd, brh.header_size, 4);
450 off[0] += BIN_RES_HDR_SIZE;
451 }
452
453 /* Read data from file, abort on failure */
454 static void
455 read_res_data (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax, void *data,
456 rc_uint_type size)
457 {
458 if ((off[0] + size) > omax)
459 fatal ("%s: unexpected end of file %ld/%ld %ld", filename,(long) off[0],
460 (long) omax, (long) size);
461 get_windres_bfd_content (wrbfd, data, off[0], size);
462 off[0] += size;
463 }
464
465 /* Write a resource id */
466 static rc_uint_type
467 write_res_id (windres_bfd *wrbfd, rc_uint_type off, const rc_res_id *id)
468 {
469 if (id->named)
470 {
471 rc_uint_type len = (((bfd_signed_vma) id->u.n.length < 0 ? 0 : id->u.n.length) + 1);
472 if (wrbfd)
473 {
474 rc_uint_type i;
475 bfd_byte *d = (bfd_byte *) xmalloc (len * sizeof (unichar));
476 for (i = 0; i < (len - 1); i++)
477 windres_put_16 (wrbfd, d + (i * sizeof (unichar)), id->u.n.name[i]);
478 windres_put_16 (wrbfd, d + (i * sizeof (unichar)), 0);
479 set_windres_bfd_content (wrbfd, d, off, (len * sizeof (unichar)));
480 }
481 off += (len * sizeof (unichar));
482 }
483 else
484 {
485 if (wrbfd)
486 {
487 struct bin_res_id bid;
488 windres_put_16 (wrbfd, bid.sig, 0xffff);
489 windres_put_16 (wrbfd, bid.id, id->u.id);
490 set_windres_bfd_content (wrbfd, &bid, off, BIN_RES_ID);
491 }
492 off += BIN_RES_ID;
493 }
494 return off;
495 }
496
497 /* Write resource info */
498 static rc_uint_type
499 write_res_info (windres_bfd *wrbfd, rc_uint_type off, const rc_res_res_info *info)
500 {
501 if (wrbfd)
502 {
503 struct bin_res_info l;
504
505 windres_put_32 (wrbfd, l.version, info->version);
506 windres_put_16 (wrbfd, l.memflags, info->memflags);
507 windres_put_16 (wrbfd, l.language, info->language);
508 windres_put_32 (wrbfd, l.version2, info->version);
509 windres_put_32 (wrbfd, l.characteristics, info->characteristics);
510 set_windres_bfd_content (wrbfd, &l, off, BIN_RES_INFO_SIZE);
511 }
512 return off + BIN_RES_INFO_SIZE;
513 }
514
515 /* read a resource identifier */
516 static void
517 read_res_id (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax, rc_res_id *id)
518 {
519 struct bin_res_id bid;
520 unsigned short ord;
521 unichar *id_s = NULL;
522 rc_uint_type len;
523
524 read_res_data (wrbfd, off, omax, &bid, BIN_RES_ID - 2);
525 ord = (unsigned short) windres_get_16 (wrbfd, bid.sig, 2);
526 if (ord == 0xFFFF) /* an ordinal id */
527 {
528 read_res_data (wrbfd, off, omax, bid.id, BIN_RES_ID - 2);
529 id->named = 0;
530 id->u.id = windres_get_16 (wrbfd, bid.id, 2);
531 }
532 else
533 /* named id */
534 {
535 off[0] -= 2;
536 id_s = read_unistring (wrbfd, off, omax, &len);
537 id->named = 1;
538 id->u.n.length = len;
539 id->u.n.name = id_s;
540 }
541 }
542
543 /* Read a null terminated UNICODE string */
544 static unichar *
545 read_unistring (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax,
546 rc_uint_type *len)
547 {
548 unichar *s;
549 bfd_byte d[2];
550 unichar c;
551 unichar *p;
552 rc_uint_type l;
553 rc_uint_type soff = off[0];
554
555 do
556 {
557 read_res_data (wrbfd, &soff, omax, d, sizeof (unichar));
558 c = windres_get_16 (wrbfd, d, 2);
559 }
560 while (c != 0);
561 l = ((soff - off[0]) / sizeof (unichar));
562
563 /* there are hardly any names longer than 256 characters, but anyway. */
564 p = s = (unichar *) xmalloc (sizeof (unichar) * l);
565 do
566 {
567 read_res_data (wrbfd, off, omax, d, sizeof (unichar));
568 c = windres_get_16 (wrbfd, d, 2);
569 *p++ = c;
570 }
571 while (c != 0);
572 *len = l - 1;
573 return s;
574 }
575
576 static int
577 probe_binary (windres_bfd *wrbfd, rc_uint_type omax)
578 {
579 rc_uint_type off;
580 res_hdr reshdr;
581
582 off = 0;
583 read_res_data_hdr (wrbfd, &off, omax, &reshdr);
584 if (reshdr.data_size != 0)
585 return 1;
586 if ((reshdr.header_size != 0x20 && ! target_is_bigendian)
587 || (reshdr.header_size != 0x20000000 && target_is_bigendian))
588 return 1;
589
590 /* Subtract size of HeaderSize. DataSize has to be zero. */
591 off += 0x20 - BIN_RES_HDR_SIZE;
592 if ((off + BIN_RES_HDR_SIZE) >= omax)
593 return 1;
594 read_res_data_hdr (wrbfd, &off, omax, &reshdr);
595 /* off is advanced by BIN_RES_HDR_SIZE in read_res_data_hdr()
596 which is part of reshdr.header_size. We shouldn't take it
597 into account twice. */
598 if ((off - BIN_RES_HDR_SIZE + reshdr.data_size + reshdr.header_size) > omax)
599 return 0;
600 return 1;
601 }
602
603 /* Check if file is a win32 binary resource file, if so
604 skip past the null resource. Returns 0 if successful, -1 on
605 error.
606 */
607 static void
608 skip_null_resource (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax)
609 {
610 res_hdr reshdr;
611 read_res_data_hdr (wrbfd, off, omax, &reshdr);
612 if (reshdr.data_size != 0)
613 goto skip_err;
614 if ((reshdr.header_size != 0x20 && ! target_is_bigendian)
615 || (reshdr.header_size != 0x20000000 && target_is_bigendian))
616 goto skip_err;
617
618 /* Subtract size of HeaderSize. DataSize has to be zero. */
619 off[0] += 0x20 - BIN_RES_HDR_SIZE;
620 if (off[0] >= omax)
621 goto skip_err;
622
623 return;
624
625 skip_err:
626 fprintf (stderr, "%s: %s: Not a valid WIN32 resource file\n", program_name,
627 filename);
628 xexit (1);
629 }
630
631 /* Add a resource to resource directory */
632 static void
633 res_add_resource (rc_res_resource *r, const rc_res_id *type, const rc_res_id *id,
634 rc_uint_type language, int dupok)
635 {
636 rc_res_id a[3];
637
638 a[0] = *type;
639 a[1] = *id;
640 a[2].named = 0;
641 a[2].u.id = language;
642 res_append_resource (&resources, r, 3, a, dupok);
643 }
644
645 /* Append a resource to resource directory.
646 This is just copied from define_resource
647 and modified to add an existing resource.
648 */
649 static void
650 res_append_resource (rc_res_directory **res_dirs, rc_res_resource *resource,
651 int cids, const rc_res_id *ids, int dupok)
652 {
653 rc_res_entry *re = NULL;
654 int i;
655
656 assert (cids > 0);
657 for (i = 0; i < cids; i++)
658 {
659 rc_res_entry **pp;
660
661 if (*res_dirs == NULL)
662 {
663 static unsigned long timeval;
664
665 /* Use the same timestamp for every resource created in a
666 single run. */
667 if (timeval == 0)
668 timeval = time (NULL);
669
670 *res_dirs = ((rc_res_directory *)
671 res_alloc (sizeof (rc_res_directory)));
672 (*res_dirs)->characteristics = 0;
673 (*res_dirs)->time = timeval;
674 (*res_dirs)->major = 0;
675 (*res_dirs)->minor = 0;
676 (*res_dirs)->entries = NULL;
677 }
678
679 for (pp = &(*res_dirs)->entries; *pp != NULL; pp = &(*pp)->next)
680 if (res_id_cmp ((*pp)->id, ids[i]) == 0)
681 break;
682
683 if (*pp != NULL)
684 re = *pp;
685 else
686 {
687 re = (rc_res_entry *) res_alloc (sizeof (rc_res_entry));
688 re->next = NULL;
689 re->id = ids[i];
690 if ((i + 1) < cids)
691 {
692 re->subdir = 1;
693 re->u.dir = NULL;
694 }
695 else
696 {
697 re->subdir = 0;
698 re->u.res = NULL;
699 }
700
701 *pp = re;
702 }
703
704 if ((i + 1) < cids)
705 {
706 if (! re->subdir)
707 {
708 fprintf (stderr, "%s: ", program_name);
709 res_ids_print (stderr, i, ids);
710 fprintf (stderr, ": expected to be a directory\n");
711 xexit (1);
712 }
713
714 res_dirs = &re->u.dir;
715 }
716 }
717
718 if (re->subdir)
719 {
720 fprintf (stderr, "%s: ", program_name);
721 res_ids_print (stderr, cids, ids);
722 fprintf (stderr, ": expected to be a leaf\n");
723 xexit (1);
724 }
725
726 if (re->u.res != NULL)
727 {
728 if (dupok)
729 return;
730
731 fprintf (stderr, "%s: warning: ", program_name);
732 res_ids_print (stderr, cids, ids);
733 fprintf (stderr, ": duplicate value\n");
734 }
735
736 re->u.res = resource;
737 }
This page took 0.045003 seconds and 4 git commands to generate.