Return non-zero if an error occurs.
[AROS.git] / tools / sfdc / main.pl
blob7eecc089b90425800141dbd92328855da34f913c
1 #!/usr/bin/perl -w
3 # sfdc - Compile SFD files into someting useful
4 # Copyright (C) 2003-2004 Martin Blom <martin@blom.org>
5 #
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 use strict;
22 use IO::Handle;
23 use Getopt::Long;
25 # The default AmigaOS GG installation of does not seem to include
26 # Pod::Usage, so we have to provide a fallback. Ugly, but it works and
27 # that's what counts.
29 eval {
30 require Pod::Usage;
31 import Pod::Usage;
34 if ($@) {
35 eval '
36 # Minimal fall-back ...
38 sub pod2usage {
39 my @params = @_;
41 my $verbose = 0;
42 my $exitval = 0;
43 my $message = "";
44 my $output = \*STDERR;
46 while (@params) {
47 for (shift @params) {
48 /^-verbose$/ && do { $verbose = shift @params};
49 /^-exitval$/ && do { $exitval = shift @params};
50 /^-message$/ && do { $message = shift @params};
51 /^-output$/ && do { $output = shift @params};
55 print $output "$message\n" if $message;
56 print $output "\n";
57 print $output "Perl module Pod::Usage is missing.\n";
58 print $output "Please refer to the sfdc documentation for usage, ".
59 "or install Pod::Usage.\n";
60 exit $exitval;
65 sub parse_sfd ( $ );
66 sub parse_proto ( $$$ );
67 sub open_output ( $$ );
68 sub will_close_output ( $$ );
69 sub close_output ();
71 my @lf =
73 'struct Library* LibInit(struct Library* library,' .
74 ' BPTR seglist,' .
75 ' struct ExecBase* SysBase)' .
76 ' (d0,a0,a6)',
77 'struct Library* LibOpen(ULONG version) (d0)',
78 'BPTR LibClose() ()',
79 'BPTR LibExpunge() ()',
80 'ULONG LibNull() ()'
83 my @df =
85 'struct Library* DevInit(struct Library* library,' .
86 ' BPTR seglist,' .
87 ' struct ExecBase* SysBase)' .
88 ' (d0,a0,a6)',
89 'ULONG DevOpen(struct IORequest* ioreq,' .
90 ' ULONG unit,' .
91 ' ULONG flags) (a1,d0,d1)',
92 'BPTR DevClose(struct IORequest* ioreq) (a1)',
93 'BPTR DevExpunge() ()',
94 'ULONG DevNull() ()',
95 'VOID DevBeginIO(struct IORequest* ioreq) (a1)',
96 'ULONG DevAbortIO(struct IORequest* ioreq) (a1)'
99 my @bf =
101 'struct ClassLibrary* ClassInit(struct ClassLibrary* library,' .
102 ' BPTR seglist,' .
103 ' struct ExecBase* SysBase)' .
104 ' (d0,a0,a6)',
105 'struct ClassLibrary* ClassOpen(ULONG version) (d0)',
106 'BPTR ClassClose() ()',
107 'BPTR ClassExpunge() ()',
108 'ULONG ClassNull() ()',
109 'Class* ObtainEngine() ()',
112 my %targets = (
113 'generic' =>
114 { target => 'generic',
115 vectors => { 'library' => @lf, 'device' => @df, 'boopsi' => @bf },
116 macros => 'Macro',
117 stubs => 'Stub',
118 gatestubs => 'Gate',
121 '(\w)+(-.*)?-aros' =>
122 { target => 'aros',
123 vectors => { 'library' => @lf, 'device' => @df, 'boopsi' => @bf },
124 macros => 'MacroAROS',
125 stubs => 'StubAROS',
126 gatestubs => 'GateAROS',
127 sdistubs => 'SDIAROS'
130 'i.86be(-pc)?-amithlon' =>
131 { target => 'amithlon',
132 vectors => { 'library' => @lf, 'device' => @df, 'boopsi' => @bf },
133 macros => 'MacroLP',
134 stubs => 'StubAmithlon',
135 gatestubs => 'GateAmithlon'
138 'm68k(-unknown)?-amigaos' =>
139 { target => 'amigaos',
140 vectors => { 'library' => @lf, 'device' => @df, 'boopsi' => @bf },
141 macros => 'Macro68k',
142 stubs => 'Stub68k',
143 gatestubs => 'Gate68k'
146 'p(ower)?pc(-unknown)?-amigaos' =>
147 { target => 'amigaos4',
148 vectors => { 'library' => @lf, 'device' => @df, 'boopsi' => @bf },
149 macros => 'MacroAOS4',
150 stubs => 'StubAOS4',
151 gatestubs => 'GateAOS4'
154 'p(ower)?pc(-unknown)?-morphos' =>
155 { target => 'morphos',
156 vectors => { 'library' => @lf, 'device' => @df, 'boopsi' => @bf },
157 macros => 'MacroMOS',
158 stubs => 'StubMOS',
159 gatestubs => 'GateMOS'
163 my $classes;
165 ###############################################################################
166 ### Main program ##############################################################
167 ###############################################################################
169 Getopt::Long::Configure ("bundling");
171 my $gateprefix = '';
172 my $help = '0';
173 my $libarg = 'none';
174 my $libprefix = '';
175 my $addvectors = 'none';
176 my $man = '0';
177 my $mode = 'verify';
178 my $output = '-';
179 my $quiet = '0';
180 my $target = 'm68k-unknown-amigaos';
181 my $version = '0';
183 GetOptions ('addvectors=s' => \$addvectors,
184 'gateprefix=s' => \$gateprefix,
185 'help|h' => \$help,
186 'libarg=s' => \$libarg,
187 'libprefix=s' => \$libprefix,
188 'man' => \$man,
189 'mode=s' => \$mode,
190 'output|o=s' => \$output,
191 'quiet|q' => \$quiet,
192 'target=s' => \$target,
193 'version|v' => \$version) or exit 10;
195 if ($version) {
196 print STDERR "sfdc SFDC_VERSION (SFDC_DATE)\n";
197 print STDERR "Copyright (C) 2003-2004 Martin Blom <martin\@blom.org>\n";
198 print STDERR "This is free software; " .
199 "see the source for copying conditions.\n";
200 exit 0;
203 if ($help) {
204 pod2usage (-verbose => 1,
205 -exitval => 0,
206 -output => \*STDOUT);
209 if ($man) {
210 pod2usage (-verbose => 3,
211 -exitval => 0);
212 exit 0;
215 if ($#ARGV < 0) {
216 pod2usage (-message => "No SFD file specified.",
217 -verbose => 0,
218 -exitval => 10);
221 $mode = lc $mode;
223 if (!($mode =~ /^(clib|dump|fd|libproto|lvo|functable|macros|proto|pragmas|stubs|gateproto|gatestubs|sdiproto|sdistubs|verify)$/)) {
224 pod2usage (-message => "Unknown mode specified. Use --help for a list.",
225 -verbose => 0,
226 -exitval => 10);
229 if ($libarg !~ /^(first|last|none)$/) {
230 pod2usage (-message => "Unknown libarg specified. Use --help for a list.",
231 -verbose => 0,
232 -exitval => 10);
235 if ($addvectors !~ /^(none|library|device|boopsi)$/) {
236 pod2usage (-message => "Unknown addvectors value. Use --help for a list.",
237 -verbose => 0,
238 -exitval => 10);
241 check_target: {
242 foreach my $target_regex (keys %targets) {
243 if ($target =~ /^$target_regex$/) {
244 $classes = $targets{$target_regex};
245 last check_target;
249 pod2usage (-message => "Unknown target specified. Use --help for a list.",
250 -verbose => 0,
251 -exitval => 10);
254 # Save old STDOUT
256 open( OLDOUT, ">&STDOUT" );
258 for my $i ( 0 .. $#ARGV ) {
259 my $sfd = parse_sfd ($ARGV[$i]);
260 my $num = $#{$$sfd{'prototypes'}};
262 my $obj;
264 for ($mode) {
265 /^clib$/ && do {
266 $obj = CLib->new( sfd => $sfd );
267 last;
270 /^fd$/ && do {
271 $obj = FD->new( sfd => $sfd );
272 last;
275 /^dump$/ && do {
276 $obj = Dump->new( sfd => $sfd );
277 last;
280 /^libproto$/ && do {
281 $obj = Gate->new( sfd => $sfd,
282 proto => 0,
283 libproto => 1 );
284 last;
287 /^lvo$/ && do {
288 $obj = LVO->new( sfd => $sfd );
289 last;
292 /^functable$/ && do {
293 $obj = FuncTable->new( sfd => $sfd );
294 last;
297 /^macros$/ && do {
298 $obj = $$classes{'macros'}->new( sfd => $sfd );
300 # By tradition, the functions in the macro files are sorted
301 # @{$$sfd{'prototypes'}} = sort {
302 # $$a{'funcname'} cmp $$b{'funcname'}
303 # } @{$$sfd{'prototypes'}};
304 last;
307 /^proto$/ && do {
308 $obj = Proto->new( sfd => $sfd );
309 last;
312 /^pragmas$/ && do {
313 $obj = SASPragmas->new( sfd => $sfd );
314 last;
317 /^verify$/ && do {
318 $obj = Verify->new( sfd => $sfd );
319 last;
322 /^stubs$/ && do {
323 $obj = $$classes{'stubs'}->new( sfd => $sfd );
325 # By tradition, the functions in the stub files are sorted
326 # @{$$sfd{'prototypes'}} = sort {
327 # $$a{'funcname'} cmp $$b{'funcname'}
328 # } @{$$sfd{'prototypes'}};
329 last;
332 /^gateproto$/ && do {
333 $obj = $$classes{'gatestubs'}->new( sfd => $sfd,
334 proto => 1,
335 libproto => 0);
336 last;
339 /^gatestubs$/ && do {
340 $obj = $$classes{'gatestubs'}->new( sfd => $sfd,
341 proto => 0,
342 libproto => 0);
344 last;
347 /^sdiproto$/ && do {
348 $obj = $$classes{'sdistubs'}->new( sfd => $sfd,
349 proto => 1);
351 last;
354 /^sdistubs$/ && do {
355 $obj = $$classes{'sdistubs'}->new( sfd => $sfd,
356 proto => 0 );
358 last;
361 die "Unknown mode specified: " . $mode;
365 for my $j ( 0 .. $num + 1) {
366 my $prototype = $$sfd{'prototypes'}[$j];
367 my $funcname = $$prototype{'funcname'};
369 if (!defined ($funcname) || will_close_output ($sfd, $funcname) != 0) {
370 $obj->footer ();
373 if ($j > $num) {
374 last;
377 if (open_output ($sfd, $funcname) != 0) {
378 $obj->header ();
381 $obj->function (prototype => $prototype);
384 close_output ();
387 if (!$quiet) {
388 print STDERR "All done.\n";
391 open (STDOUT, ">&OLDOUT");
392 close (OLDOUT);
394 exit 0;
401 ###############################################################################
402 ### Subroutines ###############################################################
403 ###############################################################################
406 ### parse_sfd: Parse an SFD file hand return a hash record #####################
408 sub parse_sfd ( $ ) {
409 my $file = shift;
410 local *SFD;
412 my $type = 'function';
413 my $last_type = $type;
414 my $private = 0;
415 my $bias = 0;
416 my $version = 1;
417 my $comment = '';
419 my $result = {
420 copyright => 'Copyright © 2001 Amiga, Inc.',
421 id => '',
422 libname => '',
423 base => '',
424 basetype => 'struct Library *',
425 # includes => (),
426 # typedefs => (),
427 # prototypes => (),
428 basename => '',
429 BASENAME => '',
430 Basename => ''
433 # Why do I need this????
434 $$result{'prototypes'} = ();
435 $$result{'includes'} = ();
436 $$result{'typedefs'} = ();
438 if ($addvectors ne 'none') {
439 push @{$$result{'includes'}}, '<dos/dos.h>';
440 push @{$$result{'includes'}}, '<exec/execbase.h>';
442 if ($addvectors eq 'device') {
443 push @{$$result{'includes'}}, '<exec/io.h>';
445 elsif ($addvectors eq 'boopsi') {
446 push @{$$result{'includes'}}, '<intuition/classes.h>';
449 for my $i ( 0 .. $#{$classes->{vectors}->{$addvectors}} ) {
450 push @{$$result{'prototypes'}}, {
451 type => 'function',
452 subtype => $addvectors,
453 value => $classes->{vectors}->{$addvectors}[$i],
454 line => 0,
455 private => 0,
456 bias => 6 * $i,
457 version => 0,
458 comment => ''
464 my $proto_line = '';
465 my %proto;
467 if (!$quiet) {
468 ( my $fn = $file ) =~ s,.*[/\\](.*),$1,;
469 print STDERR "Processing SFD file '$fn'.\n";
470 STDERR->flush();
473 unless (open (SFD, "<" . $file)) {
474 print STDERR "Unable to open file '$file'.\n";
475 die;
478 my $line_no = 0;
480 LINE:
481 while (my $line = <SFD>) {
483 ++$line_no;
485 for ($line) {
486 /^==copyright\s/ && do {
487 ( $$result{'copyright'} = $_ ) =~ s/==copyright\s+(.*)\s*/$1/;
488 last;
491 /^==id\s+/ && do {
492 ( $$result{'id'} = $_ ) =~ s/==id\s+(.*)\s*/$1/;
493 last;
496 /^==libname\s+/ && do {
497 ( $$result{'libname'} = $_ ) =~ s/==libname\s+(.*)\s*/$1/;
498 last;
501 /^==base\s+/ && do {
502 ( $$result{'base'} = $_ ) =~ s/==base\s+_?(.*)\s*/$1/;
503 last;
506 /^==basetype\s+/ && do {
507 ( $$result{'basetype'} = $_ ) =~ s/==basetype\s+(.*)\s*/$1/;
508 last;
511 /^==include\s+/ && do {
512 ( my $inc = $_ ) =~ s/==include\s+(.*)\s*/$1/;
514 push @{$$result{'includes'}}, $inc;
515 last;
518 /^==typedef\s+/ && do {
519 ( my $td = $_ ) =~ s/==typedef\s+(.*)\s*$/$1/;
521 push @{$$result{'typedefs'}}, $td;
522 last;
525 /^==bias\s+/ && do {
526 ( $bias = $_ ) =~ s/==bias\s+(.*)\s*/$1/;
527 last;
530 /^==reserve\s+/ && do {
531 ( my $reserve = $_ ) =~ s/==reserve\s+(.*)\s*/$1/;
533 $bias += 6 * $reserve;
534 last;
537 /^==alias\s*$/ && do {
538 # Move back again
539 $type = $last_type;
540 $bias -= 6;
541 last;
544 /^==varargs\s*$/ && do {
545 $type = 'varargs';
546 # Move back again
547 $bias -= 6;
548 last;
551 /^==private\s*$/ && do {
552 $private = 1;
553 last;
556 /^==public\s*$/ && do {
557 $private = 0;
558 last;
561 /^==version\s+/ && do {
562 ( $version = $_ ) =~ s/==version\s+(.*)\s*/$1/;
563 last;
566 /^==end\s*$/ && do {
567 last LINE;
570 /^\*/ && do {
571 ( my $cmt = $_ ) =~ s/^\*(.*)\s*/$1/;
573 $comment .= ($comment eq '' ? "" : "\n" ) . $cmt;
574 last;
577 /^[^=*\n]/ && do {
578 # Strip whitespaces and append
579 $line =~ s/\s*(.*)\s*/$1/;
580 $proto_line .= $line . " ";
581 last;
584 /^\s*$/ && do {
585 # Skip blank lines
586 last;
589 # If we get here, we found a line we don't understand
590 print STDERR "Unable to parse line $line_no in SFD file" .
591 " '$file'. The line looks like this:\n" . $line ;
592 die;
595 if ( $proto_line =~
596 /.*[A-Za-z0-9_]+\s*\(.*\).*\(((base|sysv|autoreg|[\saAdD][0-7]-?),?)*\)\s*$/
599 if ($proto_line =~ /.*\(.*[0-7]-.*\)\s*$/) {
600 if ($$classes{'target'} ne 'amigaos') {
601 print STDERR "Warning: Multiregister functions are m68k only.\n";
603 $proto_line =~ s/([da][0-7])-[da][0-7]/$1/g;
605 # else {
606 push @{$$result{'prototypes'}}, {
607 type => $type,
608 subtype => '',
609 value => $proto_line,
610 line => $line_no,
611 private => $private,
612 bias => $bias,
613 version => $version,
614 comment => $comment
617 $comment = '';
620 $last_type = $type;
621 $type = 'function';
622 $proto_line = '';
623 $bias += 6;
627 if( $proto_line ne '' ) {
628 # If $proto_line isn't empty, we couldn't parse it
629 die "Unhanled proto '" . $proto_line . "'\n";
632 close (SFD);
634 # Now parse the prototypes
635 my $real_funcname = '';
636 my $real_prototype = {};
637 my $varargs_type = '';
639 for my $i ( 0 .. $#{$$result{'prototypes'}} ) {
640 my $prototype = $$result{'prototypes'}[$i];
642 if ($$prototype{'type'} eq 'varargs') {
643 $$prototype{'real_funcname'} = $real_funcname;
644 $$prototype{'real_prototype'} = $real_prototype;
646 else {
647 $$prototype{'real_funcname'} = '';
648 $$prototype{'real_prototype'} = '';
651 parse_proto ($result, $prototype, $varargs_type);
653 if ($$prototype{'type'} eq 'function') {
654 $varargs_type = $$prototype{'argtypes'}[$#{$$prototype{'argtypes'}}];
657 if ($$prototype{'type'} eq 'function') {
658 $real_funcname = $$prototype{'funcname'};
659 $real_prototype = $prototype;
663 # Create some other variables
665 ( $$result{'basename'} = $file ) =~ s:.*/(\w+?)_lib\.sfd:$1:;
667 if ($$result{'basename'} eq '') {
668 ( $$result{'basename'} = $$result{'libname'} ) =~ s/(.*)\.\w+/$1/ or do {
669 print STDERR "Unable to find or guess base name.\n";
670 print STDERR "Please add \"==libname module_name\" to SFD file.\n";
671 die;
674 # Fake the CIA libname
675 if ($$result{'basename'} eq "cia") {
676 $$result{'libname'} = "ciaX.resource";
678 else {
679 $$result{'libname'} = $$result{'basename'} . ".library";
683 # Fake the Workbench basename
684 if ($$result{'basename'} eq "workbench") {
685 $$result{'basename'} = "wb";
688 $$result{'basename'} =~ s/-/_/g;
689 $$result{'basename'} =~ s/\//_/g;
690 $$result{'basename'} =~ s/\./_/g;
691 $$result{'basename'} = lc $$result{'basename'};
692 $$result{'BASENAME'} = uc $$result{'basename'};
693 $$result{'Basename'} = ucfirst $$result{'basename'};
694 ($result->{BaseName} = $result->{base}) =~ s/Base//;
696 return $result;
700 ### parse_proto: Parse a single function prototype ###########################
702 sub parse_proto ( $$$ ) {
703 my $sfd = shift;
704 my $prototype = shift;
705 my $varargs_type = shift;
707 my $return;
708 my $name;
709 my $arguments;
710 my $registers;
712 if (!(($return,undef,undef,$name,$arguments,$registers) =
713 ( $$prototype{'value'} =~
714 /^((struct\s+)?(\w+\s*?)+\**)\s*(\w+)\s*\((.*)\)\s*\((.*)\).*/ ))) {
715 print STDERR "Unable to parse prototype on line $$prototype{'line'}.\n";
716 die;
719 # Nuke whitespaces from the register specification
720 $registers =~ s/\s//;
722 $$prototype{'return'} = $return;
723 $$prototype{'funcname'} = $name;
725 $$prototype{'numargs'} = 0;
726 $$prototype{'numregs'} = 0;
728 @{$$prototype{'regs'}} = ();
729 @{$$prototype{'args'}} = ();
730 @{$$prototype{'___args'}} = ();
731 @{$$prototype{'argnames'}} = ();
732 @{$$prototype{'___argnames'}} = ();
733 @{$$prototype{'argtypes'}} = ();
735 if ($arguments =~ /^(void|VOID)$/) {
736 $arguments = "";
739 my @args = split(/,/,$arguments);
741 # Fix function pointer arguments and build $$prototype{'args'}
743 my $par_cnt = 0;
744 foreach my $arg (@args) {
745 # Strip whitespaces
746 $arg =~ s/\s*(.*?)\s*/$1/;
748 if ($par_cnt != 0) {
749 my $old_arg = pop @{$$prototype{'args'}};
751 push @{$$prototype{'args'}}, $old_arg . "," . $arg;
753 else {
754 push @{$$prototype{'args'}}, $arg;
757 # Count parentheses (a function pointer arguments is processed
758 # when $par_cnt is 0).
759 $par_cnt += ( $arg =~ tr/\(/\(/ );
760 $par_cnt -= ( $arg =~ tr/\)/\)/ );
763 $$prototype{'numargs'} = $#{$$prototype{'args'}} + 1;
765 if ($registers =~ /sysv/) {
766 $prototype->{type} = 'cfunction';
767 $prototype->{nb} = 1;
769 elsif ($registers =~ /autoreg/) {
770 my $a_cnt = 0;
771 my $d_cnt = 0;
772 foreach my $arg (@{$$prototype{'args'}}) {
773 if ($arg =~ /\*/) {
774 push @{$$prototype{'regs'}}, "a$a_cnt";
775 $a_cnt++;
777 else {
778 push @{$$prototype{'regs'}}, "d$d_cnt";
779 $d_cnt++;
783 $prototype->{numregs} = $#{$$prototype{'regs'}} + 1;
784 $prototype->{nb} = $sfd->{base} eq '';
786 else {
787 # Split regs and make them lower case
788 @{$$prototype{'regs'}} = split(/,/,lc $registers);
789 $prototype->{numregs} = $#{$$prototype{'regs'}} + 1;
790 $prototype->{nb} = $sfd->{base} eq '' || $registers =~ /a6/;
793 $$prototype{'nr'} = $$prototype{'return'} =~ /^(VOID|void)$/;
795 # varargs sub types:
796 # printfcall: LONG Printf( STRPTR format, ... );
797 # All varargs are optional
798 # tagcall: BOOL AslRequestTags( APTR requester, Tag Tag1, ... );
799 # First vararg is a Tag, then a TAG_DONE terminated tag list
800 # methodcall: ULONG DoGadgetMethod( ... ULONG message, ...);
801 # First vararg is required.
803 if ($prototype->{type} eq 'varargs') {
804 if ($varargs_type =~
805 /^\s*(const|CONST)?\s*struct\s+TagItem\s*\*\s*$/ ) {
806 $prototype->{subtype} = 'tagcall';
808 if ($prototype->{numargs} == $prototype->{numregs}) {
809 if (!$quiet) {
810 print STDERR "Warning: Adding missing Tag argument to " .
811 $prototype->{funcname} . "()\n";
814 my $last = pop @{$prototype->{args}};
815 push @{$prototype->{args}}, "Tag _tag1" ;
816 push @{$prototype->{args}}, $last;
818 ++$prototype->{numargs};
821 else {
822 if ($prototype->{numargs} == $prototype->{numregs}) {
823 $prototype->{subtype} = 'printfcall';
825 elsif ($prototype->{numargs} == $prototype->{numregs} + 1) {
826 $prototype->{subtype} = 'methodcall';
830 elsif ($prototype->{type} eq 'cfunction') {
831 foreach (split(/,/,lc $registers)) {
832 /^sysv$/ && do {
833 $prototype->{subtype} = 'sysv';
834 next;
837 /^base$/ && do {
838 if ($sfd->{base} eq '') {
839 printf STDERR "$prototype->{funcname}: " .
840 "Library has no base!\n";
841 die;
844 $prototype->{nb} = 0;
845 next;
852 # Make sure we have the same number of arguments as registers, or,
853 # if this is a varargs function, possible one extra, á la "MethodID, ...".
854 # Tagcalls always have one extra, á la "Tag, ...".
856 if (($prototype->{type} eq 'varargs' &&
857 $prototype->{subtype} eq 'tagcall' &&
858 $prototype->{numargs} != $prototype->{numregs} + 1 ) ||
860 ($prototype->{type} eq 'varargs' &&
861 $prototype->{subtype} eq 'printfcall' &&
862 $prototype->{numargs} != $prototype->{numregs}) ||
864 ($prototype->{type} eq 'varargs' &&
865 $prototype->{subtype} eq 'methodcall' &&
866 $prototype->{numargs} != $prototype->{numregs} + 1) ||
868 ($prototype->{type} eq 'function' &&
869 $prototype->{numargs} != $prototype->{numregs})) {
871 print STDERR "Failed to parse arguments/registers on SFD " .
872 "line $$prototype{'line'}:\n$$prototype{'value'}\n";
873 print STDERR "The number of arguments doesn't match " .
874 "the number of registers (+1 if tagcall).\n";
875 die;
878 my $type = '';
880 foreach my $arg (@{$$prototype{'args'}}) {
881 my $name = '';
882 my $___name = '';
883 my $___arg = '';
885 # MorhOS includes use __CLIB_PROTOTYPE for some reason ...
886 if ($arg =~ /.*\(.*?\)\s*(__CLIB_PROTOTYPE)?\(.*\)/) {
887 my $type1;
888 my $type2;
890 ($type1, $name, $type2) =
891 ( $arg =~ /^\s*(.*)\(\s*\*\s*(\w+)\s*\)\s*(\w*\(.*\))\s*/ );
892 $type = "$type1(*)$type2";
893 $___name = "___$name";
894 $___arg = "$type1(*___$name) $type2";
896 elsif ($arg !~ /^\.\.\.$/) {
897 ($type, $name) = ( $arg =~ /^\s*(.*?[\s*]*?)\s*(\w+)\s*$/ );
898 $___name = "___$name";
899 $___arg = "$type ___$name";
901 else {
902 if ($prototype->{type} eq 'varargs') {
903 $type = $varargs_type;
905 else {
906 # Unknown type
907 # $type = "void*";
908 $type = "...";
910 $name = '...';
911 $___name = '...';
912 $___arg = '...';
915 if ($type eq '' || $name eq '' ) {
916 print STDERR "Type or name missing from '$arg'.\n";
917 die;
920 push @{$$prototype{'___args'}}, $___arg;
921 push @{$$prototype{'argnames'}}, $name;
922 push @{$$prototype{'___argnames'}}, $___name;
924 push @{$$prototype{'argtypes'}}, $type;
930 sub BEGIN {
931 my $old_output = '';
934 ### close_output: Close the output file if necessary #########################
936 sub close_output () {
937 close (STDOUT);
938 $old_output = '';
942 ### check_output: Check if the file will be reopended by open_output ##########
944 sub will_close_output ( $$ ) {
945 my $sfd = shift;
946 my $function = shift;
948 my $new_output = $output;
950 $new_output =~ s/%f/$function/;
951 $new_output =~ s/%b/$$sfd{'base'}/;
952 $new_output =~ s/%l/$$sfd{'libname'}/;
953 $new_output =~ s/%n/$$sfd{'basename'}/;
955 if( $old_output ne '' &&
956 $new_output ne $old_output ) {
957 return 1;
959 else {
960 return 0;
964 ### open_output: (Re)open the output file if necessary #######################
966 sub open_output ( $$ ) {
967 my $sfd = shift;
968 my $function = shift;
970 my $new_output = $output;
972 $new_output =~ s/%f/$function/;
973 $new_output =~ s/%b/$$sfd{'base'}/;
974 $new_output =~ s/%l/$$sfd{'libname'}/;
975 $new_output =~ s/%n/$$sfd{'basename'}/;
977 if( $new_output ne $old_output ) {
979 close_output ();
981 if ($new_output eq '-') {
982 open (STDOUT, ">&OLDOUT") or die;
984 else {
985 open (STDOUT, ">" . $new_output) or die;
987 if (!$quiet) {
988 print STDERR "Writing to '$new_output'\n";
992 $old_output = $new_output;
994 return 1;
996 else {
997 return 0;