[inseparable changes from patch from perl5.003_11 to perl5.003_12]
[p5sagit/p5-mst-13.2.git] / utils / h2ph.PL
1 #!/usr/local/bin/perl
2
3 use Config;
4 use File::Basename qw(&basename &dirname);
5
6 # List explicitly here the variables you want Configure to
7 # generate.  Metaconfig only looks for shell variables, so you
8 # have to mention them as if they were shell variables, not
9 # %Config entries.  Thus you write
10 #  $startperl
11 # to ensure Configure will look for $Config{startperl}.
12 # Wanted:  $archlibexp
13
14 # This forces PL files to create target in same directory as PL file.
15 # This is so that make depend always knows where to find PL derivatives.
16 chdir(dirname($0));
17 ($file = basename($0)) =~ s/\.PL$//;
18 $file =~ s/\.pl$//
19         if ($^O eq 'VMS' or $^O eq 'os2');  # "case-forgiving"
20
21 open OUT,">$file" or die "Can't create $file: $!";
22
23 print "Extracting $file (with variable substitutions)\n";
24
25 # In this section, perl variables will be expanded during extraction.
26 # You can use $Config{...} to use Configure variables.
27
28 print OUT <<"!GROK!THIS!";
29 $Config{startperl}
30     eval 'exec $Config{perlpath} -S \$0 \${1+"\$@"}'
31         if \$running_under_some_shell;
32 !GROK!THIS!
33
34 # In the following, perl variables are not expanded during extraction.
35
36 print OUT <<'!NO!SUBS!';
37
38 use Config;
39 $perlincl = @Config{installsitearch};
40
41 chdir '/usr/include' || die "Can't cd /usr/include";
42
43 @isatype = split(' ',<<END);
44         char    uchar   u_char
45         short   ushort  u_short
46         int     uint    u_int
47         long    ulong   u_long
48         FILE
49 END
50
51 @isatype{@isatype} = (1) x @isatype;
52 $inif = 0;
53
54 @ARGV = ('-') unless @ARGV;
55
56 foreach $file (@ARGV) {
57     # Recover from header files with unbalanced cpp directives
58     $t = '';
59     $tab = 0;
60
61     if ($file eq '-') {
62         open(IN, "-");
63         open(OUT, ">-");
64     }
65     else {
66         ($outfile = $file) =~ s/\.h$/.ph/ || next;
67         print "$file -> $outfile\n";
68         if ($file =~ m|^(.*)/|) {
69             $dir = $1;
70             if (!-d "$perlincl/$dir") {
71                 mkdir("$perlincl/$dir",0777);
72             }
73         }
74         open(IN,"$file") || ((warn "Can't open $file: $!\n"),next);
75         open(OUT,">$perlincl/$outfile") || die "Can't create $outfile: $!\n";
76     }
77     while (<IN>) {
78         chop;
79         while (/\\$/) {
80             chop;
81             $_ .= <IN>;
82             chop;
83         }
84         if (s:/\*:\200:g) {
85             s:\*/:\201:g;
86             s/\200[^\201]*\201//g;      # delete single line comments
87             if (s/\200.*//) {           # begin multi-line comment?
88                 $_ .= '/*';
89                 $_ .= <IN>;
90                 redo;
91             }
92         }
93         if (s/^#\s*//) {
94             if (s/^define\s+(\w+)//) {
95                 $name = $1;
96                 $new = '';
97                 s/\s+$//;
98                 if (s/^\(([\w,\s]*)\)//) {
99                     $args = $1;
100                     if ($args ne '') {
101                         foreach $arg (split(/,\s*/,$args)) {
102                             $arg =~ s/^\s*([^\s].*[^\s])\s*$/$1/;
103                             $curargs{$arg} = 1;
104                         }
105                         $args =~ s/\b(\w)/\$$1/g;
106                         $args = "local($args) = \@_;\n$t    ";
107                     }
108                     s/^\s+//;
109                     expr();
110                     $new =~ s/(["\\])/\\$1/g;
111                     if ($t ne '') {
112                         $new =~ s/(['\\])/\\$1/g;
113                         print OUT $t,
114                           "eval 'sub $name {\n$t    ${args}eval \"$new\";\n$t}';\n";
115                     }
116                     else {
117                         print OUT "sub $name {\n    ${args}eval \"$new\";\n}\n";
118                     }
119                     %curargs = ();
120                 }
121                 else {
122                     s/^\s+//;
123                     expr();
124                     $new = 1 if $new eq '';
125                     if ($t ne '') {
126                         $new =~ s/(['\\])/\\$1/g;
127                         print OUT $t,"eval 'sub $name {",$new,";}';\n";
128                     }
129                     else {
130                         print OUT $t,"sub $name {",$new,";}\n";
131                     }
132                 }
133             }
134             elsif (/^include\s*<(.*)>/) {
135                 ($incl = $1) =~ s/\.h$/.ph/;
136                 print OUT $t,"require '$incl';\n";
137             }
138             elsif (/^ifdef\s+(\w+)/) {
139                 print OUT $t,"if (defined &$1) {\n";
140                 $tab += 4;
141                 $t = "\t" x ($tab / 8) . ' ' x ($tab % 8);
142             }
143             elsif (/^ifndef\s+(\w+)/) {
144                 print OUT $t,"if (!defined &$1) {\n";
145                 $tab += 4;
146                 $t = "\t" x ($tab / 8) . ' ' x ($tab % 8);
147             }
148             elsif (s/^if\s+//) {
149                 $new = '';
150                 $inif = 1;
151                 expr();
152                 $inif = 0;
153                 print OUT $t,"if ($new) {\n";
154                 $tab += 4;
155                 $t = "\t" x ($tab / 8) . ' ' x ($tab % 8);
156             }
157             elsif (s/^elif\s+//) {
158                 $new = '';
159                 $inif = 1;
160                 expr();
161                 $inif = 0;
162                 $tab -= 4;
163                 $t = "\t" x ($tab / 8) . ' ' x ($tab % 8);
164                 print OUT $t,"}\n${t}elsif ($new) {\n";
165                 $tab += 4;
166                 $t = "\t" x ($tab / 8) . ' ' x ($tab % 8);
167             }
168             elsif (/^else/) {
169                 $tab -= 4;
170                 $t = "\t" x ($tab / 8) . ' ' x ($tab % 8);
171                 print OUT $t,"}\n${t}else {\n";
172                 $tab += 4;
173                 $t = "\t" x ($tab / 8) . ' ' x ($tab % 8);
174             }
175             elsif (/^endif/) {
176                 $tab -= 4;
177                 $t = "\t" x ($tab / 8) . ' ' x ($tab % 8);
178                 print OUT $t,"}\n";
179             }
180         }
181     }
182     print OUT "1;\n";
183 }
184
185 sub expr {
186     while ($_ ne '') {
187         s/^(\s+)//              && do {$new .= ' '; next;};
188         s/^(0x[0-9a-fA-F]+)//   && do {$new .= $1; next;};
189         s/^(\d+)[LlUu]*//       && do {$new .= $1; next;};
190         s/^("(\\"|[^"])*")//    && do {$new .= $1; next;};
191         s/^'((\\"|[^"])*)'//    && do {
192             if ($curargs{$1}) {
193                 $new .= "ord('\$$1')";
194             }
195             else {
196                 $new .= "ord('$1')";
197             }
198             next;
199         };
200         # replace "sizeof(foo)" with "{foo}"
201         # also, remove * (C dereference operator) to avoid perl syntax
202         # problems.  Where the %sizeof array comes from is anyone's
203         # guess (c2ph?), but this at least avoids fatal syntax errors.
204         # Behavior is undefined if sizeof() delimiters are unbalanced.
205         # This code was modified to able to handle constructs like this:
206         #   sizeof(*(p)), which appear in the HP-UX 10.01 header files.
207         s/^sizeof\s*\(// && do {
208             $new .= '$sizeof';
209             my $lvl = 1;  # already saw one open paren
210             # tack { on the front, and skip it in the loop
211             $_ = "{" . "$_";
212             my $index = 1;
213             # find balanced closing paren
214             while ($index <= length($_) && $lvl > 0) {
215                 $lvl++ if substr($_, $index, 1) eq "(";
216                 $lvl-- if substr($_, $index, 1) eq ")";
217                 $index++;
218             }
219             # tack } on the end, replacing )
220             substr($_, $index - 1, 1) = "}";
221             # remove pesky * operators within the sizeof argument
222             substr($_, 0, $index - 1) =~ s/\*//g;
223             next;
224         };
225         s/^([_a-zA-Z]\w*)//     && do {
226             $id = $1;
227             if ($id eq 'struct') {
228                 s/^\s+(\w+)//;
229                 $id .= ' ' . $1;
230                 $isatype{$id} = 1;
231             }
232             elsif ($id eq 'unsigned') {
233                 s/^\s+(\w+)//;
234                 $id .= ' ' . $1;
235                 $isatype{$id} = 1;
236             }
237             if ($curargs{$id}) {
238                 $new .= '$' . $id;
239             }
240             elsif ($id eq 'defined') {
241                 $new .= 'defined';
242             }
243             elsif (/^\(/) {
244                 s/^\((\w),/("$1",/ if $id =~ /^_IO[WR]*$/i;     # cheat
245                 $new .= " &$id";
246             }
247             elsif ($isatype{$id}) {
248                 if ($new =~ /{\s*$/) {
249                     $new .= "'$id'";
250                 }
251                 elsif ($new =~ /\(\s*$/ && /^[\s*]*\)/) {
252                     $new =~ s/\(\s*$//;
253                     s/^[\s*]*\)//;
254                 }
255                 else {
256                     $new .= q(').$id.q(');
257                 }
258             }
259             else {
260                 if ($inif && $new !~ /defined\s*\($/) {
261                     $new .= '(defined(&' . $id . ') ? &' . $id . ' : 0)';
262                 } 
263                 elsif (/^\[/) { 
264                     $new .= ' $' . $id;
265                 }
266                 else {
267                     $new .= ' &' . $id;
268                 }
269             }
270             next;
271         };
272         s/^(.)// && do { if ($1 ne '#') { $new .= $1; } next;};
273     }
274 }
275 ##############################################################################
276 __END__
277
278 =head1 NAME
279
280 h2ph - convert .h C header files to .ph Perl header files
281
282 =head1 SYNOPSIS
283
284 B<h2ph [headerfiles]>
285
286 =head1 DESCRIPTION
287
288 I<h2ph>
289 converts any C header files specified to the corresponding Perl header file
290 format.
291 It is most easily run while in /usr/include:
292
293         cd /usr/include; h2ph * sys/*
294
295 If run with no arguments, filters standard input to standard output.
296
297 =head1 ENVIRONMENT
298
299 No environment variables are used.
300
301 =head1 FILES
302
303  /usr/include/*.h
304  /usr/include/sys/*.h
305
306 etc.
307
308 =head1 AUTHOR
309
310 Larry Wall
311
312 =head1 SEE ALSO
313
314 perl(1)
315
316 =head1 DIAGNOSTICS
317
318 The usual warnings if it can't read or write the files involved.
319
320 =head1 BUGS
321
322 Doesn't construct the %sizeof array for you.
323
324 It doesn't handle all C constructs, but it does attempt to isolate
325 definitions inside evals so that you can get at the definitions
326 that it can translate.
327
328 It's only intended as a rough tool.
329 You may need to dicker with the files produced.
330
331 =cut
332
333 !NO!SUBS!
334
335 close OUT or die "Can't close $file: $!";
336 chmod 0755, $file or die "Can't reset permissions for $file: $!\n";
337 exec("$Config{'eunicefix'} $file") if $Config{'eunicefix'} ne ':';