This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Okay, here's your official unofficial closure leak patch
[perl5.git] / c2ph.SH
1 case $CONFIG in
2 '')
3     if test ! -f config.sh; then
4         ln ../config.sh . || \
5         ln ../../config.sh . || \
6         ln ../../../config.sh . || \
7         (echo "Can't find config.sh."; exit 1)
8     fi
9     . config.sh
10     ;;
11 esac
12 : This forces SH files to create target in same directory as SH file.
13 : This is so that make depend always knows where to find SH derivatives.
14 case "$0" in
15 */*) cd `expr X$0 : 'X\(.*\)/'` ;;
16 esac
17 echo "Extracting c2ph (with variable substitutions)"
18 : This section of the file will have variable substitutions done on it.
19 : Move anything that needs config subs from !NO!SUBS! section to !GROK!THIS!.
20 : Protect any dollar signs and backticks that you do not want interpreted
21 : by putting a backslash in front.  You may delete these comments.
22 rm -f c2ph
23 $spitshell >c2ph <<!GROK!THIS!
24 #!$bin/perl
25 #
26 !GROK!THIS!
27
28 : In the following dollars and backticks do not need the extra backslash.
29 $spitshell >>c2ph <<'!NO!SUBS!'
30 #
31 #   c2ph (aka pstruct)
32 #   Tom Christiansen, <tchrist@convex.com>
33 #   
34 #   As pstruct, dump C structures as generated from 'cc -g -S' stabs.
35 #   As c2ph, do this PLUS generate perl code for getting at the structures.
36 #
37 #   See the usage message for more.  If this isn't enough, read the code.
38 #
39
40 $RCSID = 'c2ph.SH';
41
42
43 ######################################################################
44
45 # some handy data definitions.   many of these can be reset later.
46
47 $bitorder = 'b';  # ascending; set to B for descending bit fields
48
49 %intrinsics = 
50 %template = (
51     'char',                     'c',
52     'unsigned char',            'C',
53     'short',                    's',
54     'short int',                's',
55     'unsigned short',           'S',
56     'unsigned short int',       'S',
57     'short unsigned int',       'S',
58     'int',                      'i',
59     'unsigned int',             'I',
60     'long',                     'l',
61     'long int',                 'l',
62     'unsigned long',            'L',
63     'unsigned long',            'L',
64     'long unsigned int',        'L',
65     'unsigned long int',        'L',
66     'long long',                'q',
67     'long long int',            'q',
68     'unsigned long long',       'Q',
69     'unsigned long long int',   'Q',
70     'float',                    'f',
71     'double',                   'd',
72     'pointer',                  'p',
73     'null',                     'x',
74     'neganull',                 'X',
75     'bit',                      $bitorder,
76 ); 
77
78 &buildscrunchlist;
79 delete $intrinsics{'neganull'};
80 delete $intrinsics{'bit'};
81 delete $intrinsics{'null'};
82
83 # use -s to recompute sizes
84 %sizeof = (
85     'char',                     '1',
86     'unsigned char',            '1',
87     'short',                    '2',
88     'short int',                '2',
89     'unsigned short',           '2',
90     'unsigned short int',       '2',
91     'short unsigned int',       '2',
92     'int',                      '4',
93     'unsigned int',             '4',
94     'long',                     '4',
95     'long int',                 '4',
96     'unsigned long',            '4',
97     'unsigned long int',        '4',
98     'long unsigned int',        '4',
99     'long long',                '8',
100     'long long int',            '8',
101     'unsigned long long',       '8',
102     'unsigned long long int',   '8',
103     'float',                    '4',
104     'double',                   '8',
105     'pointer',                  '4',
106 );
107
108 ($type_width, $member_width, $offset_width, $size_width) = (20, 20, 6, 5);
109
110 ($offset_fmt, $size_fmt) = ('d', 'd');
111
112 $indent = 2;
113
114 $CC = 'cc';
115 $CFLAGS = '-g -S';
116 $DEFINES = '';
117
118 $perl++ if $0 =~ m#/?c2ph$#;
119
120 require 'getopts.pl';
121
122 eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_]+=)(.*)/ && shift;
123
124 &Getopts('aixdpvtnws:') || &usage(0);
125
126 $opt_d && $debug++;
127 $opt_t && $trace++;
128 $opt_p && $perl++;
129 $opt_v && $verbose++;
130 $opt_n && ($perl = 0);
131
132 if ($opt_w) {
133     ($type_width, $member_width, $offset_width) = (45, 35, 8);
134
135 if ($opt_x) {
136     ($offset_fmt, $offset_width, $size_fmt, $size_width) = ( 'x', '08', 'x', 04 );
137 }
138
139 eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_]+=)(.*)/ && shift;
140
141 sub PLUMBER {
142     select(STDERR);
143     print "oops, apperent pager foulup\n";
144     $isatty++;
145     &usage(1);
146
147
148 sub usage {
149     local($oops) = @_;
150     unless (-t STDOUT) {
151         select(STDERR);
152     } elsif (!$oops) {
153         $isatty++;
154         $| = 1;
155         print "hit <RETURN> for further explanation: ";
156         <STDIN>;
157         open (PIPE, "|". ($ENV{PAGER} || 'more'));
158         $SIG{PIPE} = PLUMBER;
159         select(PIPE);
160     } 
161
162     print "usage: $0 [-dpnP] [var=val] [files ...]\n";
163
164     exit unless $isatty;
165
166     print <<EOF;
167
168 Options:
169
170 -w      wide; short for: type_width=45 member_width=35 offset_width=8
171 -x      hex; short for:  offset_fmt=x offset_width=08 size_fmt=x size_width=04
172
173 -n      do not generate perl code  (default when invoked as pstruct)
174 -p      generate perl code         (default when invoked as c2ph)
175 -v      generate perl code, with C decls as comments
176
177 -i      do NOT recompute sizes for intrinsic datatypes
178 -a      dump information on intrinsics also
179
180 -t      trace execution
181 -d      spew reams of debugging output
182
183 -slist  give comma-separated list a structures to dump
184
185
186 Var Name        Default Value    Meaning
187
188 EOF
189
190     &defvar('CC', 'which_compiler to call');
191     &defvar('CFLAGS', 'how to generate *.s files with stabs');
192     &defvar('DEFINES','any extra cflags or cpp defines, like -I, -D, -U');
193
194     print "\n";
195
196     &defvar('type_width', 'width of type field   (column 1)');
197     &defvar('member_width', 'width of member field (column 2)');
198     &defvar('offset_width', 'width of offset field (column 3)');
199     &defvar('size_width', 'width of size field   (column 4)');
200
201     print "\n";
202
203     &defvar('offset_fmt', 'sprintf format type for offset');
204     &defvar('size_fmt', 'sprintf format type for size');
205
206     print "\n";
207
208     &defvar('indent', 'how far to indent each nesting level');
209
210    print <<'EOF';
211
212     If any *.[ch] files are given, these will be catted together into
213     a temporary *.c file and sent through:
214             $CC $CFLAGS $DEFINES 
215     and the resulting *.s groped for stab information.  If no files are
216     supplied, then stdin is read directly with the assumption that it
217     contains stab information.  All other liens will be ignored.  At
218     most one *.s file should be supplied.
219
220 EOF
221     close PIPE;
222     exit 1;
223
224
225 sub defvar {
226     local($var, $msg) = @_;
227     printf "%-16s%-15s  %s\n", $var, eval "\$$var", $msg;
228
229
230 $recurse = 1;
231
232 if (@ARGV) {
233     if (grep(!/\.[csh]$/,@ARGV)) {
234         warn "Only *.[csh] files expected!\n";
235         &usage;
236     } 
237     elsif (grep(/\.s$/,@ARGV)) {
238         if (@ARGV > 1) { 
239             warn "Only one *.s file allowed!\n";
240             &usage;
241         }
242     } 
243     elsif (@ARGV == 1 && $ARGV[0] =~ /\.c$/) {
244         local($dir, $file) = $ARGV[0] =~ m#(.*/)?(.*)$#;
245         $chdir = "cd $dir; " if $dir;
246         &system("$chdir$CC $CFLAGS $DEFINES $file") && exit 1;
247         $ARGV[0] =~ s/\.c$/.s/;
248     } 
249     else {
250         $TMP = "/tmp/c2ph.$$.c";
251         &system("cat @ARGV > $TMP") && exit 1;
252         &system("cd /tmp; $CC $CFLAGS $DEFINES $TMP") && exit 1;
253         unlink $TMP;
254         $TMP =~ s/\.c$/.s/;
255         @ARGV = ($TMP);
256     } 
257 }
258
259 if ($opt_s) {
260     for (split(/[\s,]+/, $opt_s)) {
261         $interested{$_}++;
262     } 
263
264
265
266 $| = 1 if $debug;
267
268 main: {
269
270     if ($trace) {
271         if (-t && !@ARGV) { 
272             print STDERR "reading from your keyboard: ";
273         } else {
274             print STDERR "reading from " . (@ARGV ? "@ARGV" : "<STDIN>").": ";
275         }
276     }
277
278 STAB: while (<>) {
279         if ($trace && !($. % 10)) {
280             $lineno = $..'';
281             print STDERR $lineno, "\b" x length($lineno);
282         } 
283         next unless /^\s*\.stabs\s+/;
284         $line = $_;
285         s/^\s*\.stabs\s+//; 
286         &stab; 
287     }
288     print STDERR "$.\n" if $trace;
289     unlink $TMP if $TMP;
290
291     &compute_intrinsics if $perl && !$opt_i;
292
293     print STDERR "resolving types\n" if $trace;
294
295     &resolve_types;
296     &adjust_start_addrs;
297
298     $sum = 2 + $type_width + $member_width;
299     $pmask1 = "%-${type_width}s %-${member_width}s"; 
300     $pmask2 = "%-${sum}s %${offset_width}${offset_fmt}%s %${size_width}${size_fmt}%s";
301
302     if ($perl) {
303         # resolve template -- should be in stab define order, but even this isn't enough.
304         print STDERR "\nbuilding type templates: " if $trace;
305         for $i (reverse 0..$#type) {
306             next unless defined($name = $type[$i]);
307             next unless defined $struct{$name};
308             $build_recursed = 0;
309             &build_template($name) unless defined $template{&psou($name)} ||
310                                         $opt_s && !$interested{$name};
311         } 
312         print STDERR "\n\n" if $trace;
313     }
314
315     print STDERR "dumping structs: " if $trace;
316
317
318     foreach $name (sort keys %struct) {
319         next if $opt_s && !$interested{$name};
320         print STDERR "$name " if $trace;
321
322         undef @sizeof;
323         undef @typedef;
324         undef @offsetof;
325         undef @indices;
326         undef @typeof;
327
328         $mname = &munge($name);
329
330         $fname = &psou($name);
331
332         print "# " if $perl && $verbose;
333         $pcode = '';
334         print "$fname {\n" if !$perl || $verbose; 
335         $template{$fname} = &scrunch($template{$fname}) if $perl;
336         &pstruct($name,$name,0); 
337         print "# " if $perl && $verbose;
338         print "}\n" if !$perl || $verbose; 
339         print "\n" if $perl && $verbose;
340
341         if ($perl) {
342             print "$pcode";
343
344             printf("\nsub %-32s { %4d; }\n\n", "${mname}'struct", $countof{$name});
345
346             print <<EOF;
347 sub ${mname}'typedef { 
348     local(\$${mname}'index) = shift;
349     defined \$${mname}'index 
350         ? \$${mname}'typedef[\$${mname}'index] 
351         : \$${mname}'typedef;
352 }
353 EOF
354
355             print <<EOF;
356 sub ${mname}'sizeof { 
357     local(\$${mname}'index) = shift;
358     defined \$${mname}'index 
359         ? \$${mname}'sizeof[\$${mname}'index] 
360         : \$${mname}'sizeof;
361 }
362 EOF
363
364             print <<EOF;
365 sub ${mname}'offsetof { 
366     local(\$${mname}'index) = shift;
367     defined \$${mname}index 
368         ? \$${mname}'offsetof[\$${mname}'index] 
369         : \$${mname}'sizeof;
370 }
371 EOF
372
373             print <<EOF;
374 sub ${mname}'typeof { 
375     local(\$${mname}'index) = shift;
376     defined \$${mname}index 
377         ? \$${mname}'typeof[\$${mname}'index] 
378         : '$name';
379 }
380 EOF
381     
382
383             print "\$${mname}'typedef = '" . &scrunch($template{$fname}) 
384                 . "';\n";
385
386             print "\$${mname}'sizeof = $sizeof{$name};\n\n";
387
388
389             print "\@${mname}'indices = (", &squishseq(@indices), ");\n";
390
391             print "\n";
392
393             print "\@${mname}'typedef[\@${mname}'indices] = (",
394                         join("\n\t", '', @typedef), "\n    );\n\n";
395             print "\@${mname}'sizeof[\@${mname}'indices] = (",
396                         join("\n\t", '', @sizeof), "\n    );\n\n";
397             print "\@${mname}'offsetof[\@${mname}'indices] = (",
398                         join("\n\t", '', @offsetof), "\n    );\n\n";
399             print "\@${mname}'typeof[\@${mname}'indices] = (",
400                         join("\n\t", '', @typeof), "\n    );\n\n";
401
402             $template_printed{$fname}++;
403             $size_printed{$fname}++;
404         } 
405         print "\n";
406     }
407
408     print STDERR "\n" if $trace;
409
410     unless ($perl && $opt_a) { 
411         print "\n1;\n";
412         exit;
413     }
414
415
416
417     foreach $name (sort bysizevalue keys %intrinsics) {
418         next if $size_printed{$name};
419         print '$',&munge($name),"'sizeof = ", $sizeof{$name}, ";\n";
420     }
421
422     print "\n";
423
424     sub bysizevalue { $sizeof{$a} <=> $sizeof{$b}; }
425
426
427     foreach $name (sort keys %intrinsics) {
428         print '$',&munge($name),"'typedef = '", $template{$name}, "';\n";
429     }
430
431     print "\n1;\n";
432         
433     exit;
434 }
435
436 ########################################################################################
437
438
439 sub stab {
440     next unless /:[\$\w]+(\(\d+,\d+\))?=[\*\$\w]+/;  # (\d+,\d+) is for sun
441     s/"//                                               || next;
442     s/",([x\d]+),([x\d]+),([x\d]+),.*//                 || next;
443
444     next if /^\s*$/;
445
446     $size = $3 if $3;
447
448
449     $line = $_;
450
451     if (($name, $pdecl) = /^([\$ \w]+):[tT]((\d+)(=[rufs*](\d+))+)$/) {
452         print "$name is a typedef for some funky pointers: $pdecl\n" if $debug;
453         &pdecl($pdecl);
454         next;
455     }
456
457
458
459     if (/(([ \w]+):t(\d+|\(\d+,\d+\)))=r?(\d+|\(\d+,\d+\))(;\d+;\d+;)?/) {  
460         local($ident) = $2;
461         push(@intrinsics, $ident);
462         $typeno = &typeno($3);
463         $type[$typeno] = $ident;
464         print STDERR "intrinsic $ident in new type $typeno\n" if $debug; 
465         next;
466     }
467
468     if (($name, $typeordef, $typeno, $extra, $struct, $_) 
469         = /^([\$ \w]+):([ustT])(\d+|\(\d+,\d+\))(=[rufs*](\d+))?(.*)$/) 
470     {
471         $typeno = &typeno($typeno);  # sun foolery
472     } 
473     elsif (/^[\$\w]+:/) {
474         next; # variable
475     }
476     else { 
477         warn "can't grok stab: <$_> in: $line " if $_;
478         next;
479     } 
480
481     #warn "got size $size for $name\n";
482     $sizeof{$name} = $size if $size;
483
484     s/;[-\d]*;[-\d]*;$//;  # we don't care about ranges
485
486     $typenos{$name} = $typeno;
487
488     unless (defined $type[$typeno]) {
489         &panic("type 0??") unless $typeno;
490         $type[$typeno] = $name unless defined $type[$typeno];
491         printf "new type $typeno is $name" if $debug;
492         if ($extra =~ /\*/ && defined $type[$struct]) {
493             print ", a typedef for a pointer to " , $type[$struct] if $debug;
494         }
495     } else {
496         printf "%s is type %d", $name, $typeno if $debug;
497         print ", a typedef for " , $type[$typeno] if $debug;
498     } 
499     print "\n" if $debug;
500     #next unless $extra =~ /[su*]/;
501
502     #$type[$struct] = $name;
503
504     if ($extra =~ /[us*]/) {
505         &sou($name, $extra);
506         $_ = &sdecl($name, $_, 0);
507     }
508     elsif (/^=ar/) {
509         print "it's a bare array typedef -- that's pretty sick\n" if $debug;
510         $_ = "$typeno$_";
511         $scripts = '';
512         $_ = &adecl($_,1);
513
514     }
515     elsif (s/((\w+):t(\d+|\(\d+,\d+\)))?=r?(;\d+;\d+;)?//) {  # the ?'s are for gcc
516         push(@intrinsics, $2);
517         $typeno = &typeno($3);
518         $type[$typeno] = $2;
519         print STDERR "intrinsic $2 in new type $typeno\n" if $debug; 
520     }
521     elsif (s/^=e//) { # blessed by thy compiler; mine won't do this
522         &edecl;
523     } 
524     else {
525         warn "Funny remainder for $name on line $_ left in $line " if $_;
526     } 
527 }
528
529 sub typeno {  # sun thinks types are (0,27) instead of just 27
530     local($_) = @_;
531     s/\(\d+,(\d+)\)/$1/;
532     $_;
533
534
535 sub pstruct {
536     local($what,$prefix,$base) = @_; 
537     local($field, $fieldname, $typeno, $count, $offset, $entry); 
538     local($fieldtype);
539     local($type, $tname); 
540     local($mytype, $mycount, $entry2);
541     local($struct_count) = 0;
542     local($pad, $revpad, $length, $prepad, $lastoffset, $lastlength, $fmt);
543     local($bits,$bytes);
544     local($template);
545
546
547     local($mname) = &munge($name);
548
549     sub munge { 
550         local($_) = @_;
551         s/[\s\$\.]/_/g;
552         $_;
553     }
554
555     local($sname) = &psou($what);
556
557     $nesting++;
558
559     for $field (split(/;/, $struct{$what})) {
560         $pad = $prepad = 0;
561         $entry = ''; 
562         ($fieldname, $typeno, $count, $offset, $length) = split(/,/, $field); 
563
564         $type = $type[$typeno];
565
566         $type =~ /([^[]*)(\[.*\])?/;
567         $mytype = $1;
568         $count .= $2;
569         $fieldtype = &psou($mytype);
570
571         local($fname) = &psou($name);
572
573         if ($build_templates) {
574
575             $pad = ($offset - ($lastoffset + $lastlength))/8 
576                 if defined $lastoffset;
577
578             if (! $finished_template{$sname}) {
579                 if ($isaunion{$what}) {
580                     $template{$sname} .= 'X' x $revpad . ' '    if $revpad;
581                 } else {
582                     $template{$sname} .= 'x' x $pad    . ' '    if $pad;
583                 }
584             }
585
586             $template = &fetch_template($type) x 
587                             ($count ? &scripts2count($count) : 1);
588
589             if (! $finished_template{$sname}) {
590                 $template{$sname} .= $template;
591             }
592
593             $revpad = $length/8 if $isaunion{$what};
594
595             ($lastoffset, $lastlength) = ($offset, $length);
596
597         } else { 
598             print '# ' if $perl && $verbose;
599             $entry = sprintf($pmask1,
600                         ' ' x ($nesting * $indent) . $fieldtype,
601                         "$prefix.$fieldname" . $count); 
602
603             $entry =~ s/(\*+)( )/$2$1/; 
604
605             printf $pmask2,
606                     $entry,
607                     ($base+$offset)/8,
608                     ($bits = ($base+$offset)%8) ? ".$bits" : "  ",
609                     $length/8,
610                     ($bits = $length % 8) ? ".$bits": ""
611                         if !$perl || $verbose;
612
613
614             if ($perl && $nesting == 1) {
615                 $template = &scrunch(&fetch_template($type) x 
616                                 ($count ? &scripts2count($count) : 1));
617                 push(@sizeof, int($length/8) .",\t# $fieldname");
618                 push(@offsetof, int($offset/8) .",\t# $fieldname");
619                 push(@typedef, "'$template', \t# $fieldname");
620                 $type =~ s/(struct|union) //;
621                 push(@typeof, "'$type" . ($count ? $count : '') .
622                     "',\t# $fieldname");
623             }
624
625             print '  ', ' ' x $indent x $nesting, $template
626                                 if $perl && $verbose;
627
628             print "\n" if !$perl || $verbose;
629
630         }    
631         if ($perl) {
632             local($mycount) = defined $struct{$mytype} ? $countof{$mytype} : 1;
633             $mycount *= &scripts2count($count) if $count;
634             if ($nesting==1 && !$build_templates) {
635                 $pcode .= sprintf("sub %-32s { %4d; }\n", 
636                         "${mname}'${fieldname}", $struct_count);
637                 push(@indices, $struct_count);
638             }
639             $struct_count += $mycount;
640         } 
641
642
643         &pstruct($type, "$prefix.$fieldname", $base+$offset) 
644                 if $recurse && defined $struct{$type}; 
645     }
646
647     $countof{$what} = $struct_count unless defined $countof{$whati};
648
649     $template{$sname} .= '$' if $build_templates;
650     $finished_template{$sname}++;
651
652     if ($build_templates && !defined $sizeof{$name}) {
653         local($fmt) = &scrunch($template{$sname});
654         print STDERR "no size for $name, punting with $fmt..." if $debug;
655         eval '$sizeof{$name} = length(pack($fmt, ()))';
656         if ($@) {
657             chop $@;
658             warn "couldn't get size for \$name: $@";
659         } else {
660             print STDERR $sizeof{$name}, "\n" if $debUg;
661         }
662     } 
663
664     --$nesting;
665 }
666
667
668 sub psize {
669     local($me) = @_; 
670     local($amstruct) = $struct{$me} ?  'struct ' : '';
671
672     print '$sizeof{\'', $amstruct, $me, '\'} = '; 
673     printf "%d;\n", $sizeof{$me}; 
674 }
675
676 sub pdecl {
677     local($pdecl) = @_;
678     local(@pdecls);
679     local($tname);
680
681     warn "pdecl: $pdecl\n" if $debug;
682
683     $pdecl =~ s/\(\d+,(\d+)\)/$1/g;
684     $pdecl =~ s/\*//g; 
685     @pdecls = split(/=/, $pdecl); 
686     $typeno = $pdecls[0];
687     $tname = pop @pdecls;
688
689     if ($tname =~ s/^f//) { $tname = "$tname&"; } 
690     #else { $tname = "$tname*"; } 
691
692     for (reverse @pdecls) {
693         $tname  .= s/^f// ? "&" : "*"; 
694         #$tname =~ s/^f(.*)/$1&/;
695         print "type[$_] is $tname\n" if $debug;
696         $type[$_] = $tname unless defined $type[$_];
697     } 
698 }
699
700
701
702 sub adecl {
703     ($arraytype, $unknown, $lower, $upper) = ();
704     #local($typeno);
705     # global $typeno, @type
706     local($_, $typedef) = @_;
707
708     while (s/^((\d+)=)?ar(\d+);//) {
709         ($arraytype, $unknown) = ($2, $3); 
710         if (s/^(\d+);(\d+);//) {
711             ($lower, $upper) = ($1, $2); 
712             $scripts .= '[' .  ($upper+1) . ']'; 
713         } else {
714             warn "can't find array bounds: $_"; 
715         } 
716     }
717     if (s/^([\d*f=]*),(\d+),(\d+);//) {
718         ($start, $length) = ($2, $3); 
719         local($whatis) = $1;
720         if ($whatis =~ /^(\d+)=/) {
721             $typeno = $1;
722             &pdecl($whatis);
723         } else {
724             $typeno = $whatis;
725         }
726     } elsif (s/^(\d+)(=[*suf]\d*)//) {
727         local($whatis) = $2; 
728
729         if ($whatis =~ /[f*]/) {
730             &pdecl($whatis); 
731         } elsif ($whatis =~ /[su]/) {  # 
732             print "$prefix.$fieldname is an array$scripts anon structs; disgusting\n" 
733                 if $debug;
734             #$type[$typeno] = $name unless defined $type[$typeno];
735             ##printf "new type $typeno is $name" if $debug;
736             $typeno = $1;
737             $type[$typeno] = "$prefix.$fieldname";
738             local($name) = $type[$typeno];
739             &sou($name, $whatis);
740             $_ = &sdecl($name, $_, $start+$offset);
741             1;
742             $start = $start{$name};
743             $offset = $sizeof{$name};
744             $length = $offset;
745         } else {
746             warn "what's this? $whatis in $line ";
747         } 
748     } elsif (/^\d+$/) {
749         $typeno = $_;
750     } else {
751         warn "bad array stab: $_ in $line ";
752         next STAB;
753     } 
754     #local($wasdef) = defined($type[$typeno]) && $debug;
755     #if ($typedef) { 
756         #print "redefining $type[$typeno] to " if $wasdef;
757         #$type[$typeno] = "$whatis$scripts"; # unless defined $type[$typeno];
758         #print "$type[$typeno]\n" if $wasdef;
759     #} else {
760         #$type[$arraytype] = $type[$typeno] unless defined $type[$arraytype];
761     #}
762     $type[$arraytype] = "$type[$typeno]$scripts" if defined $type[$typeno];
763     print "type[$arraytype] is $type[$arraytype]\n" if $debug;
764     print "$prefix.$fieldname is an array of $type[$arraytype]\n" if $debug;
765     $_;
766 }
767
768
769
770 sub sdecl {
771     local($prefix, $_, $offset) = @_;
772
773     local($fieldname, $scripts, $type, $arraytype, $unknown,
774     $whatis, $pdecl, $upper,$lower, $start,$length) = ();
775     local($typeno,$sou);
776
777
778 SFIELD:
779     while (/^([^;]+);/) {
780         $scripts = '';
781         warn "sdecl $_\n" if $debug;
782         if (s/^([\$\w]+)://) { 
783             $fieldname = $1;
784         } elsif (s/(\d+)=([us])(\d+|\(\d+,\d+\))//) { # 
785             $typeno = &typeno($1);
786             $type[$typeno] = "$prefix.$fieldname";
787             local($name) = "$prefix.$fieldname";
788             &sou($name,$2);
789             $_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
790             $start = $start{$name};
791             $offset += $sizeof{$name};
792             #print "done with anon, start is $start, offset is $offset\n";
793             #next SFIELD;
794         } else  {
795             warn "weird field $_ of $line" if $debug;
796             next STAB;
797             #$fieldname = &gensym;
798             #$_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
799         }
800
801         if (/^\d+=ar/) {
802             $_ = &adecl($_);
803         }
804         elsif (s/^(\d+|\(\d+,\d+\))?,(\d+),(\d+);//) {
805             ($start, $length) =  ($2, $3); 
806             &panic("no length?") unless $length;
807             $typeno = &typeno($1) if $1;
808         }
809         elsif (s/^((\d+|\(\d+,\d+\))(=[*f](\d+|\(\d+,\d+\)))+),(\d+),(\d+);//) {
810             ($pdecl, $start, $length) =  ($1,$5,$6); 
811             &pdecl($pdecl); 
812         }
813         elsif (s/(\d+)=([us])(\d+|\(\d+,\d+\))//) { # the dratted anon struct
814             ($typeno, $sou) = ($1, $2);
815             $typeno = &typeno($typeno);
816             if (defined($type[$typeno])) {
817                 warn "now how did we get type $1 in $fieldname of $line?";
818             } else {
819                 print "anon type $typeno is $prefix.$fieldname\n" if $debug;
820                 $type[$typeno] = "$prefix.$fieldname" unless defined $type[$typeno];
821             };
822             local($name) = "$prefix.$fieldname";
823             &sou($name,$sou);
824             print "anon ".($isastruct{$name}) ? "struct":"union"." for $prefix.$fieldname\n" if $debug;
825             $type[$typeno] = "$prefix.$fieldname";
826             $_ = &sdecl("$prefix.$fieldname", $_, $start+$offset); 
827             $start = $start{$name};
828             $length = $sizeof{$name};
829         }
830         else {
831             warn "can't grok stab for $name ($_) in line $line "; 
832             next STAB; 
833         }
834
835         &panic("no length for $prefix.$fieldname") unless $length;
836         $struct{$name} .= join(',', $fieldname, $typeno, $scripts, $start, $length) . ';';
837     }
838     if (s/;\d*,(\d+),(\d+);//) {
839         local($start, $size) = ($1, $2); 
840         $sizeof{$prefix} = $size;
841         print "start of $prefix is $start, size of $sizeof{$prefix}\n" if $debug; 
842         $start{$prefix} = $start; 
843     } 
844     $_;
845 }
846
847 sub edecl {
848     s/;$//;
849     $enum{$name} = $_;
850     $_ = '';
851
852
853 sub resolve_types {
854     local($sou);
855     for $i (0 .. $#type) {
856         next unless defined $type[$i];
857         $_ = $type[$i];
858         unless (/\d/) {
859             print "type[$i] $type[$i]\n" if $debug;
860             next;
861         }
862         print "type[$i] $_ ==> " if $debug;
863         s/^(\d+)(\**)\&\*(\**)/"$2($3".&type($1) . ')()'/e;
864         s/^(\d+)\&/&type($1)/e; 
865         s/^(\d+)/&type($1)/e; 
866         s/(\*+)([^*]+)(\*+)/$1$3$2/;
867         s/\((\*+)(\w+)(\*+)\)/$3($1$2)/;
868         s/^(\d+)([\*\[].*)/&type($1).$2/e;
869         #s/(\d+)(\*|(\[[\[\]\d\*]+]\])+)/&type($1).$2/ge;
870         $type[$i] = $_;
871         print "$_\n" if $debug;
872     }
873 }
874 sub type { &psou($type[$_[0]] || "<UNDEFINED>"); } 
875
876 sub adjust_start_addrs {
877     for (sort keys %start) {
878         ($basename = $_) =~ s/\.[^.]+$//;
879         $start{$_} += $start{$basename};
880         print "start: $_ @ $start{$_}\n" if $debug;
881     }
882 }
883
884 sub sou {
885     local($what, $_) = @_;
886     /u/ && $isaunion{$what}++;
887     /s/ && $isastruct{$what}++;
888 }
889
890 sub psou {
891     local($what) = @_;
892     local($prefix) = '';
893     if ($isaunion{$what})  {
894         $prefix = 'union ';
895     } elsif ($isastruct{$what})  {
896         $prefix = 'struct ';
897     }
898     $prefix . $what;
899 }
900
901 sub scrunch {
902     local($_) = @_;
903
904     study;
905
906     s/\$//g;
907     s/  / /g;
908     1 while s/(\w) \1/$1$1/g;
909
910     # i wanna say this, but perl resists my efforts:
911     #      s/(\w)(\1+)/$2 . length($1)/ge;
912
913     &quick_scrunch;
914
915     s/ $//;
916
917     $_;
918 }
919
920 sub buildscrunchlist {
921     $scrunch_code = "sub quick_scrunch {\n";
922     for (values %intrinsics) {
923         $scrunch_code .= "\ts/($_{2,})/'$_' . length(\$1)/ge;\n";
924     } 
925     $scrunch_code .= "}\n";
926     print "$scrunch_code" if $debug;
927     eval $scrunch_code;
928     &panic("can't eval scrunch_code $@ \nscrunch_code") if $@;
929
930
931 sub fetch_template {
932     local($mytype) = @_;
933     local($fmt);
934     local($count) = 1;
935
936     &panic("why do you care?") unless $perl;
937
938     if ($mytype =~ s/(\[\d+\])+$//) {
939         $count .= $1;
940     } 
941
942     if ($mytype =~ /\*/) {
943         $fmt = $template{'pointer'};
944     } 
945     elsif (defined $template{$mytype}) {
946         $fmt = $template{$mytype};
947     } 
948     elsif (defined $struct{$mytype}) {
949         if (!defined $template{&psou($mytype)}) {
950             &build_template($mytype) unless $mytype eq $name;
951         } 
952         elsif ($template{&psou($mytype)} !~ /\$$/) {
953             #warn "incomplete template for $mytype\n";
954         } 
955         $fmt = $template{&psou($mytype)} || '?';
956     } 
957     else {
958         warn "unknown fmt for $mytype\n";
959         $fmt = '?';
960     } 
961
962     $fmt x $count . ' ';
963 }
964
965 sub compute_intrinsics {
966     local($TMP) = "/tmp/c2ph-i.$$.c";
967     open (TMP, ">$TMP") || die "can't open $TMP: $!";
968     select(TMP);
969
970     print STDERR "computing intrinsic sizes: " if $trace;
971
972     undef %intrinsics;
973
974     print <<'EOF';
975 main() {
976     char *mask = "%d %s\n";
977 EOF
978
979     for $type (@intrinsics) {
980         next if $type eq 'void';
981         print <<"EOF";
982     printf(mask,sizeof($type), "$type");
983 EOF
984     } 
985
986     print <<'EOF';
987     printf(mask,sizeof(char *), "pointer");
988     exit(0);
989 }
990 EOF
991     close TMP;
992
993     select(STDOUT);
994     open(PIPE, "cd /tmp && $CC $TMP && /tmp/a.out|");
995     while (<PIPE>) {
996         chop;
997         split(' ',$_,2);;
998         print "intrinsic $_[1] is size $_[0]\n" if $debug;
999         $sizeof{$_[1]} = $_[0];
1000         $intrinsics{$_[1]} = $template{$_[0]};
1001     } 
1002     close(PIPE) || die "couldn't read intrinsics!";
1003     unlink($TMP, '/tmp/a.out');
1004     print STDERR "done\n" if $trace;
1005
1006
1007 sub scripts2count {
1008     local($_) = @_;
1009
1010     s/^\[//;
1011     s/\]$//;
1012     s/\]\[/*/g;
1013     $_ = eval;
1014     &panic("$_: $@") if $@;
1015     $_;
1016 }
1017
1018 sub system {
1019     print STDERR "@_\n" if $trace;
1020     system @_;
1021
1022
1023 sub build_template { 
1024     local($name) = @_;
1025
1026     &panic("already got a template for $name") if defined $template{$name};
1027
1028     local($build_templates) = 1;
1029
1030     local($lparen) = '(' x $build_recursed;
1031     local($rparen) = ')' x $build_recursed;
1032
1033     print STDERR "$lparen$name$rparen " if $trace;
1034     $build_recursed++;
1035     &pstruct($name,$name,0);
1036     print STDERR "TEMPLATE for $name is ", $template{&psou($name)}, "\n" if $debug;
1037     --$build_recursed;
1038 }
1039
1040
1041 sub panic {
1042
1043     select(STDERR);
1044
1045     print "\npanic: @_\n";
1046
1047     exit 1 if $] <= 4.003;  # caller broken
1048
1049     local($i,$_);
1050     local($p,$f,$l,$s,$h,$a,@a,@sub);
1051     for ($i = 0; ($p,$f,$l,$s,$h,$w) = caller($i); $i++) {
1052         @a = @DB'args;
1053         for (@a) {
1054             if (/^StB\000/ && length($_) == length($_main{'_main'})) {
1055                 $_ = sprintf("%s",$_);
1056             }
1057             else {
1058                 s/'/\\'/g;
1059                 s/([^\0]*)/'$1'/ unless /^-?[\d.]+$/;
1060                 s/([\200-\377])/sprintf("M-%c",ord($1)&0177)/eg;
1061                 s/([\0-\37\177])/sprintf("^%c",ord($1)^64)/eg;
1062             }
1063         }
1064         $w = $w ? '@ = ' : '$ = ';
1065         $a = $h ? '(' . join(', ', @a) . ')' : '';
1066         push(@sub, "$w&$s$a from file $f line $l\n");
1067         last if $signal;
1068     }
1069     for ($i=0; $i <= $#sub; $i++) {
1070         last if $signal;
1071         print $sub[$i];
1072     }
1073     exit 1;
1074
1075
1076 sub squishseq {
1077     local($num);
1078     local($last) = -1e8;
1079     local($string);
1080     local($seq) = '..';
1081
1082     while (defined($num = shift)) {
1083         if ($num == ($last + 1)) {
1084             $string .= $seq unless $inseq++;
1085             $last = $num;
1086             next;
1087         } elsif ($inseq) {
1088             $string .= $last unless $last == -1e8;
1089         }
1090
1091         $string .= ',' if defined $string;
1092         $string .= $num;
1093         $last = $num;
1094         $inseq = 0;
1095     }
1096     $string .= $last if $inseq && $last != -e18;
1097     $string;
1098 }
1099 !NO!SUBS!
1100 $eunicefix c2ph
1101 rm -f pstruct
1102 ln c2ph pstruct