2 Copyright (C) 2005-2008, The Perl Foundation.
7 pbc_merge - Merge multiple Parrot bytecode (PBC) files into
12 pbc_merge -o out.pbc input1.pbc input2.pbc ...
16 This program takes two or more PBC files and produces a single
17 merged output PBC file with a single fix-up table and constants
20 =head2 Command-Line Options
26 The name of the PBC file to produce, containing the merged
27 segments from the input PBC files.
40 #include "parrot/parrot.h"
41 #include "parrot/embed.h"
42 #include "parrot/oplib/ops.h"
45 /* This struct describes an input file. */
46 typedef struct pbc_merge_input
{
47 const char *filename
; /* Filename of the input file. */
48 PackFile
*pf
; /* The loaded packfile. */
49 opcode_t code_start
; /* Where the bytecode is located in the merged
51 opcode_t const_start
; /* Where the const table is located in the merged
55 /* HEADERIZER HFILE: none */
57 /* HEADERIZER BEGIN: static */
58 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
60 PARROT_DOES_NOT_RETURN
61 static void help(PARROT_INTERP
)
62 __attribute__nonnull__(1);
64 PARROT_WARN_UNUSED_RESULT
65 PARROT_CANNOT_RETURN_NULL
66 static PackFile
* pbc_merge_begin(PARROT_INTERP
,
67 ARGMOD(pbc_merge_input
**inputs
),
69 __attribute__nonnull__(1)
70 __attribute__nonnull__(2)
71 FUNC_MODIFIES(*inputs
);
73 PARROT_WARN_UNUSED_RESULT
74 PARROT_CANNOT_RETURN_NULL
75 static PackFile_ByteCode
* pbc_merge_bytecode(PARROT_INTERP
,
76 ARGMOD(pbc_merge_input
**inputs
),
79 __attribute__nonnull__(1)
80 __attribute__nonnull__(2)
81 __attribute__nonnull__(4)
82 FUNC_MODIFIES(*inputs
)
85 PARROT_WARN_UNUSED_RESULT
86 PARROT_CANNOT_RETURN_NULL
87 static PackFile_ConstTable
* pbc_merge_constants(PARROT_INTERP
,
88 ARGMOD(pbc_merge_input
**inputs
),
91 ARGMOD(PackFile_ByteCode
*bc
))
92 __attribute__nonnull__(1)
93 __attribute__nonnull__(2)
94 __attribute__nonnull__(4)
95 __attribute__nonnull__(5)
96 FUNC_MODIFIES(*inputs
)
100 static void pbc_merge_ctpointers(PARROT_INTERP
,
101 ARGMOD(pbc_merge_input
**inputs
),
103 ARGMOD(PackFile_ByteCode
*bc
))
104 __attribute__nonnull__(1)
105 __attribute__nonnull__(2)
106 __attribute__nonnull__(4)
107 FUNC_MODIFIES(*inputs
)
110 static void pbc_merge_debugs(PARROT_INTERP
,
111 ARGMOD(pbc_merge_input
**inputs
),
113 ARGMOD(PackFile
*pf
),
114 ARGMOD(PackFile_ByteCode
*bc
))
115 __attribute__nonnull__(1)
116 __attribute__nonnull__(2)
117 __attribute__nonnull__(4)
118 __attribute__nonnull__(5)
119 FUNC_MODIFIES(*inputs
)
123 static void pbc_merge_fixups(PARROT_INTERP
,
124 ARGIN(pbc_merge_input
**inputs
),
126 ARGMOD(PackFile
*pf
),
127 ARGMOD(PackFile_ByteCode
*bc
))
128 __attribute__nonnull__(1)
129 __attribute__nonnull__(2)
130 __attribute__nonnull__(4)
131 __attribute__nonnull__(5)
135 PARROT_WARN_UNUSED_RESULT
136 PARROT_CANNOT_RETURN_NULL
137 static PackFile
* pbc_merge_loadpbc(PARROT_INTERP
,
138 ARGIN(const char *fullname
))
139 __attribute__nonnull__(1)
140 __attribute__nonnull__(2);
142 static void pbc_merge_pic_index(PARROT_INTERP
,
143 ARGMOD(pbc_merge_input
**inputs
),
145 ARGMOD(PackFile
*pf
),
146 ARGMOD(PackFile_ByteCode
*bc
))
147 __attribute__nonnull__(1)
148 __attribute__nonnull__(2)
149 __attribute__nonnull__(4)
150 __attribute__nonnull__(5)
151 FUNC_MODIFIES(*inputs
)
155 static void pbc_merge_write(PARROT_INTERP
,
156 ARGMOD(PackFile
*pf
),
157 ARGIN(const char *filename
))
158 __attribute__nonnull__(1)
159 __attribute__nonnull__(2)
160 __attribute__nonnull__(3)
163 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
164 /* HEADERIZER END: static */
168 =item C<static void help>
170 Print out the user help info.
176 PARROT_DOES_NOT_RETURN
180 printf("pbc_merge - merge multiple parrot bytecode files into one\n");
182 printf(" pbc_merge -o out.pbc file1.pbc file2.pbc ...\n\n");
183 Parrot_exit(interp
, 0);
188 =item C<static PackFile* pbc_merge_loadpbc>
190 This function loads a PBC file and unpacks it. We can't
191 use Parrot_readbc because that is specified to also
192 fixup the segments, which we don't want.
198 PARROT_WARN_UNUSED_RESULT
199 PARROT_CANNOT_RETURN_NULL
201 pbc_merge_loadpbc(PARROT_INTERP
, ARGIN(const char *fullname
))
203 INTVAL program_size
, wanted
;
207 INTVAL is_mapped
= 0;
212 /* Check the file exists. */
213 STRING
* const fs
= string_make(interp
, fullname
,
214 strlen(fullname
), NULL
, 0);
215 if (!Parrot_stat_info_intval(interp
, fs
, STAT_EXISTS
)) {
216 PIO_eprintf(interp
, "PBC Merge: Can't stat %s, code %i.\n",
218 Parrot_exit(interp
, 1);
221 /* Get program size. */
222 program_size
= Parrot_stat_info_intval(interp
, fs
, STAT_FILESIZE
);
224 /* Attempt to open file and handle any errors. */
225 io
= fopen(fullname
, "rb");
227 PIO_eprintf(interp
, "PBC Merge: Can't open %s, code %i.\n",
229 Parrot_exit(interp
, 1);
232 /* Read in program. Nabbed from Parrot_readpbc. */
233 chunk_size
= program_size
> 0 ? program_size
: 1024;
234 program_code
= (char *)mem_sys_allocate(chunk_size
);
235 wanted
= program_size
;
237 cursor
= (char *)program_code
;
239 while ((read_result
= fread(cursor
, 1, chunk_size
, io
)) > 0) {
240 program_size
+= read_result
;
241 if (program_size
== wanted
)
245 (char *)mem_sys_realloc(program_code
, program_size
+ chunk_size
);
249 "PBC Merge: Could not reallocate buffer");
250 Parrot_exit(interp
, 1);
253 cursor
= (char *)program_code
+ program_size
;
256 if (read_result
< 0) {
258 "PBC Merge: Problem reading packfile from PIO.\n");
259 Parrot_exit(interp
, 1);
263 /* Now that we have the bytecode, let's unpack it. */
264 pf
= PackFile_new(interp
, is_mapped
);
265 if (!PackFile_unpack(interp
,
266 pf
, (opcode_t
*)program_code
, program_size
)) {
267 PIO_eprintf(interp
, "PBC Merge: Can't unpack packfile %s.\n",
269 Parrot_exit(interp
, 1);
272 /* Return the packfile. */
279 =item C<static PackFile_ByteCode* pbc_merge_bytecode>
281 This function merges the bytecode from the input packfiles, storing the
282 offsets that each bit of bytecode now exists at.
288 PARROT_WARN_UNUSED_RESULT
289 PARROT_CANNOT_RETURN_NULL
290 static PackFile_ByteCode
*
291 pbc_merge_bytecode(PARROT_INTERP
, ARGMOD(pbc_merge_input
**inputs
),
292 int num_inputs
, ARGMOD(PackFile
*pf
))
294 opcode_t
*bc
= mem_allocate_typed(opcode_t
);
298 /* Add a bytecode segment. */
299 PackFile_ByteCode
* const bc_seg
=
300 (PackFile_ByteCode
*)PackFile_Segment_new_seg(interp
,
301 &pf
->directory
, PF_BYTEC_SEG
, BYTE_CODE_SEGMENT_NAME
, 1);
302 if (bc_seg
== NULL
) {
303 PIO_eprintf(interp
, "PBC Merge: Error creating bytecode segment.");
304 Parrot_exit(interp
, 1);
307 /* Loop over input files. */
308 for (i
= 0; i
< num_inputs
; i
++) {
309 /* Get the bytecode segment from the input file. */
310 PackFile_ByteCode
* const in_seg
= inputs
[i
]->pf
->cur_cs
;
311 if (in_seg
== NULL
) {
313 "PBC Merge: Cannot locate bytecode segment in %s",
314 inputs
[i
]->filename
);
315 Parrot_exit(interp
, 1);
318 /* Re-allocate the current buffer. */
319 mem_realloc_n_typed(bc
, cursor
+ in_seg
->base
.size
, opcode_t
);
321 PIO_eprintf(interp
, "PBC Merge: Cannot reallocate memory\n");
322 Parrot_exit(interp
, 1);
325 /* Copy data and store cursor. */
326 memcpy(bc
+ cursor
, in_seg
->base
.data
,
327 in_seg
->base
.size
* sizeof (opcode_t
));
328 inputs
[i
]->code_start
= cursor
;
331 cursor
+= in_seg
->base
.size
;
334 /* Stash produced bytecode. */
335 bc_seg
->base
.data
= bc
;
336 bc_seg
->base
.size
= cursor
;
337 bc_seg
->base
.name
= str_dup("MERGED");
344 =item C<static PackFile_ConstTable* pbc_merge_constants>
346 This function merges the constants tables from the input PBC files.
352 PARROT_WARN_UNUSED_RESULT
353 PARROT_CANNOT_RETURN_NULL
354 static PackFile_ConstTable
*
355 pbc_merge_constants(PARROT_INTERP
, ARGMOD(pbc_merge_input
**inputs
),
356 int num_inputs
, ARGMOD(PackFile
*pf
), ARGMOD(PackFile_ByteCode
*bc
))
358 PackFile_Constant
**constants
= mem_allocate_typed(PackFile_Constant
*);
362 /* Add a constant table segment. */
363 PackFile_ConstTable
* const const_seg
= (PackFile_ConstTable
*)PackFile_Segment_new_seg(
364 interp
, &pf
->directory
, PF_CONST_SEG
, CONSTANT_SEGMENT_NAME
, 1);
365 if (const_seg
== NULL
) {
367 "PBC Merge: Error creating constant table segment.");
368 Parrot_exit(interp
, 1);
371 /* Loop over input files. */
372 for (i
= 0; i
< num_inputs
; i
++) {
373 /* Get the constant table segment from the input file. */
374 PackFile_ConstTable
* const in_seg
= inputs
[i
]->pf
->cur_cs
->const_table
;
375 if (in_seg
== NULL
) {
377 "PBC Merge: Cannot locate constant table segment in %s\n",
378 inputs
[i
]->filename
);
379 Parrot_exit(interp
, 1);
382 /* Store cursor as position where constant table starts. */
383 inputs
[i
]->const_start
= cursor
;
385 /* Allocate space for the constant list, provided we have some. */
386 if (in_seg
->const_count
> 0) {
387 constants
= (PackFile_Constant
**)mem_sys_realloc(constants
,
388 (cursor
+ in_seg
->const_count
) * sizeof (Parrot_Pointer
));
389 if (constants
== NULL
) {
390 PIO_eprintf(interp
, "PBC Merge: Out of memory");
391 Parrot_exit(interp
, 1);
395 /* Loop over the constants and copy them to the output PBC. */
396 for (j
= 0; j
< in_seg
->const_count
; j
++) {
397 /* Get the entry and allocate space for copy. */
398 PackFile_Constant
*cur_entry
= in_seg
->constants
[j
];
399 PackFile_Constant
*copy
= mem_allocate_typed(
402 PIO_eprintf(interp
, "PBC Merge: Out of memory");
403 Parrot_exit(interp
, 1);
406 STRUCT_COPY(copy
, cur_entry
);
408 /* If it's a sub PMC, need to deal with offsets. */
409 if (copy
->type
== PFC_PMC
) {
410 switch (copy
->u
.key
->vtable
->base_type
) {
412 case enum_class_Closure
:
413 case enum_class_Coroutine
:
415 Parrot_sub
* const sub
= PMC_sub(copy
->u
.key
);
416 sub
->start_offs
+= inputs
[i
]->code_start
;
417 sub
->end_offs
+= inputs
[i
]->code_start
;
425 /* Slot it into the list. */
426 constants
[cursor
] = copy
;
431 /* Stash merged constants table and count and return the new segment. */
432 const_seg
->constants
= constants
;
433 const_seg
->const_count
= cursor
;
434 const_seg
->code
= bc
;
435 bc
->const_table
= const_seg
;
442 =item C<static void pbc_merge_fixups>
444 This function merges the fixups tables from the input PBC files.
451 pbc_merge_fixups(PARROT_INTERP
, ARGIN(pbc_merge_input
**inputs
),
452 int num_inputs
, ARGMOD(PackFile
*pf
), ARGMOD(PackFile_ByteCode
*bc
))
454 PackFile_FixupTable
*fixup_seg
;
455 PackFile_FixupEntry
**fixups
= mem_allocate_typed(PackFile_FixupEntry
*);
459 /* Add a fixup table segment. */
460 fixup_seg
= (PackFile_FixupTable
*)PackFile_Segment_new_seg(
461 interp
, &pf
->directory
, PF_FIXUP_SEG
, FIXUP_TABLE_SEGMENT_NAME
, 1);
462 if (fixup_seg
== NULL
) {
464 "PBC Merge: Error creating fixup table segment.");
465 Parrot_exit(interp
, 1);
468 /* Loop over input files. */
469 for (i
= 0; i
< num_inputs
; i
++) {
470 /* Get the fixup segment from the input file. */
471 PackFile_FixupTable
* const in_seg
= inputs
[i
]->pf
->cur_cs
->fixups
;
472 if (in_seg
== NULL
) {
474 "PBC Merge: Cannot locate fixup segment in %s",
475 inputs
[i
]->filename
);
476 Parrot_exit(interp
, 1);
479 /* Allocate space for these fixups, provided we have some. */
480 if (in_seg
->fixup_count
> 0) {
481 fixups
= (PackFile_FixupEntry
**)mem_sys_realloc(fixups
,
482 (cursor
+ in_seg
->fixup_count
) * sizeof (Parrot_Pointer
));
483 if (fixups
== NULL
) {
484 PIO_eprintf(interp
, "PBC Merge: Out of memory");
485 Parrot_exit(interp
, 1);
489 /* Loop over the fixups and copy them to the output PBC, correcting
490 the offsets into the bytecode. */
491 for (j
= 0; j
< in_seg
->fixup_count
; j
++) {
492 /* Get the entry and allocate space for copies. */
493 PackFile_FixupEntry
*cur_entry
= in_seg
->fixups
[j
];
494 PackFile_FixupEntry
*copy
= mem_allocate_typed(
495 PackFile_FixupEntry
);
496 char *name_copy
= (char *)mem_sys_allocate(
497 strlen(cur_entry
->name
) + 1);
498 if (copy
== NULL
|| name_copy
== NULL
) {
499 PIO_eprintf(interp
, "PBC Merge: Out of memory");
500 Parrot_exit(interp
, 1);
503 /* Copy type and name. */
504 copy
->type
= cur_entry
->type
;
505 strcpy(name_copy
, cur_entry
->name
);
506 copy
->name
= name_copy
;
508 /* Set new offset and bytecode pointer. */
509 switch (copy
->type
) {
510 case enum_fixup_label
:
511 copy
->offset
= cur_entry
->offset
+ inputs
[i
]->code_start
;
514 copy
->offset
= cur_entry
->offset
+ inputs
[i
]->const_start
;
517 PIO_eprintf(interp
, "PBC Merge: Unknown fixup type");
518 Parrot_exit(interp
, 1);
523 /* Slot it into the list. */
524 fixups
[cursor
] = copy
;
529 /* Stash merged fixup table and count. */
530 fixup_seg
->fixups
= fixups
;
531 fixup_seg
->fixup_count
= cursor
;
537 =item C<static void pbc_merge_debugs>
539 This function merges the debug segments from the input PBC files.
546 pbc_merge_debugs(PARROT_INTERP
, ARGMOD(pbc_merge_input
**inputs
),
547 int num_inputs
, ARGMOD(PackFile
*pf
), ARGMOD(PackFile_ByteCode
*bc
))
549 PackFile_Debug
*debug_seg
;
550 opcode_t
*lines
= mem_allocate_typed(opcode_t
);
551 PackFile_DebugMapping
**mappings
=
552 mem_allocate_typed(PackFile_DebugMapping
*);
553 opcode_t num_mappings
= 0;
554 opcode_t num_lines
= 0;
557 /* We need to merge both the mappings and the list of line numbers.
558 The line numbers can just be concatenated. The mappings must have
559 their offsets fixed up. */
560 for (i
= 0; i
< num_inputs
; i
++) {
561 PackFile_Debug
*in_seg
= inputs
[i
]->pf
->cur_cs
->debugs
;
563 /* Concatenate line numbers. */
564 lines
= (opcode_t
*)mem_sys_realloc(lines
,
565 (num_lines
+ in_seg
->base
.size
) * sizeof (opcode_t
));
567 PIO_eprintf(interp
, "PBC Merge: Cannot reallocate memory\n");
568 Parrot_exit(interp
, 1);
570 memcpy(lines
+ num_lines
, in_seg
->base
.data
,
571 in_seg
->base
.size
* sizeof (opcode_t
));
573 /* Concatenate mappings. */
574 mappings
= (PackFile_DebugMapping
**)mem_sys_realloc(mappings
,
575 (num_mappings
+ in_seg
->num_mappings
) *
576 sizeof (Parrot_Pointer
));
577 for (j
= 0; j
< in_seg
->num_mappings
; j
++) {
578 PackFile_DebugMapping
*mapping
= mem_allocate_typed(
579 PackFile_DebugMapping
);
580 STRUCT_COPY(mapping
, in_seg
->mappings
[j
]);
581 mapping
->offset
+= num_lines
;
582 if (mapping
->mapping_type
== PF_DEBUGMAPPINGTYPE_FILENAME
)
583 mapping
->u
.filename
+= inputs
[i
]->const_start
;
584 mappings
[num_mappings
+ j
] = mapping
;
587 /* Update counts. The "- 1" allows for the fact that the size value
588 itself is included in in_seg->base.size. See RT#58660. */
589 num_lines
+= in_seg
->base
.size
- 1;
590 num_mappings
+= in_seg
->num_mappings
;
593 /* Create merged debug segment. Replace created data and mappings
594 with merged ones we have created. */
595 debug_seg
= Parrot_new_debug_seg(interp
, bc
, num_lines
);
596 PackFile_add_segment(interp
, &pf
->directory
, (PackFile_Segment
*)debug_seg
);
597 mem_sys_free(debug_seg
->base
.data
);
598 debug_seg
->base
.data
= lines
;
599 mem_sys_free(debug_seg
->mappings
);
601 debug_seg
->mappings
= mappings
;
602 debug_seg
->num_mappings
= num_mappings
;
607 =item C<static void pbc_merge_pic_index>
609 This function merges the pic_index segments from the input PBC files.
616 pbc_merge_pic_index(PARROT_INTERP
, ARGMOD(pbc_merge_input
**inputs
),
617 int num_inputs
, ARGMOD(PackFile
*pf
), ARGMOD(PackFile_ByteCode
*bc
))
620 PackFile_Segment
*pic_index
;
626 /* calc needed size */
627 for (i
= 0, size
= 0; i
< num_inputs
; i
++) {
628 PackFile_Segment
* const in_seg
= inputs
[i
]->pf
->cur_cs
->pic_index
;
629 size
+= in_seg
->size
;
631 pic_index
= PackFile_Segment_new_seg(interp
,
632 &pf
->directory
, PF_UNKNOWN_SEG
, "PIC_idx_MERGED", 1);
634 = (opcode_t
*)mem_sys_allocate_zeroed(size
* sizeof (opcode_t
));
635 pic_index
->size
= size
;
637 for (i
= 0, size
= 0; i
< num_inputs
; i
++) {
638 PackFile_Segment
* const in_seg
= inputs
[i
]->pf
->cur_cs
->pic_index
;
641 * pic_index is 0 or an ever increasing (by 1) number
643 for (j
= 0; j
< in_seg
->size
; j
++) {
644 const opcode_t k
= in_seg
->data
[j
];
646 pic_index
->data
[cursor
] = k
+ start
;
653 bc
->pic_index
= pic_index
;
658 =item C<static void pbc_merge_ctpointers>
660 This function corrects the pointers into the constants table found in the
668 pbc_merge_ctpointers(PARROT_INTERP
, ARGMOD(pbc_merge_input
**inputs
),
669 int num_inputs
, ARGMOD(PackFile_ByteCode
*bc
))
672 opcode_t
*ops
= bc
->base
.data
;
677 /* Loop over the ops in the merged bytecode. */
678 while (cur_op
< (opcode_t
)bc
->base
.size
) {
682 /* Keep track of the current input file. */
683 if (cur_input
+ 1 < num_inputs
&&
684 cur_op
>= inputs
[cur_input
+ 1]->code_start
)
687 /* Get info about this op and jump over it. */
688 op_num
= ops
[cur_op
];
689 op
= &interp
->op_info_table
[op_num
];
690 op_ptr
= ops
+ cur_op
;
693 /* Loop over the arguments. */
694 for (cur_arg
= 1; cur_arg
< op
->op_count
; cur_arg
++) {
695 /* Pick out any indexes into the constant table and correct them. */
696 switch (op
->types
[cur_arg
- 1]) {
701 ops
[cur_op
] += inputs
[cur_input
]->const_start
;
707 /* Move along the bytecode array. */
711 /* Handle special case variable argument opcodes. */
712 if (op_num
== PARROT_OP_set_args_pc
||
713 op_num
== PARROT_OP_get_results_pc
||
714 op_num
== PARROT_OP_get_params_pc
||
715 op_num
== PARROT_OP_set_returns_pc
) {
716 /* Get the signature. */
717 const PMC
* const sig
= bc
->const_table
->constants
[op_ptr
[1]]->u
.key
;
719 /* Loop over the arguments to locate any that need a fixup. */
720 const int sig_items
= SIG_ELEMS(sig
);
721 for (cur_arg
= 0; cur_arg
< sig_items
; cur_arg
++) {
722 switch (SIG_ITEM(sig
, cur_arg
)) {
727 ops
[cur_op
] += inputs
[cur_input
]->const_start
;
741 =item C<static PackFile* pbc_merge_begin>
743 This is the function that drives PBC merging process.
748 PARROT_WARN_UNUSED_RESULT
749 PARROT_CANNOT_RETURN_NULL
751 pbc_merge_begin(PARROT_INTERP
, ARGMOD(pbc_merge_input
**inputs
), int num_inputs
)
753 PackFile_ByteCode
*bc
;
754 PackFile_ConstTable
*ct
;
756 /* Create a new empty packfile. */
757 PackFile
* const merged
= PackFile_new(interp
, 0);
758 if (merged
== NULL
) {
759 PIO_eprintf(interp
, "PBC Merge: Error creating new packfile.\n");
760 Parrot_exit(interp
, 1);
763 /* Merge the various stuff. */
764 bc
= pbc_merge_bytecode(interp
, inputs
, num_inputs
, merged
);
765 ct
= pbc_merge_constants(interp
, inputs
, num_inputs
, merged
, bc
);
768 pbc_merge_fixups(interp
, inputs
, num_inputs
, merged
, bc
);
769 pbc_merge_debugs(interp
, inputs
, num_inputs
, merged
, bc
);
770 pbc_merge_pic_index(interp
, inputs
, num_inputs
, merged
, bc
);
772 /* Walk bytecode and fix ops that reference the constants table. */
773 pbc_merge_ctpointers(interp
, inputs
, num_inputs
, bc
);
775 /* Return merged result. */
782 =item C<static void pbc_merge_write>
784 This functions writes out the merged packfile.
791 pbc_merge_write(PARROT_INTERP
, ARGMOD(PackFile
*pf
), ARGIN(const char *filename
))
795 /* Get size of packfile we'll write. */
796 const size_t size
= PackFile_pack_size(interp
, pf
) * sizeof (opcode_t
);
798 /* Allocate memory. */
799 opcode_t
* const pack
= (opcode_t
*) mem_sys_allocate(size
);
801 PIO_eprintf(interp
, "PBC Merge: Out of memory");
802 Parrot_exit(interp
, 1);
805 /* Write and clean up. */
806 PackFile_pack(interp
, pf
, pack
);
807 if ((fp
= fopen(filename
, "wb")) == 0) {
808 PIO_eprintf(interp
, "PBC Merge: Couldn't open %s\n", filename
);
809 Parrot_exit(interp
, 1);
811 if ((1 != fwrite(pack
, size
, 1, fp
))) {
812 PIO_eprintf(interp
, "PBC Merge: Couldn't write %s\n", filename
);
813 Parrot_exit(interp
, 1);
824 The main function that grabs console input, reads in the packfiles
825 provided they exist, hands them to another function that runs the
826 merge process and finally writes out the produced packfile.
832 static struct longopt_opt_decl options
[] = {
833 { 'o', 'o', OPTION_required_FLAG
, { "--output" } }
837 main(int argc
, const char **argv
)
840 pbc_merge_input
** input_files
;
843 const char *output_file
= NULL
;
844 struct longopt_opt_info opt
= LONGOPT_OPT_INFO_INIT
;
845 Interp
* const interp
= Parrot_new(NULL
);
847 Parrot_block_GC_mark(interp
);
849 /* Get options, ensuring we have at least one input
850 file and an output file. */
854 while ((status
= longopt_get(interp
, argc
, argv
, options
, &opt
)) > 0) {
855 switch (opt
.opt_id
) {
857 if (output_file
== NULL
)
858 output_file
= opt
.opt_arg
;
869 if (status
== -1 || !output_file
) {
872 argc
-= opt
.opt_index
; /* Now the number of input files. */
873 argv
+= opt
.opt_index
; /* Now at first input filename. */
875 /* Load each packfile that we are to merge and set up an input
876 structure for each of them. */
877 input_files
= (pbc_merge_input
**)mem_sys_allocate(
878 argc
* sizeof (Parrot_Pointer
));
880 for (i
= 0; i
< argc
; i
++) {
881 /* Allocate a struct. */
882 input_files
[i
] = mem_allocate_typed(pbc_merge_input
);
885 input_files
[i
]->filename
= *argv
;
887 /* Load the packfile and unpack it. */
888 input_files
[i
]->pf
= pbc_merge_loadpbc(interp
,
889 input_files
[i
]->filename
);
890 if (input_files
[i
]->pf
== NULL
) {
892 "PBC Merge: Unknown error while reading and unpacking %s\n",
894 Parrot_exit(interp
, 1);
902 merged
= pbc_merge_begin(interp
, input_files
, argc
);
904 /* Write merged packfile. */
905 pbc_merge_write(interp
, merged
, output_file
);
907 /* Finally, we're done. */
908 Parrot_exit(interp
, 0);
914 * c-file-style: "parrot"
916 * vim: expandtab shiftwidth=4: