Updated windres tool
[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, 2007
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 2 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_endianess (&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 (abfd, ".data");
132 if (sec == NULL)
133 bfd_fatal ("bfd_make_section");
134 if (! bfd_set_section_flags (abfd, sec,
135 (SEC_HAS_CONTENTS | SEC_ALLOC
136 | SEC_LOAD | SEC_DATA)))
137 bfd_fatal ("bfd_set_section_flags");
138 /* Requiring this is probably a bug in BFD. */
139 sec->output_section = sec;
140
141 set_windres_bfd (&wrbfd, abfd, sec,
142 (target_is_bigendian ? WR_KIND_BFD_BIN_B
143 : WR_KIND_BFD_BIN_L));
144
145 language = -1;
146 sec_length = write_res_directory ((windres_bfd *) NULL, 0x20UL, resdir,
147 (const rc_res_id *) NULL,
148 (const rc_res_id *) NULL, &language, 1);
149 if (! bfd_set_section_size (abfd, sec, (sec_length + 3) & ~3))
150 bfd_fatal ("bfd_set_section_size");
151 if ((sec_length & 3) != 0)
152 set_windres_bfd_content (&wrbfd, sign, sec_length, 4-(sec_length & 3));
153 set_windres_bfd_content (&wrbfd, sign, 0, sizeof (sign));
154 language = -1;
155 sec_length_wrote = write_res_directory (&wrbfd, 0x20UL, resdir,
156 (const rc_res_id *) NULL,
157 (const rc_res_id *) NULL,
158 &language, 1);
159 if (sec_length != sec_length_wrote)
160 fatal ("res write failed with different sizes (%lu/%lu).", (long) sec_length,
161 (long) sec_length_wrote);
162
163 bfd_close (abfd);
164 return;
165 }
166
167 /* Read a resource entry, returns 0 when all resources are read */
168 static int
169 read_resource_entry (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax)
170 {
171 rc_res_id type;
172 rc_res_id name;
173 rc_res_res_info resinfo;
174 res_hdr reshdr;
175 void *buff;
176
177 rc_res_resource *r;
178 struct bin_res_info l;
179
180 off[0] = (off[0] + 3) & ~3;
181
182 /* Read header */
183 if ((off[0] + 8) > omax)
184 return 0;
185 read_res_data_hdr (wrbfd, off, omax, &reshdr);
186
187 /* read resource type */
188 read_res_id (wrbfd, off, omax, &type);
189 /* read resource id */
190 read_res_id (wrbfd, off, omax, &name);
191
192 off[0] = (off[0] + 3) & ~3;
193
194 /* Read additional resource header */
195 read_res_data (wrbfd, off, omax, &l, BIN_RES_INFO_SIZE);
196 resinfo.version = windres_get_32 (wrbfd, l.version, 4);
197 resinfo.memflags = windres_get_16 (wrbfd, l.memflags, 2);
198 resinfo.language = windres_get_16 (wrbfd, l.language, 2);
199 /* resinfo.version2 = windres_get_32 (wrbfd, l.version2, 4); */
200 resinfo.characteristics = windres_get_32 (wrbfd, l.characteristics, 4);
201
202 off[0] = (off[0] + 3) & ~3;
203
204 /* Allocate buffer for data */
205 buff = res_alloc (reshdr.data_size);
206 /* Read data */
207 read_res_data (wrbfd, off, omax, buff, reshdr.data_size);
208 /* Convert binary data to resource */
209 r = bin_to_res (wrbfd, type, buff, reshdr.data_size);
210 r->res_info = resinfo;
211 /* Add resource to resource directory */
212 res_add_resource (r, &type, &name, resinfo.language, 0);
213
214 return 1;
215 }
216
217 /* write resource directory to binary resource file */
218 static rc_uint_type
219 write_res_directory (windres_bfd *wrbfd, rc_uint_type off, const rc_res_directory *rd,
220 const rc_res_id *type, const rc_res_id *name, rc_uint_type *language,
221 int level)
222 {
223 const rc_res_entry *re;
224
225 for (re = rd->entries; re != NULL; re = re->next)
226 {
227 switch (level)
228 {
229 case 1:
230 /* If we're at level 1, the key of this resource is the
231 type. This normally duplicates the information we have
232 stored with the resource itself, but we need to remember
233 the type if this is a user define resource type. */
234 type = &re->id;
235 break;
236
237 case 2:
238 /* If we're at level 2, the key of this resource is the name
239 we are going to use in the rc printout. */
240 name = &re->id;
241 break;
242
243 case 3:
244 /* If we're at level 3, then this key represents a language.
245 Use it to update the current language. */
246 if (! re->id.named
247 && re->id.u.id != (unsigned long) *language
248 && (re->id.u.id & 0xffff) == re->id.u.id)
249 {
250 *language = re->id.u.id;
251 }
252 break;
253
254 default:
255 break;
256 }
257
258 if (re->subdir)
259 off = write_res_directory (wrbfd, off, re->u.dir, type, name, language,
260 level + 1);
261 else
262 {
263 if (level == 3)
264 {
265 /* This is the normal case: the three levels are
266 TYPE/NAME/LANGUAGE. NAME will have been set at level
267 2, and represents the name to use. We probably just
268 set LANGUAGE, and it will probably match what the
269 resource itself records if anything. */
270 off = write_res_resource (wrbfd, off, type, name, re->u.res,
271 language);
272 }
273 else
274 {
275 fprintf (stderr, "// Resource at unexpected level %d\n", level);
276 off = write_res_resource (wrbfd, off, type, (rc_res_id *) NULL,
277 re->u.res, language);
278 }
279 }
280 }
281
282 return off;
283 }
284
285 static rc_uint_type
286 write_res_resource (windres_bfd *wrbfd, rc_uint_type off, const rc_res_id *type,
287 const rc_res_id *name, const rc_res_resource *res,
288 rc_uint_type *language ATTRIBUTE_UNUSED)
289 {
290 int rt;
291
292 switch (res->type)
293 {
294 default:
295 abort ();
296
297 case RES_TYPE_ACCELERATOR:
298 rt = RT_ACCELERATOR;
299 break;
300
301 case RES_TYPE_BITMAP:
302 rt = RT_BITMAP;
303 break;
304
305 case RES_TYPE_CURSOR:
306 rt = RT_CURSOR;
307 break;
308
309 case RES_TYPE_GROUP_CURSOR:
310 rt = RT_GROUP_CURSOR;
311 break;
312
313 case RES_TYPE_DIALOG:
314 rt = RT_DIALOG;
315 break;
316
317 case RES_TYPE_FONT:
318 rt = RT_FONT;
319 break;
320
321 case RES_TYPE_FONTDIR:
322 rt = RT_FONTDIR;
323 break;
324
325 case RES_TYPE_ICON:
326 rt = RT_ICON;
327 break;
328
329 case RES_TYPE_GROUP_ICON:
330 rt = RT_GROUP_ICON;
331 break;
332
333 case RES_TYPE_MENU:
334 rt = RT_MENU;
335 break;
336
337 case RES_TYPE_MESSAGETABLE:
338 rt = RT_MESSAGETABLE;
339 break;
340
341 case RES_TYPE_RCDATA:
342 rt = RT_RCDATA;
343 break;
344
345 case RES_TYPE_STRINGTABLE:
346 rt = RT_STRING;
347 break;
348
349 case RES_TYPE_USERDATA:
350 rt = 0;
351 break;
352
353 case RES_TYPE_VERSIONINFO:
354 rt = RT_VERSION;
355 break;
356
357 case RES_TYPE_TOOLBAR:
358 rt = RT_TOOLBAR;
359 break;
360 }
361
362 if (rt != 0
363 && type != NULL
364 && (type->named || type->u.id != (unsigned long) rt))
365 {
366 fprintf (stderr, "// Unexpected resource type mismatch: ");
367 res_id_print (stderr, *type, 1);
368 fprintf (stderr, " != %d", rt);
369 abort ();
370 }
371
372 return write_res_bin (wrbfd, off, res, type, name, &res->res_info);
373 }
374
375 /* Write a resource in binary resource format */
376 static rc_uint_type
377 write_res_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res,
378 const rc_res_id *type, const rc_res_id *name,
379 const rc_res_res_info *resinfo)
380 {
381 rc_uint_type noff;
382 rc_uint_type datasize = 0;
383
384 noff = res_to_bin ((windres_bfd *) NULL, off, res);
385 datasize = noff - off;
386
387 off = write_res_header (wrbfd, off, datasize, type, name, resinfo);
388 return res_to_bin (wrbfd, off, res);
389 }
390
391 /* Get number of bytes needed to store an id in binary format */
392 static unsigned long
393 get_id_size (id)
394 const rc_res_id *id;
395 {
396 if (id->named)
397 return sizeof (unichar) * (id->u.n.length + 1);
398 else
399 return sizeof (unichar) * 2;
400 }
401
402 /* Write a resource header */
403 static rc_uint_type
404 write_res_header (windres_bfd *wrbfd, rc_uint_type off, rc_uint_type datasize,
405 const rc_res_id *type, const rc_res_id *name,
406 const rc_res_res_info *resinfo)
407 {
408 res_hdr reshdr;
409 reshdr.data_size = datasize;
410 reshdr.header_size = 24 + get_id_size (type) + get_id_size (name);
411
412 reshdr.header_size = (reshdr.header_size + 3) & ~3;
413
414 off = (off + 3) & ~3;
415
416 off = write_res_data_hdr (wrbfd, off, &reshdr);
417 off = write_res_id (wrbfd, off, type);
418 off = write_res_id (wrbfd, off, name);
419
420 off = (off + 3) & ~3;
421
422 off = write_res_info (wrbfd, off, resinfo);
423 off = (off + 3) & ~3;
424 return off;
425 }
426
427 static rc_uint_type
428 write_res_data_hdr (windres_bfd *wrbfd, rc_uint_type off, res_hdr *hdr)
429 {
430 if (wrbfd)
431 {
432 struct bin_res_hdr brh;
433 windres_put_32 (wrbfd, brh.data_size, hdr->data_size);
434 windres_put_32 (wrbfd, brh.header_size, hdr->header_size);
435 set_windres_bfd_content (wrbfd, &brh, off, BIN_RES_HDR_SIZE);
436 }
437 return off + BIN_RES_HDR_SIZE;
438 }
439
440 static void
441 read_res_data_hdr (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax,
442 res_hdr *reshdr)
443 {
444 struct bin_res_hdr brh;
445
446 if ((off[0] + BIN_RES_HDR_SIZE) > omax)
447 fatal ("%s: unexpected end of file %ld/%ld", filename,(long) off[0], (long) omax);
448
449 get_windres_bfd_content (wrbfd, &brh, off[0], BIN_RES_HDR_SIZE);
450 reshdr->data_size = windres_get_32 (wrbfd, brh.data_size, 4);
451 reshdr->header_size = windres_get_32 (wrbfd, brh.header_size, 4);
452 off[0] += BIN_RES_HDR_SIZE;
453 }
454
455 /* Read data from file, abort on failure */
456 static void
457 read_res_data (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax, void *data,
458 rc_uint_type size)
459 {
460 if ((off[0] + size) > omax)
461 fatal ("%s: unexpected end of file %ld/%ld %ld", filename,(long) off[0],
462 (long) omax, (long) size);
463 get_windres_bfd_content (wrbfd, data, off[0], size);
464 off[0] += size;
465 }
466
467 /* Write a resource id */
468 static rc_uint_type
469 write_res_id (windres_bfd *wrbfd, rc_uint_type off, const rc_res_id *id)
470 {
471 if (id->named)
472 {
473 rc_uint_type len = (((bfd_signed_vma) id->u.n.length < 0 ? 0 : id->u.n.length) + 1);
474 if (wrbfd)
475 {
476 rc_uint_type i;
477 bfd_byte *d = (bfd_byte *) xmalloc (len * sizeof (unichar));
478 for (i = 0; i < (len - 1); i++)
479 windres_put_16 (wrbfd, d + (i * sizeof (unichar)), id->u.n.name[i]);
480 windres_put_16 (wrbfd, d + (i * sizeof (unichar)), 0);
481 set_windres_bfd_content (wrbfd, d, off, (len * sizeof (unichar)));
482 }
483 off += (len * sizeof (unichar));
484 }
485 else
486 {
487 if (wrbfd)
488 {
489 struct bin_res_id bid;
490 windres_put_16 (wrbfd, bid.sig, 0xffff);
491 windres_put_16 (wrbfd, bid.id, id->u.id);
492 set_windres_bfd_content (wrbfd, &bid, off, BIN_RES_ID);
493 }
494 off += BIN_RES_ID;
495 }
496 return off;
497 }
498
499 /* Write resource info */
500 static rc_uint_type
501 write_res_info (windres_bfd *wrbfd, rc_uint_type off, const rc_res_res_info *info)
502 {
503 if (wrbfd)
504 {
505 struct bin_res_info l;
506
507 windres_put_32 (wrbfd, l.version, info->version);
508 windres_put_16 (wrbfd, l.memflags, info->memflags);
509 windres_put_16 (wrbfd, l.language, info->language);
510 windres_put_32 (wrbfd, l.version2, info->version);
511 windres_put_32 (wrbfd, l.characteristics, info->characteristics);
512 set_windres_bfd_content (wrbfd, &l, off, BIN_RES_INFO_SIZE);
513 }
514 return off + BIN_RES_INFO_SIZE;
515 }
516
517 /* read a resource identifier */
518 static void
519 read_res_id (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax, rc_res_id *id)
520 {
521 struct bin_res_id bid;
522 unsigned short ord;
523 unichar *id_s = NULL;
524 rc_uint_type len;
525
526 read_res_data (wrbfd, off, omax, &bid, BIN_RES_ID - 2);
527 ord = (unsigned short) windres_get_16 (wrbfd, bid.sig, 2);
528 if (ord == 0xFFFF) /* an ordinal id */
529 {
530 read_res_data (wrbfd, off, omax, bid.id, BIN_RES_ID - 2);
531 id->named = 0;
532 id->u.id = windres_get_16 (wrbfd, bid.id, 2);
533 }
534 else
535 /* named id */
536 {
537 off[0] -= 2;
538 id_s = read_unistring (wrbfd, off, omax, &len);
539 id->named = 1;
540 id->u.n.length = len;
541 id->u.n.name = id_s;
542 }
543 }
544
545 /* Read a null terminated UNICODE string */
546 static unichar *
547 read_unistring (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax,
548 rc_uint_type *len)
549 {
550 unichar *s;
551 bfd_byte d[2];
552 unichar c;
553 unichar *p;
554 rc_uint_type l;
555 rc_uint_type soff = off[0];
556
557 do {
558 read_res_data (wrbfd, &soff, omax, d, sizeof (unichar));
559 c = windres_get_16 (wrbfd, d, 2);
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 if ((off + reshdr.data_size + reshdr.header_size) > omax)
596 return 0;
597 return 1;
598 }
599
600 /* Check if file is a win32 binary resource file, if so
601 skip past the null resource. Returns 0 if successful, -1 on
602 error.
603 */
604 static void
605 skip_null_resource (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax)
606 {
607 res_hdr reshdr;
608 read_res_data_hdr (wrbfd, off, omax, &reshdr);
609 if (reshdr.data_size != 0)
610 goto skip_err;
611 if ((reshdr.header_size != 0x20 && ! target_is_bigendian)
612 || (reshdr.header_size != 0x20000000 && target_is_bigendian))
613 goto skip_err;
614
615 /* Subtract size of HeaderSize. DataSize has to be zero. */
616 off[0] += 0x20 - BIN_RES_HDR_SIZE;
617 if (off[0] >= omax)
618 goto skip_err;
619
620 return;
621
622 skip_err:
623 fprintf (stderr, "%s: %s: Not a valid WIN32 resource file\n", program_name,
624 filename);
625 xexit (1);
626 }
627
628 /* Add a resource to resource directory */
629 static void
630 res_add_resource (rc_res_resource *r, const rc_res_id *type, const rc_res_id *id,
631 rc_uint_type language, int dupok)
632 {
633 rc_res_id a[3];
634
635 a[0] = *type;
636 a[1] = *id;
637 a[2].named = 0;
638 a[2].u.id = language;
639 res_append_resource (&resources, r, 3, a, dupok);
640 }
641
642 /* Append a resource to resource directory.
643 This is just copied from define_resource
644 and modified to add an existing resource.
645 */
646 static void
647 res_append_resource (rc_res_directory **resources, rc_res_resource *resource,
648 int cids, const rc_res_id *ids, int dupok)
649 {
650 rc_res_entry *re = NULL;
651 int i;
652
653 assert (cids > 0);
654 for (i = 0; i < cids; i++)
655 {
656 rc_res_entry **pp;
657
658 if (*resources == NULL)
659 {
660 static unsigned long timeval;
661
662 /* Use the same timestamp for every resource created in a
663 single run. */
664 if (timeval == 0)
665 timeval = time (NULL);
666
667 *resources = ((rc_res_directory *)
668 res_alloc (sizeof (rc_res_directory)));
669 (*resources)->characteristics = 0;
670 (*resources)->time = timeval;
671 (*resources)->major = 0;
672 (*resources)->minor = 0;
673 (*resources)->entries = NULL;
674 }
675
676 for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next)
677 if (res_id_cmp ((*pp)->id, ids[i]) == 0)
678 break;
679
680 if (*pp != NULL)
681 re = *pp;
682 else
683 {
684 re = (rc_res_entry *) res_alloc (sizeof (rc_res_entry));
685 re->next = NULL;
686 re->id = ids[i];
687 if ((i + 1) < cids)
688 {
689 re->subdir = 1;
690 re->u.dir = NULL;
691 }
692 else
693 {
694 re->subdir = 0;
695 re->u.res = NULL;
696 }
697
698 *pp = re;
699 }
700
701 if ((i + 1) < cids)
702 {
703 if (! re->subdir)
704 {
705 fprintf (stderr, "%s: ", program_name);
706 res_ids_print (stderr, i, ids);
707 fprintf (stderr, ": expected to be a directory\n");
708 xexit (1);
709 }
710
711 resources = &re->u.dir;
712 }
713 }
714
715 if (re->subdir)
716 {
717 fprintf (stderr, "%s: ", program_name);
718 res_ids_print (stderr, cids, ids);
719 fprintf (stderr, ": expected to be a leaf\n");
720 xexit (1);
721 }
722
723 if (re->u.res != NULL)
724 {
725 if (dupok)
726 return;
727
728 fprintf (stderr, "%s: warning: ", program_name);
729 res_ids_print (stderr, cids, ids);
730 fprintf (stderr, ": duplicate value\n");
731 }
732
733 re->u.res = resource;
734 }
This page took 0.065673 seconds and 5 git commands to generate.