2 Copyright (C) 2005-2007, 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.
36 #include "parrot/parrot.h"
37 #include "parrot/embed.h"
38 #include "parrot/oplib/ops.h"
41 /* This struct describes an input file. */
42 typedef struct pbc_merge_input
{
43 const char *filename
; /* Filename of the input file. */
44 PackFile
*pf
; /* The loaded packfile. */
45 opcode_t code_start
; /* Where the bytecode is located in the merged
47 opcode_t const_start
; /* Where the const table is located in the merged
51 /* HEADERIZER HFILE: none */
53 /* HEADERIZER BEGIN: static */
55 static void help( PARROT_INTERP
)
56 __attribute__nonnull__(1);
58 PARROT_WARN_UNUSED_RESULT
59 PARROT_CANNOT_RETURN_NULL
60 static PackFile
* pbc_merge_begin( PARROT_INTERP
,
61 NOTNULL(pbc_merge_input
**inputs
),
63 __attribute__nonnull__(1)
64 __attribute__nonnull__(2);
66 PARROT_WARN_UNUSED_RESULT
67 PARROT_CANNOT_RETURN_NULL
68 static PackFile_ByteCode
* pbc_merge_bytecode( PARROT_INTERP
,
69 NOTNULL(pbc_merge_input
**inputs
),
71 NOTNULL(PackFile
*pf
) )
72 __attribute__nonnull__(1)
73 __attribute__nonnull__(2)
74 __attribute__nonnull__(4);
76 PARROT_WARN_UNUSED_RESULT
77 PARROT_CANNOT_RETURN_NULL
78 static PackFile_ConstTable
* pbc_merge_constants( PARROT_INTERP
,
79 NOTNULL(pbc_merge_input
**inputs
),
81 NOTNULL(PackFile
*pf
),
82 NOTNULL(PackFile_ByteCode
*bc
) )
83 __attribute__nonnull__(1)
84 __attribute__nonnull__(2)
85 __attribute__nonnull__(4)
86 __attribute__nonnull__(5);
88 static void pbc_merge_ctpointers( PARROT_INTERP
,
89 NOTNULL(pbc_merge_input
**inputs
),
91 NOTNULL(PackFile_ByteCode
*bc
) )
92 __attribute__nonnull__(1)
93 __attribute__nonnull__(2)
94 __attribute__nonnull__(4);
96 static void pbc_merge_debugs( PARROT_INTERP
,
97 NOTNULL(pbc_merge_input
**inputs
),
99 NOTNULL(PackFile
*pf
),
100 NOTNULL(PackFile_ByteCode
*bc
) )
101 __attribute__nonnull__(1)
102 __attribute__nonnull__(2)
103 __attribute__nonnull__(4)
104 __attribute__nonnull__(5);
106 static void pbc_merge_fixups( PARROT_INTERP
,
107 NOTNULL(pbc_merge_input
**inputs
),
109 NOTNULL(PackFile
*pf
),
110 NOTNULL(PackFile_ByteCode
*bc
) )
111 __attribute__nonnull__(1)
112 __attribute__nonnull__(2)
113 __attribute__nonnull__(4)
114 __attribute__nonnull__(5);
116 PARROT_WARN_UNUSED_RESULT
117 PARROT_CANNOT_RETURN_NULL
118 static PackFile
* pbc_merge_loadpbc( PARROT_INTERP
,
119 NOTNULL(const char *fullname
) )
120 __attribute__nonnull__(1)
121 __attribute__nonnull__(2);
123 static void pbc_merge_pic_index( PARROT_INTERP
,
124 NOTNULL(pbc_merge_input
**inputs
),
126 NOTNULL(PackFile
*pf
),
127 NOTNULL(PackFile_ByteCode
*bc
) )
128 __attribute__nonnull__(1)
129 __attribute__nonnull__(2)
130 __attribute__nonnull__(4)
131 __attribute__nonnull__(5);
133 static void pbc_merge_write( PARROT_INTERP
,
134 NOTNULL(PackFile
*pf
),
135 NOTNULL(const char *filename
) )
136 __attribute__nonnull__(1)
137 __attribute__nonnull__(2)
138 __attribute__nonnull__(3);
141 PARROT_CANNOT_RETURN_NULL
142 static char * str_dup( NOTNULL(const char *old
) )
143 __attribute__nonnull__(1);
145 /* HEADERIZER END: static */
149 static void help(Interp *)
151 Print out the user help info.
158 printf("pbc_merge - merge multiple parrot bytecode files into one\n");
160 printf(" pbc_merge -o out.pbc file1.pbc file2.pbc ...\n\n");
161 Parrot_exit(interp
, 0);
173 PARROT_CANNOT_RETURN_NULL
175 str_dup(NOTNULL(const char *old
))
177 const size_t bytes
= strlen(old
) + 1;
178 char * const copy
= mem_sys_allocate(bytes
);
179 memcpy(copy
, old
, bytes
);
181 debug(interp
, 1,"line %d str_dup %s [%x]\n", line
, old
, copy
);
188 FUNCDOC: 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.
195 PARROT_WARN_UNUSED_RESULT
196 PARROT_CANNOT_RETURN_NULL
198 pbc_merge_loadpbc(PARROT_INTERP
, NOTNULL(const char *fullname
))
200 INTVAL program_size
, wanted
;
204 INTVAL is_mapped
= 0;
209 /* Check the file exists. */
210 STRING
* const fs
= string_make(interp
, fullname
,
211 strlen(fullname
), NULL
, 0);
212 if (!Parrot_stat_info_intval(interp
, fs
, STAT_EXISTS
)) {
213 PIO_eprintf(interp
, "PBC Merge: Can't stat %s, code %i.\n",
215 Parrot_exit(interp
, 1);
218 /* Get program size. */
219 program_size
= Parrot_stat_info_intval(interp
, fs
, STAT_FILESIZE
);
221 /* Attempt to open file and handle any errors. */
222 io
= fopen(fullname
, "rb");
224 PIO_eprintf(interp
, "PBC Merge: Can't open %s, code %i.\n",
226 Parrot_exit(interp
, 1);
229 /* Read in program. Nabbed from Parrot_readpbc. */
230 chunk_size
= program_size
> 0 ? program_size
: 1024;
231 program_code
= (char *)mem_sys_allocate(chunk_size
);
232 wanted
= program_size
;
234 cursor
= (char *)program_code
;
236 while ((read_result
= fread(cursor
, 1, chunk_size
, io
)) > 0) {
237 program_size
+= read_result
;
238 if (program_size
== wanted
)
242 (char *)mem_sys_realloc(program_code
, program_size
+ chunk_size
);
246 "PBC Merge: Could not reallocate buffer");
247 Parrot_exit(interp
, 1);
250 cursor
= (char *)program_code
+ program_size
;
253 if (read_result
< 0) {
255 "PBC Merge: Problem reading packfile from PIO.\n");
256 Parrot_exit(interp
, 1);
260 /* Now that we have the bytecode, let's unpack it. */
261 pf
= PackFile_new(interp
, is_mapped
);
262 if (!PackFile_unpack(interp
,
263 pf
, (opcode_t
*)program_code
, program_size
)) {
264 PIO_eprintf(interp
, "PBC Merge: Can't unpack packfile %s.\n",
266 Parrot_exit(interp
, 1);
269 /* Return the packfile. */
276 FUNCDOC: pbc_merge_bytecode
278 This function merges the bytecode from the input packfiles, storing the
279 offsets that each bit of bytecode now exists at.
282 PARROT_WARN_UNUSED_RESULT
283 PARROT_CANNOT_RETURN_NULL
284 static PackFile_ByteCode
*
285 pbc_merge_bytecode(PARROT_INTERP
, NOTNULL(pbc_merge_input
**inputs
),
286 int num_inputs
, NOTNULL(PackFile
*pf
))
288 opcode_t
*bc
= mem_allocate_typed(opcode_t
);
292 /* Add a bytecode segment. */
293 PackFile_ByteCode
* const bc_seg
=
294 (PackFile_ByteCode
*)PackFile_Segment_new_seg(interp
,
295 &pf
->directory
, PF_BYTEC_SEG
, BYTE_CODE_SEGMENT_NAME
, 1);
296 if (bc_seg
== NULL
) {
297 PIO_eprintf(interp
, "PBC Merge: Error creating bytecode segment.");
298 Parrot_exit(interp
, 1);
301 /* Loop over input files. */
302 for (i
= 0; i
< num_inputs
; i
++) {
303 /* Get the bytecode segment from the input file. */
304 PackFile_ByteCode
*in_seg
= inputs
[i
]->pf
->cur_cs
;
305 if (in_seg
== NULL
) {
307 "PBC Merge: Cannot locate bytecode segment in %s",
308 inputs
[i
]->filename
);
309 Parrot_exit(interp
, 1);
312 /* Re-allocate the current buffer. */
313 bc
= (opcode_t
*)mem_sys_realloc(bc
,
314 (cursor
+ in_seg
->base
.size
) * sizeof (opcode_t
));
316 PIO_eprintf(interp
, "PBC Merge: Cannot reallocate memory\n");
317 Parrot_exit(interp
, 1);
320 /* Copy data and store cursor. */
321 memcpy(bc
+ cursor
, in_seg
->base
.data
,
322 in_seg
->base
.size
* sizeof (opcode_t
));
323 inputs
[i
]->code_start
= cursor
;
326 cursor
+= in_seg
->base
.size
;
329 /* Stash produced bytecode. */
330 bc_seg
->base
.data
= bc
;
331 bc_seg
->base
.size
= cursor
;
332 bc_seg
->base
.name
= str_dup("MERGED");
339 FUNCDOC: pbc_merge_constants
341 This function merges the constants tables from the input PBC files.
344 PARROT_WARN_UNUSED_RESULT
345 PARROT_CANNOT_RETURN_NULL
346 static PackFile_ConstTable
*
347 pbc_merge_constants(PARROT_INTERP
, NOTNULL(pbc_merge_input
**inputs
),
348 int num_inputs
, NOTNULL(PackFile
*pf
), NOTNULL(PackFile_ByteCode
*bc
))
350 PackFile_Constant
**constants
= mem_allocate_typed(PackFile_Constant
*);
354 /* Add a constant table segment. */
355 PackFile_ConstTable
* const const_seg
= (PackFile_ConstTable
*)PackFile_Segment_new_seg(
356 interp
, &pf
->directory
, PF_CONST_SEG
, CONSTANT_SEGMENT_NAME
, 1);
357 if (const_seg
== NULL
) {
359 "PBC Merge: Error creating constant table segment.");
360 Parrot_exit(interp
, 1);
363 /* Loop over input files. */
364 for (i
= 0; i
< num_inputs
; i
++) {
365 /* Get the constant table segment from the input file. */
366 PackFile_ConstTable
* const in_seg
= inputs
[i
]->pf
->cur_cs
->const_table
;
367 if (in_seg
== NULL
) {
369 "PBC Merge: Cannot locate constant table segment in %s\n",
370 inputs
[i
]->filename
);
371 Parrot_exit(interp
, 1);
374 /* Store cursor as position where constant table starts. */
375 inputs
[i
]->const_start
= cursor
;
377 /* Allocate space for the constant list, provided we have some. */
378 if (in_seg
->const_count
> 0) {
379 constants
= (PackFile_Constant
**)mem_sys_realloc(constants
,
380 (cursor
+ in_seg
->const_count
) * sizeof (Parrot_Pointer
));
381 if (constants
== NULL
) {
382 PIO_eprintf(interp
, "PBC Merge: Out of memory");
383 Parrot_exit(interp
, 1);
387 /* Loop over the constants and copy them to the output PBC. */
388 for (j
= 0; j
< in_seg
->const_count
; j
++) {
389 /* Get the entry and allocate space for copy. */
390 PackFile_Constant
*cur_entry
= in_seg
->constants
[j
];
391 PackFile_Constant
*copy
= mem_allocate_typed(
394 PIO_eprintf(interp
, "PBC Merge: Out of memory");
395 Parrot_exit(interp
, 1);
398 STRUCT_COPY(copy
, cur_entry
);
400 /* If it's a sub PMC, need to deal with offsets. */
401 if (copy
->type
== PFC_PMC
) {
402 switch (copy
->u
.key
->vtable
->base_type
) {
404 case enum_class_Closure
:
405 case enum_class_Coroutine
:
407 Parrot_sub
* const sub
= PMC_sub(copy
->u
.key
);
408 sub
->start_offs
+= inputs
[i
]->code_start
;
409 sub
->end_offs
+= inputs
[i
]->code_start
;
415 /* Slot it into the list. */
416 constants
[cursor
] = copy
;
421 /* Stash merged constants table and count and return the new segment. */
422 const_seg
->constants
= constants
;
423 const_seg
->const_count
= cursor
;
424 const_seg
->code
= bc
;
425 bc
->const_table
= const_seg
;
432 FUNCDOC: pbc_merge_fixups
434 This function merges the fixups tables from the input PBC files.
438 pbc_merge_fixups(PARROT_INTERP
, NOTNULL(pbc_merge_input
**inputs
),
439 int num_inputs
, NOTNULL(PackFile
*pf
), NOTNULL(PackFile_ByteCode
*bc
))
441 PackFile_FixupTable
*fixup_seg
;
442 PackFile_FixupEntry
**fixups
= mem_allocate_typed(PackFile_FixupEntry
*);
446 /* Add a fixup table segment. */
447 fixup_seg
= (PackFile_FixupTable
*)PackFile_Segment_new_seg(
448 interp
, &pf
->directory
, PF_FIXUP_SEG
, FIXUP_TABLE_SEGMENT_NAME
, 1);
449 if (fixup_seg
== NULL
) {
451 "PBC Merge: Error creating fixup table segment.");
452 Parrot_exit(interp
, 1);
455 /* Loop over input files. */
456 for (i
= 0; i
< num_inputs
; i
++) {
457 /* Get the fixup segment from the input file. */
458 PackFile_FixupTable
* const in_seg
= inputs
[i
]->pf
->cur_cs
->fixups
;
459 if (in_seg
== NULL
) {
461 "PBC Merge: Cannot locate fixup segment in %s",
462 inputs
[i
]->filename
);
463 Parrot_exit(interp
, 1);
466 /* Allocate space for these fixups, provided we have some. */
467 if (in_seg
->fixup_count
> 0) {
468 fixups
= (PackFile_FixupEntry
**)mem_sys_realloc(fixups
,
469 (cursor
+ in_seg
->fixup_count
) * sizeof (Parrot_Pointer
));
470 if (fixups
== NULL
) {
471 PIO_eprintf(interp
, "PBC Merge: Out of memory");
472 Parrot_exit(interp
, 1);
476 /* Loop over the fixups and copy them to the output PBC, correcting
477 the offsets into the bytecode. */
478 for (j
= 0; j
< in_seg
->fixup_count
; j
++) {
479 /* Get the entry and allocate space for copies. */
480 PackFile_FixupEntry
*cur_entry
= in_seg
->fixups
[j
];
481 PackFile_FixupEntry
*copy
= mem_allocate_typed(
482 PackFile_FixupEntry
);
483 char *name_copy
= (char *)mem_sys_allocate(
484 strlen(cur_entry
->name
) + 1);
485 if (copy
== NULL
|| name_copy
== NULL
) {
486 PIO_eprintf(interp
, "PBC Merge: Out of memory");
487 Parrot_exit(interp
, 1);
490 /* Copy type and name. */
491 copy
->type
= cur_entry
->type
;
492 strcpy(name_copy
, cur_entry
->name
);
493 copy
->name
= name_copy
;
495 /* Set new offset and bytecode pointer. */
496 switch (copy
->type
) {
497 case enum_fixup_label
:
498 copy
->offset
= cur_entry
->offset
+ inputs
[i
]->code_start
;
501 copy
->offset
= cur_entry
->offset
+ inputs
[i
]->const_start
;
504 PIO_eprintf(interp
, "PBC Merge: Unknown fixup type");
505 Parrot_exit(interp
, 1);
510 /* Slot it into the list. */
511 fixups
[cursor
] = copy
;
516 /* Stash merged fixup table and count. */
517 fixup_seg
->fixups
= fixups
;
518 fixup_seg
->fixup_count
= cursor
;
524 FUNCDOC: pbc_merge_debugs
526 This function merges the debug segments from the input PBC files.
530 pbc_merge_debugs(PARROT_INTERP
, NOTNULL(pbc_merge_input
**inputs
),
531 int num_inputs
, NOTNULL(PackFile
*pf
), NOTNULL(PackFile_ByteCode
*bc
))
533 PackFile_Debug
*debug_seg
;
534 opcode_t
*lines
= mem_allocate_typed(opcode_t
);
535 PackFile_DebugMapping
**mappings
=
536 mem_allocate_typed(PackFile_DebugMapping
*);
537 opcode_t num_mappings
= 0;
538 opcode_t num_lines
= 0;
541 /* We need to merge both the mappings and the list of line numbers.
542 The line numbers can just be concatenated. The mappings must have
543 their offsets fixed up. */
544 for (i
= 0; i
< num_inputs
; i
++) {
545 PackFile_Debug
*in_seg
= inputs
[i
]->pf
->cur_cs
->debugs
;
547 /* Concatenate line numbers. */
548 lines
= (opcode_t
*)mem_sys_realloc(lines
,
549 (num_lines
+ in_seg
->base
.size
) * sizeof (opcode_t
));
551 PIO_eprintf(interp
, "PBC Merge: Cannot reallocate memory\n");
552 Parrot_exit(interp
, 1);
554 memcpy(lines
+ num_lines
, in_seg
->base
.data
,
555 in_seg
->base
.size
* sizeof (opcode_t
));
557 /* Concatenate mappings. */
558 mappings
= (PackFile_DebugMapping
**)mem_sys_realloc(mappings
,
559 (num_mappings
+ in_seg
->num_mappings
) *
560 sizeof (Parrot_Pointer
));
561 for (j
= 0; j
< in_seg
->num_mappings
; j
++) {
562 PackFile_DebugMapping
*mapping
= mem_allocate_typed(
563 PackFile_DebugMapping
);
564 STRUCT_COPY(mapping
, in_seg
->mappings
[j
]);
565 mapping
->offset
+= num_lines
;
566 if (mapping
->mapping_type
== PF_DEBUGMAPPINGTYPE_FILENAME
)
567 mapping
->u
.filename
+= inputs
[i
]->const_start
;
568 mappings
[num_mappings
+ j
] = mapping
;
572 num_lines
+= in_seg
->base
.size
;
573 num_mappings
+= in_seg
->num_mappings
;
576 /* Create merged debug segment. Replace created data and mappings
577 with merged ones we have created. */
578 debug_seg
= Parrot_new_debug_seg(interp
, bc
, num_lines
);
579 PackFile_add_segment(interp
, &pf
->directory
, (PackFile_Segment
*)debug_seg
);
580 free(debug_seg
->base
.data
);
581 debug_seg
->base
.data
= lines
;
582 free(debug_seg
->mappings
);
584 debug_seg
->mappings
= mappings
;
585 debug_seg
->num_mappings
= num_mappings
;
590 FUNCDOC: pbc_merge_pic_index
592 This function merges the pic_index segments from the input PBC files.
597 pbc_merge_pic_index(PARROT_INTERP
, NOTNULL(pbc_merge_input
**inputs
),
598 int num_inputs
, NOTNULL(PackFile
*pf
), NOTNULL(PackFile_ByteCode
*bc
))
601 PackFile_Segment
*pic_index
;
607 /* calc needed size */
608 for (i
= 0, size
= 0; i
< num_inputs
; i
++) {
609 PackFile_Segment
* const in_seg
= inputs
[i
]->pf
->cur_cs
->pic_index
;
610 size
+= in_seg
->size
;
612 pic_index
= PackFile_Segment_new_seg(interp
,
613 &pf
->directory
, PF_UNKNOWN_SEG
, "PIC_idx_MERGED", 1);
615 = (opcode_t
*)mem_sys_allocate_zeroed(size
* sizeof (opcode_t
));
616 pic_index
->size
= size
;
618 for (i
= 0, size
= 0; i
< num_inputs
; i
++) {
619 PackFile_Segment
* const in_seg
= inputs
[i
]->pf
->cur_cs
->pic_index
;
622 * pic_index is 0 or an ever increasing (by 1) number
624 for (j
= 0; j
< in_seg
->size
; j
++) {
625 const opcode_t k
= in_seg
->data
[j
];
627 pic_index
->data
[cursor
] = k
+ start
;
634 bc
->pic_index
= pic_index
;
639 FUNCDOC: pbc_merge_ctpointers
641 This function corrects the pointers into the constants table found in the
646 pbc_merge_ctpointers(PARROT_INTERP
, NOTNULL(pbc_merge_input
**inputs
),
647 int num_inputs
, NOTNULL(PackFile_ByteCode
*bc
))
650 opcode_t
*ops
= bc
->base
.data
;
655 /* Loop over the ops in the merged bytecode. */
656 while (cur_op
< (opcode_t
)bc
->base
.size
) {
660 /* Keep track of the current input file. */
661 if (cur_input
+ 1 < num_inputs
&&
662 cur_op
>= inputs
[cur_input
+ 1]->code_start
)
665 /* Get info about this op and jump over it. */
666 op_num
= ops
[cur_op
];
667 op
= &interp
->op_info_table
[op_num
];
668 op_ptr
= ops
+ cur_op
;
671 /* Loop over the arguments. */
672 for (cur_arg
= 1; cur_arg
< op
->op_count
; cur_arg
++) {
673 /* Pick out any indexes into the constant table and correct them. */
674 switch (op
->types
[cur_arg
- 1]) {
679 ops
[cur_op
] += inputs
[cur_input
]->const_start
;
683 /* Move along the bytecode array. */
687 /* Handle special case variable argument opcodes. */
688 if (op_num
== PARROT_OP_set_args_pc
||
689 op_num
== PARROT_OP_get_results_pc
||
690 op_num
== PARROT_OP_get_params_pc
||
691 op_num
== PARROT_OP_set_returns_pc
) {
692 /* Get the signature. */
693 const PMC
* const sig
= bc
->const_table
->constants
[op_ptr
[1]]->u
.key
;
695 /* Loop over the arguments to locate any that need a fixup. */
696 const int sig_items
= SIG_ELEMS(sig
);
697 for (cur_arg
= 0; cur_arg
< sig_items
; cur_arg
++) {
698 switch (SIG_ITEM(sig
, cur_arg
)) {
703 ops
[cur_op
] += inputs
[cur_input
]->const_start
;
715 FUNCDOC: pbc_merge_begin
717 This is the function that drives PBC merging process.
720 PARROT_WARN_UNUSED_RESULT
721 PARROT_CANNOT_RETURN_NULL
723 pbc_merge_begin(PARROT_INTERP
, NOTNULL(pbc_merge_input
**inputs
), int num_inputs
)
725 PackFile_ByteCode
*bc
;
727 /* Create a new empty packfile. */
728 PackFile
* const merged
= PackFile_new(interp
, 0);
729 if (merged
== NULL
) {
730 PIO_eprintf(interp
, "PBC Merge: Error creating new packfile.\n");
731 Parrot_exit(interp
, 1);
734 /* Merge the various stuff. */
735 bc
= pbc_merge_bytecode(interp
, inputs
, num_inputs
, merged
);
736 pbc_merge_constants(interp
, inputs
, num_inputs
, merged
, bc
);
738 pbc_merge_fixups(interp
, inputs
, num_inputs
, merged
, bc
);
739 pbc_merge_debugs(interp
, inputs
, num_inputs
, merged
, bc
);
740 pbc_merge_pic_index(interp
, inputs
, num_inputs
, merged
, bc
);
742 /* Walk bytecode and fix ops that reference the constants table. */
743 pbc_merge_ctpointers(interp
, inputs
, num_inputs
, bc
);
745 /* Return merged result. */
752 FUNCDOC: pbc_merge_write
754 This functions writes out the merged packfile.
758 pbc_merge_write(PARROT_INTERP
, NOTNULL(PackFile
*pf
), NOTNULL(const char *filename
))
762 /* Get size of packfile we'll write. */
763 const size_t size
= PackFile_pack_size(interp
, pf
) * sizeof (opcode_t
);
765 /* Allocate memory. */
766 opcode_t
* const pack
= (opcode_t
*) mem_sys_allocate(size
);
768 PIO_eprintf(interp
, "PBC Merge: Out of memory");
769 Parrot_exit(interp
, 1);
772 /* Write and clean up. */
773 PackFile_pack(interp
, pf
, pack
);
774 if ((fp
= fopen(filename
, "wb")) == 0) {
775 PIO_eprintf(interp
, "PBC Merge: Couldn't open %s\n", filename
);
776 Parrot_exit(interp
, 1);
778 if ((1 != fwrite(pack
, size
, 1, fp
))) {
779 PIO_eprintf(interp
, "PBC Merge: Couldn't write %s\n", filename
);
780 Parrot_exit(interp
, 1);
789 FUNCDOC: main(int argc, char **argv)
791 The main function that grabs console input, reads in the packfiles
792 provided they exist, hands them to another function that runs the
793 merge process and finally writes out the produced packfile.
797 static struct longopt_opt_decl options
[] = {
798 { 'o', 'o', OPTION_required_FLAG
, { "--output" } }
802 main(int argc
, char **argv
)
805 pbc_merge_input
** input_files
;
808 const char *output_file
= NULL
;
809 struct longopt_opt_info opt
= LONGOPT_OPT_INFO_INIT
;
810 Interp
* const interp
= Parrot_new(NULL
);
812 Parrot_block_DOD(interp
);
814 /* Get options, ensuring we have at least one input
815 file and an output file. */
819 while ((status
= longopt_get(interp
, argc
, argv
, options
, &opt
)) > 0) {
820 switch (opt
.opt_id
) {
822 if (output_file
== NULL
)
823 output_file
= opt
.opt_arg
;
832 if (status
== -1 || !output_file
) {
835 argc
-= opt
.opt_index
; /* Now the number of input files. */
836 argv
+= opt
.opt_index
; /* Now at first input filename. */
838 /* Load each packfile that we are to merge and set up an input
839 structure for each of them. */
840 input_files
= (pbc_merge_input
**)mem_sys_allocate(
841 argc
* sizeof (Parrot_Pointer
));
843 for (i
= 0; i
< argc
; i
++) {
844 /* Allocate a struct. */
845 input_files
[i
] = mem_allocate_typed(pbc_merge_input
);
848 input_files
[i
]->filename
= *argv
;
850 /* Load the packfile and unpack it. */
851 input_files
[i
]->pf
= pbc_merge_loadpbc(interp
,
852 input_files
[i
]->filename
);
853 if (input_files
[i
]->pf
== NULL
) {
855 "PBC Merge: Unknown error while reading and unpacking %s\n",
857 Parrot_exit(interp
, 1);
865 merged
= pbc_merge_begin(interp
, input_files
, argc
);
866 if (merged
== NULL
) {
867 PIO_eprintf(interp
, "PBC Merge: Unknown error during merge\n");
868 Parrot_exit(interp
, 1);
871 /* Write merged packfile. */
872 pbc_merge_write(interp
, merged
, output_file
);
874 /* Finally, we're done. */
875 Parrot_exit(interp
, 0);
882 * c-file-style: "parrot"
884 * vim: expandtab shiftwidth=4: