a795cfc822d1f0838d53f4aaee77fe0600935744
[p5sagit/p5-mst-13.2.git] / ext / Errno / Errno_pm.PL
1 use ExtUtils::MakeMaker;
2 use Config;
3 use strict;
4
5 our $VERSION = "1.09_00";
6
7 my %err = ();
8 my %wsa = ();
9
10 unlink "Errno.pm" if -f "Errno.pm";
11 open OUT, ">Errno.pm" or die "Cannot open Errno.pm: $!";
12 select OUT;
13 my $file;
14 foreach $file (get_files()) {
15     process_file($file);
16 }
17 write_errno_pm();
18 unlink "errno.c" if -f "errno.c";
19
20 sub process_file {
21     my($file) = @_;
22
23     return unless defined $file and -f $file;
24 #   warn "Processing $file\n";
25
26     local *FH;
27     if (($^O eq 'VMS') && ($Config{vms_cc_type} ne 'gnuc')) {
28         unless(open(FH," LIBRARY/EXTRACT=ERRNO/OUTPUT=SYS\$OUTPUT $file |")) {
29             warn "Cannot open '$file'";
30             return;
31         }     
32     } elsif ($Config{gccversion} ne ''
33              # OpenSTEP has gcc 2.7.2.1 which recognizes but
34              # doesn't implement the -dM flag.
35              && $^O ne 'openstep' && $^O ne 'next' && $^O ne 'darwin'
36              ) { 
37         # With the -dM option, gcc outputs every #define it finds
38         unless(open(FH,"$Config{cc} -E -dM $Config{cppflags} $file |")) {
39             warn "Cannot open '$file'";
40             return;
41         }     
42     } else {
43         unless(open(FH,"< $file")) {
44             # This file could be a temporary file created by cppstdin
45             # so only warn under -w, and return
46             warn "Cannot open '$file'" if $^W;
47             return;
48         }
49     }
50
51     if ($^O eq 'MacOS') {
52         while(<FH>) {
53             $err{$1} = $2
54                 if /^\s*#\s*define\s+(E\w+)\s+(\d+)/;
55         }
56     } else {
57         while(<FH>) {
58             $err{$1} = 1
59                 if /^\s*#\s*define\s+(E\w+)\s+/;
60             if ($^O eq 'MSWin32') {
61                 $wsa{$1} = 1
62                     if /^\s*#\s*define\s+WSA(E\w+)\s+/;
63             }
64         }
65     }
66     close(FH);
67 }
68
69 my $cppstdin;
70
71 sub default_cpp {
72     unless (defined $cppstdin) {
73         use File::Spec;
74         $cppstdin = $Config{cppstdin};
75         my $upup_cppstdin = File::Spec->catfile(File::Spec->updir,
76                                                 File::Spec->updir,
77                                                 "cppstdin");
78         my $cppstdin_is_wrapper =
79             ($cppstdin eq 'cppstdin'
80                 and -f $upup_cppstdin
81                     and -x $upup_cppstdin);
82         $cppstdin = $upup_cppstdin if $cppstdin_is_wrapper;
83     }
84     return "$cppstdin $Config{cppflags} $Config{cppminus}";
85 }
86
87 sub get_files {
88     my %file = ();
89     # VMS keeps its include files in system libraries (well, except for Gcc)
90     if ($^O eq 'VMS') {
91         if ($Config{vms_cc_type} eq 'decc') {
92             $file{'Sys$Library:DECC$RTLDEF.TLB'} = 1;
93         } elsif ($Config{vms_cc_type} eq 'vaxc') {
94             $file{'Sys$Library:vaxcdef.tlb'} = 1;
95         } elsif ($Config{vms_cc_type} eq 'gcc') {
96             $file{'gnu_cc_include:[000000]errno.h'} = 1;
97         }
98     } elsif ($^O eq 'os390') {
99         # OS/390 C compiler doesn't generate #file or #line directives
100         $file{'/usr/include/errno.h'} = 1;
101     } elsif ($^O eq 'vmesa') {
102         # OS/390 C compiler doesn't generate #file or #line directives
103         $file{'../../vmesa/errno.h'} = 1;
104     } elsif ($Config{archname} eq 'epoc') {
105         # Watch out for cross compiling for EPOC (usually done on linux)
106         $file{'/usr/local/epocemx/epocsdk/include/libc/sys/errno.h'} = 1;
107     } elsif ($^O eq 'linux' &&
108              $Config{gccversion} ne '' # might be using, say, Intel's icc
109              ) {
110         # Some Linuxes have weird errno.hs which generate
111         # no #file or #line directives
112         my $linux_errno_h = -e '/usr/include/errno.h' ?
113             '/usr/include/errno.h' : '/usr/local/include/errno.h';
114         $file{$linux_errno_h} = 1;
115     } elsif ($^O eq 'MacOS') {
116         # note that we are only getting the GUSI errno's here ...
117         # we might miss out on compiler-specific ones
118         $file{"$ENV{GUSI}include:sys:errno.h"} = 1;
119
120     } elsif ($^O eq 'beos') {
121         # hidden in a special place
122         $file{'/boot/develop/headers/posix/errno.h'} = 1;
123
124     } elsif ($^O eq 'vos') {
125         # avoid problem where cpp returns non-POSIX pathnames
126         $file{'/system/include_library/errno.h'} = 1;
127     } else {
128         open(CPPI,"> errno.c") or
129             die "Cannot open errno.c";
130
131         if ($^O eq 'NetWare') {
132             print CPPI "#include <nwerrno.h>\n";
133         } else {
134             print CPPI "#include <errno.h>\n";
135             if ($^O eq 'MSWin32') {
136                 print CPPI "#define _WINSOCKAPI_\n"; # don't drag in everything
137                 print CPPI "#include <winsock.h>\n";
138             }
139         }
140
141         close(CPPI);
142
143         # invoke CPP and read the output
144         if ($^O eq 'MSWin32' || $^O eq 'NetWare') {
145             open(CPPO,"$Config{cpprun} $Config{cppflags} errno.c |") or
146                 die "Cannot run '$Config{cpprun} $Config{cppflags} errno.c'";
147         } else {
148             my $cpp = default_cpp();
149             open(CPPO,"$cpp < errno.c |") or
150                 die "Cannot exec $cpp";
151         }
152
153         my $pat;
154         if (($^O eq 'MSWin32' || $^O eq 'NetWare') and $Config{cc} =~ /^bcc/i) {
155             $pat = '^/\*\s+(.+)\s+\d+\s*:\s+\*/';
156         }
157         else {
158             $pat = '^#\s*(?:line)?\s*\d+\s+"([^"]+)"';
159         }
160         while(<CPPO>) {
161             if ($^O eq 'os2' or $^O eq 'MSWin32' or $^O eq 'NetWare') {
162                 if (/$pat/o) {
163                    my $f = $1;
164                    $f =~ s,\\\\,/,g;
165                    $file{$f} = 1;
166                 }
167             }
168             else {
169                 $file{$1} = 1 if /$pat/o;
170             }
171         }
172         close(CPPO);
173     }
174     return keys %file;
175 }
176
177 sub write_errno_pm {
178     my $err;
179
180     # quick sanity check
181
182     die "No error definitions found" unless keys %err;
183
184     # create the CPP input
185
186     open(CPPI,"> errno.c") or
187         die "Cannot open errno.c";
188
189     if ($^O eq 'NetWare') {
190         print CPPI "#include <nwerrno.h>\n";
191         } 
192     else {
193         print CPPI "#include <errno.h>\n";
194     }
195     if ($^O eq 'MSWin32') {
196         print CPPI "#include <winsock.h>\n";
197         foreach $err (keys %wsa) {
198             print CPPI "#ifndef $err\n";
199             print CPPI "#define $err WSA$err\n";
200             print CPPI "#endif\n";
201             $err{$err} = 1;
202         }
203     }
204  
205     foreach $err (keys %err) {
206         print CPPI '"',$err,'" [[',$err,']]',"\n";
207     }
208
209     close(CPPI);
210
211     unless ($^O eq 'MacOS') {   # trust what we have
212     # invoke CPP and read the output
213
214         if ($^O eq 'VMS') {
215             my $cpp = "$Config{cppstdin} $Config{cppflags} $Config{cppminus}";
216             $cpp =~ s/sys\$input//i;
217             open(CPPO,"$cpp  errno.c |") or
218                 die "Cannot exec $Config{cppstdin}";
219         } elsif ($^O eq 'MSWin32' || $^O eq 'NetWare') {
220             open(CPPO,"$Config{cpprun} $Config{cppflags} errno.c |") or
221                 die "Cannot run '$Config{cpprun} $Config{cppflags} errno.c'";
222         } else {
223             my $cpp = default_cpp();
224             open(CPPO,"$cpp < errno.c |")
225                 or die "Cannot exec $cpp";
226         }
227
228         %err = ();
229
230         while(<CPPO>) {
231             my($name,$expr);
232             next unless ($name, $expr) = /"(.*?)"\s*\[\s*\[\s*(.*?)\s*\]\s*\]/;
233             next if $name eq $expr;
234             $expr =~ s/\(?\(\w+\)([^\)]*)\)?/$1/; # ((type)0xcafebabe) at alia
235             $expr =~ s/((?:0x)?[0-9a-fA-F]+)[LU]+\b/$1/g; # 2147483647L et alia
236             next if $expr =~ m/^[a-zA-Z]+$/; # skip some Win32 functions
237             if($expr =~ m/^0[xX]/) {
238                 $err{$name} = hex $expr;
239             }
240             else {
241             $err{$name} = eval $expr;
242         }
243             delete $err{$name} unless defined $err{$name};
244         }
245         close(CPPO);
246     }
247
248     # Many of the E constants (including ENOENT, which is being
249     # used in the Perl test suite a lot), are available only as
250     # enums in BeOS, so compiling and executing some code is about
251     # only way to find out what the numeric Evalues are.
252
253     if ($^O eq 'beos') {
254         if (open(C, ">errno.c")) {
255             my @zero = grep { !$err{$_} } keys %err;
256             print C <<EOF;
257 #include <errno.h>
258 #include <stdio.h>
259 int main() {
260 EOF
261             for (@zero) {
262                 print C qq[printf("$_ %d\n", $_);]
263             }
264             print C "}\n";
265             close C;
266             system("cc -o errno errno.c");
267             unlink("errno.c");
268             if (open(C, "./errno|")) {
269                 while (<C>) {
270                     if (/^(\w+) (-?\d+)$/) { $err{$1} = $2 }
271                 }
272                 close(C);
273             } else {
274                 die "failed to execute ./errno: $!\n";
275             }
276             unlink("errno");
277         } else {
278             die "failed to create errno.c: $!\n";
279         }
280     }
281
282     # Write Errno.pm
283
284     print <<"EDQ";
285 #
286 # This file is auto-generated. ***ANY*** changes here will be lost
287 #
288
289 package Errno;
290 our (\@EXPORT_OK,\%EXPORT_TAGS,\@ISA,\$VERSION,\%errno,\$AUTOLOAD);
291 use Exporter ();
292 use Config;
293 use strict;
294
295 "\$Config{'archname'}-\$Config{'osvers'}" eq
296 "$Config{'archname'}-$Config{'osvers'}" or
297         die "Errno architecture ($Config{'archname'}-$Config{'osvers'}) does not match executable architecture (\$Config{'archname'}-\$Config{'osvers'})";
298
299 \$VERSION = "$VERSION";
300 \$VERSION = eval \$VERSION;
301 \@ISA = qw(Exporter);
302
303 EDQ
304    
305     my $len = 0;
306     my @err = sort { $err{$a} <=> $err{$b} } keys %err;
307     map { $len = length if length > $len } @err;
308
309     my $j = "\@EXPORT_OK = qw(" . join(" ",keys %err) . ");\n";
310     $j =~ s/(.{50,70})\s/$1\n\t/g;
311     print $j,"\n";
312
313 print <<'ESQ';
314 %EXPORT_TAGS = (
315     POSIX => [qw(
316 ESQ
317
318     my $k = join(" ", grep { exists $err{$_} } 
319         qw(E2BIG EACCES EADDRINUSE EADDRNOTAVAIL EAFNOSUPPORT
320         EAGAIN EALREADY EBADF EBUSY ECHILD ECONNABORTED
321         ECONNREFUSED ECONNRESET EDEADLK EDESTADDRREQ EDOM EDQUOT
322         EEXIST EFAULT EFBIG EHOSTDOWN EHOSTUNREACH EINPROGRESS
323         EINTR EINVAL EIO EISCONN EISDIR ELOOP EMFILE EMLINK
324         EMSGSIZE ENAMETOOLONG ENETDOWN ENETRESET ENETUNREACH
325         ENFILE ENOBUFS ENODEV ENOENT ENOEXEC ENOLCK ENOMEM
326         ENOPROTOOPT ENOSPC ENOSYS ENOTBLK ENOTCONN ENOTDIR
327         ENOTEMPTY ENOTSOCK ENOTTY ENXIO EOPNOTSUPP EPERM
328         EPFNOSUPPORT EPIPE EPROCLIM EPROTONOSUPPORT EPROTOTYPE
329         ERANGE EREMOTE ERESTART EROFS ESHUTDOWN ESOCKTNOSUPPORT
330         ESPIPE ESRCH ESTALE ETIMEDOUT ETOOMANYREFS ETXTBSY
331         EUSERS EWOULDBLOCK EXDEV));
332
333     $k =~ s/(.{50,70})\s/$1\n\t/g;
334     print "\t",$k,"\n    )]\n);\n\n";
335
336     foreach $err (@err) {
337         printf "sub %s () { %d }\n",,$err,$err{$err};
338     }
339
340     print <<'ESQ';
341
342 sub TIEHASH { bless [] }
343
344 sub FETCH {
345     my ($self, $errname) = @_;
346     my $proto = prototype("Errno::$errname");
347     my $errno = "";
348     if (defined($proto) && $proto eq "") {
349         no strict 'refs';
350         $errno = &$errname;
351         $errno = 0 unless $! == $errno;
352     }
353     return $errno;
354 }
355
356 sub STORE {
357     require Carp;
358     Carp::confess("ERRNO hash is read only!");
359 }
360
361 *CLEAR = \&STORE;
362 *DELETE = \&STORE;
363
364 sub NEXTKEY {
365     my($k,$v);
366     while(($k,$v) = each %Errno::) {
367         my $proto = prototype("Errno::$k");
368         last if (defined($proto) && $proto eq "");
369     }
370     $k
371 }
372
373 sub FIRSTKEY {
374     my $s = scalar keys %Errno::;       # initialize iterator
375     goto &NEXTKEY;
376 }
377
378 sub EXISTS {
379     my ($self, $errname) = @_;
380     my $r = ref $errname;
381     my $proto = !$r || $r eq 'CODE' ? prototype($errname) : undef;
382     defined($proto) && $proto eq "";
383 }
384
385 tie %!, __PACKAGE__;
386
387 1;
388 __END__
389
390 =head1 NAME
391
392 Errno - System errno constants
393
394 =head1 SYNOPSIS
395
396     use Errno qw(EINTR EIO :POSIX);
397
398 =head1 DESCRIPTION
399
400 C<Errno> defines and conditionally exports all the error constants
401 defined in your system C<errno.h> include file. It has a single export
402 tag, C<:POSIX>, which will export all POSIX defined error numbers.
403
404 C<Errno> also makes C<%!> magic such that each element of C<%!> has a
405 non-zero value only if C<$!> is set to that value. For example:
406
407     use Errno;
408
409     unless (open(FH, "/fangorn/spouse")) {
410         if ($!{ENOENT}) {
411             warn "Get a wife!\n";
412         } else {
413             warn "This path is barred: $!";
414         } 
415     } 
416
417 If a specified constant C<EFOO> does not exist on the system, C<$!{EFOO}>
418 returns C<"">.  You may use C<exists $!{EFOO}> to check whether the
419 constant is available on the system.
420
421 =head1 CAVEATS
422
423 Importing a particular constant may not be very portable, because the
424 import will fail on platforms that do not have that constant.  A more
425 portable way to set C<$!> to a valid value is to use:
426
427     if (exists &Errno::EFOO) {
428         $! = &Errno::EFOO;
429     }
430
431 =head1 AUTHOR
432
433 Graham Barr <gbarr@pobox.com>
434
435 =head1 COPYRIGHT
436
437 Copyright (c) 1997-8 Graham Barr. All rights reserved.
438 This program is free software; you can redistribute it and/or modify it
439 under the same terms as Perl itself.
440
441 =cut
442
443 ESQ
444
445 }