ZWNJ, ZWJ. Any further convenience aliasing should
[p5sagit/p5-mst-13.2.git] / reentr.pl
index f9e2d3c..6b1f21c 100644 (file)
--- a/reentr.pl
+++ b/reentr.pl
@@ -64,6 +64,8 @@ print <<EOF;
 #ifdef __hpux
 #   undef HAS_CRYPT_R
 #   undef HAS_DRAND48_R
+#   undef HAS_ENDGRENT_R
+#   undef HAS_ENDPWENT_R
 #   undef HAS_GETGRENT_R
 #   undef HAS_GETPWENT_R
 #   undef HAS_SETLOCALE_R
@@ -159,7 +161,14 @@ while (<DATA>) {
     if ($opts{U} && open(U, ">d_${f}_r.U"))  {
        select U;
     }
-    my $prereqh = $h eq 'stdio' ? '' : "i_$h"; # There's no i_stdio.
+    my $prereqs  = '';
+    my $prereqh  = '';
+    my $prereqsh = '';
+    if ($h ne 'stdio') { # There's no i_stdio.
+       $prereqs  = "i_$h";
+       $prereqh  = "$h.h";
+       $prereqsh = "\$$prereqs $prereqh";
+    }
     print <<EOF if $opts{U};
 ?RCS: \$Id: d_${f}_r.U,v $
 ?RCS:
@@ -170,7 +179,7 @@ while (<DATA>) {
 ?RCS:
 ?RCS: Generated by the reentr.pl from the Perl 5.8 distribution.
 ?RCS:
-?MAKE:d_${f}_r ${f}_r_proto: Inlibc Protochk i_systypes $prereqh
+?MAKE:d_${f}_r ${f}_r_proto: Inlibc Protochk Hasproto i_systypes i_systime $prereqs usethreads i_pthread
 ?MAKE: -pick add \$@ %<
 ?S:d_${f}_r:
 ?S:    This variable conditionally defines the HAS_${F}_R symbol,
@@ -190,7 +199,7 @@ while (<DATA>) {
 ?H:#\$d_${f}_r HAS_${F}_R         /**/
 ?H:#define ${F}_R_PROTO \$${f}_r_proto    /**/
 ?H:.
-?T:try hdrs
+?T:try hdrs d_${f}_r_proto
 ?LINT:set d_${f}_r
 ?LINT:set ${f}_r_proto
 : see if ${f}_r exists
@@ -198,7 +207,20 @@ set ${f}_r d_${f}_r
 eval \$inlibc
 case "\$d_${f}_r" in
 "\$define")
-       hdrs="\$i_systypes sys/types.h define stdio.h \$i_${h} $h.h"
+       hdrs="\$i_systypes sys/types.h define stdio.h $prereqsh"
+       case "$h" in
+       time)
+               hdrs="\$hdrs \$i_systime sys/time.h"
+               ;;
+       esac
+       case "\$d_${f}_r_proto:\$usethreads" in
+       ":define")      d_${f}_r_proto=define
+               set d_${f}_r_proto ${f}_r \$hdrs
+               eval \$hasproto ;;
+       *)      ;;
+       esac
+       case "\$d_${f}_r_proto" in
+       define)
 EOF
        for my $p (@p) {
            my ($r, $a) = ($p =~ /^(.)_(.+)/);
@@ -221,9 +243,9 @@ EOF
        if ($opts{U}) {
            print <<EOF;
        case "\$${f}_r_proto" in
-       '')     d_${f}_r=undef
+       ''|0)   d_${f}_r=undef
                ${f}_r_proto=0
-               echo "Disabling ${f}_r, cannot determine prototype." ;;
+               echo "Disabling ${f}_r, cannot determine prototype." >&4 ;;
        * )     case "\$${f}_r_proto" in
                REENTRANT_PROTO*) ;;
                *) ${f}_r_proto="REENTRANT_PROTO_\$${f}_r_proto" ;;
@@ -231,6 +253,14 @@ EOF
                echo "Prototype: \$try" ;;
        esac
        ;;
+       *)      case "\$usethreads" in
+               define) echo "${f}_r has no prototype, not using it." >&4 ;;
+               esac
+               d_${f}_r=undef
+               ${f}_r_proto=0
+               ;;
+       esac
+       ;;
 *)     ${f}_r_proto=0
        ;;
 esac
@@ -289,13 +319,18 @@ sub define {
 /* The @F using \L$n? */
 
 EOF
+    my $G;
     for my $f (@F) {
        my $F = uc $f;
        my $h = "${F}_R_HAS_$n";
        push @H, $h;
        my @h = grep { /$p/ } @{$seena{$f}};
+       unless (defined $G) {
+           $G = $F;
+           $G =~ s/^GET//;
+       }
        if (@h) {
-           push @define, "#if (" . join(" || ", map { "${F}_R_PROTO == REENTRANT_PROTO_$_" } @h) . ")\n";
+           push @define, "#if defined(HAS_${F}_R) && (" . join(" || ", map { "${F}_R_PROTO == REENTRANT_PROTO_$_" } @h) . ")\n";
 
            push @define, <<EOF;
 #   define $h
@@ -312,14 +347,17 @@ EOF
 EOF
     push @define, "#if (" . join(" || ", map { "defined($_)" } @H) . ")\n";
     push @define, <<EOF;
-#   define USE_${H}_$n
+#   define USE_${G}_$n
 #else
-#   undef  USE_${H}_$n
+#   undef  USE_${G}_$n
 #endif
 
 EOF
 }
 
+define('BUFFER',  'B',
+       qw(getgrent getgrgid getgrnam));
+
 define('PTR',  'R',
        qw(getgrent getgrgid getgrnam));
 define('PTR',  'R',
@@ -328,9 +366,12 @@ define('PTR',  'R',
        qw(getspent getspnam));
 
 define('FPTR', 'H',
-       qw(getgrent getgrgid getgrnam));
+       qw(getgrent getgrgid getgrnam setgrent endgrent));
 define('FPTR', 'H',
-       qw(getpwent getpwnam getpwuid));
+       qw(getpwent getpwnam getpwuid setpwent endpwent));
+
+define('BUFFER',  'B',
+       qw(getpwent getpwgid getpwnam));
 
 define('PTR', 'R',
        qw(gethostent gethostbyaddr gethostbyname));
@@ -341,6 +382,15 @@ define('PTR', 'R',
 define('PTR', 'R',
        qw(getservent getservbyname getservbyport));
 
+define('BUFFER', 'B',
+       qw(gethostent gethostbyaddr gethostbyname));
+define('BUFFER', 'B',
+       qw(getnetent getnetbyaddr getnetbyname));
+define('BUFFER', 'B',
+       qw(getprotoent getprotobyname getprotobynumber));
+define('BUFFER', 'B',
+       qw(getservent getservbyname getservbyport));
+
 define('ERRNO', 'E',
        qw(gethostent gethostbyaddr gethostbyname));
 define('ERRNO', 'E',
@@ -359,23 +409,32 @@ for my $f (@seenf) {
        size_t  _${f}_size;
 EOF
            push @size, <<EOF;
-       PL_reentrant_buffer->_${f}_size = 256; /* Make something up. */
+       PL_reentrant_buffer->_${f}_size = REENTRANTSMALLSIZE;
 EOF
            pushinitfree $f;
            pushssif $endif;
        }
-        elsif ($f =~ /^(crypt|drand48|gmtime|localtime|random)$/) {
+        elsif ($f =~ /^(crypt)$/) {
            pushssif $ifdef;
            push @struct, <<EOF;
+#if CRYPT_R_PROTO == REENTRANT_PROTO_B_CCD
+       $seend{$f} _${f}_data;
+#else
        $seent{$f} _${f}_struct;
+#endif
 EOF
-           if ($f eq 'crypt') {
-               push @init, <<EOF;
+           push @init, <<EOF;
 #ifdef __GLIBC__
        PL_reentrant_buffer->_${f}_struct.initialized = 0;
 #endif
 EOF
-           }
+           pushssif $endif;
+       }
+        elsif ($f =~ /^(drand48|gmtime|localtime|random)$/) {
+           pushssif $ifdef;
+           push @struct, <<EOF;
+       $seent{$f} _${f}_struct;
+EOF
            if ($1 eq 'drand48') {
                push @struct, <<EOF;
        double  _${f}_double;
@@ -387,6 +446,7 @@ EOF
            pushssif $ifdef;
            my $g = $f;
            $g =~ s/nam/ent/g;
+           $g =~ s/^get//;
            my $G = uc $g;
            push @struct, <<EOF;
        $seent{$f}      _${g}_struct;
@@ -415,9 +475,13 @@ EOF
 EOF
                my $sc = $g eq 'getgrent' ?
                    '_SC_GETGR_R_SIZE_MAX' : '_SC_GETPW_R_SIZE_MAX';
+               my $sz = $g eq 'getgrent' ?
+                    '_grent_size' : '_pwent_size';
                push @size, <<EOF;
 #   if defined(HAS_SYSCONF) && defined($sc) && !defined(__GLIBC__)
        PL_reentrant_buffer->_${g}_size = sysconf($sc);
+       if (PL_reentrant_buffer->$sz == -1)
+               PL_reentrant_buffer->$sz = REENTRANTUSUALSIZE;
 #   else
 #       if defined(__osf__) && defined(__alpha) && defined(SIABUFSIZ)
        PL_reentrant_buffer->_${g}_size = SIABUFSIZ;
@@ -425,7 +489,7 @@ EOF
 #           ifdef __sgi
        PL_reentrant_buffer->_${g}_size = BUFSIZ;
 #           else
-       PL_reentrant_buffer->_${g}_size = 2048;
+       PL_reentrant_buffer->_${g}_size = REENTRANTUSUALSIZE;
 #           endif
 #       endif
 #   endif 
@@ -438,9 +502,11 @@ EOF
            pushssif $ifdef;
            my $g = $f;
            $g =~ s/byname/ent/;
+           $g =~ s/^get//;
            my $G = uc $g;
            my $D = ifprotomatch($F, grep {/D/} @p);
            my $d = $seend{$f};
+           $d =~ s/\*$//; # snip: we need need the base type.
            push @struct, <<EOF;
        $seent{$f}      _${g}_struct;
 #   if $D
@@ -460,7 +526,7 @@ EOF
 EOF
            push @size, <<EOF;
 #if   !($D)
-       PL_reentrant_buffer->_${g}_size = 2048; /* Any better ideas? */
+       PL_reentrant_buffer->_${g}_size = REENTRANTUSUALSIZE;
 #endif
 EOF
            push @init, <<EOF;
@@ -501,7 +567,6 @@ EOF
 
        push @wrap, $ifdef;
 
-# Doesn't implement the buffer growth loop for glibc gethostby*().
        push @wrap, <<EOF;
 #   undef $f
 EOF
@@ -511,10 +576,9 @@ EOF
            my ($r, $a) = split '_', $p;
            my $test = $r eq 'I' ? ' == 0' : '';
            my $true  = 1;
-           my $false = 0;
            my $g = $f;
            if ($g =~ /^(?:get|set|end)(pw|gr|host|net|proto|serv|sp)/) {
-               $g = "get$1ent";
+               $g = "$1ent";
            } elsif ($g eq 'srand48') {
                $g = "drand48";
            }
@@ -569,9 +633,16 @@ EOF
 #       define $f($v) $call
 EOF
            } else {
-               push @wrap, <<EOF;
-#       define $f($v) ($call$test ? $true : $false)
+               if ($f =~ /^get/) {
+                   my $rv = $v ? ", $v" : "";
+                   push @wrap, <<EOF;
+#       define $f($v) ($call$test ? $true : (errno == ERANGE ? Perl_reentrant_retry("$f"$rv) : 0))
 EOF
+               } else {
+                   push @wrap, <<EOF;
+#       define $f($v) ($call$test ? $true : 0)
+EOF
+               }
            }
            push @wrap, <<EOF;
 #   endif
@@ -631,6 +702,8 @@ print <<EOF;
 void
 Perl_reentrant_size(pTHX) {
 #ifdef USE_REENTRANT_API
+#define REENTRANTSMALLSIZE      256    /* Make something up. */
+#define REENTRANTUSUALSIZE     4096    /* Make something up. */
 @size
 #endif /* USE_REENTRANT_API */
 }
@@ -652,20 +725,213 @@ Perl_reentrant_free(pTHX) {
 #endif /* USE_REENTRANT_API */
 }
 
+void*
+Perl_reentrant_retry(const char *f, ...)
+{
+    dTHX;
+    void *retptr = NULL;
+#ifdef USE_REENTRANT_API
+#  if defined(USE_HOSTENT_BUFFER) || defined(USE_GRENT_BUFFER) || defined(USE_NETENT_BUFFER) || defined(USE_PWENT_BUFFER) || defined(USE_PROTOENT_BUFFER) || defined(USE_SRVENT_BUFFER)
+    void *p0;
+#  endif
+#  if defined(USE_SERVENT_BUFFER)
+    void *p1;
+#  endif
+#  if defined(USE_HOSTENT_BUFFER)
+    size_t asize;
+#  endif
+#  if defined(USE_HOSTENT_BUFFER) || defined(USE_NETENT_BUFFER) || defined(USE_PROTOENT_BUFFER) || defined(USE_SERVENT_BUFFER)
+    int anint;
+#  endif
+    va_list ap;
+
+    va_start(ap, f);
+
+#define REENTRANTHALFMAXSIZE 32768 /* The maximum may end up twice this. */
+
+    switch (PL_op->op_type) {
+#ifdef USE_HOSTENT_BUFFER
+    case OP_GHBYADDR:
+    case OP_GHBYNAME:
+    case OP_GHOSTENT:
+       {
+           if (PL_reentrant_buffer->_hostent_size <= REENTRANTHALFMAXSIZE) {
+               PL_reentrant_buffer->_hostent_size *= 2;
+               Renew(PL_reentrant_buffer->_hostent_buffer,
+                     PL_reentrant_buffer->_hostent_size, char);
+               switch (PL_op->op_type) {
+               case OP_GHBYADDR:
+                   p0    = va_arg(ap, void *);
+                   asize = va_arg(ap, size_t);
+                   anint  = va_arg(ap, int);
+                   retptr = gethostbyaddr(p0, asize, anint); break;
+               case OP_GHBYNAME:
+                   p0 = va_arg(ap, void *);
+                   retptr = gethostbyname(p0); break;
+               case OP_GHOSTENT:
+                   retptr = gethostent(); break;
+               default:
+                   break;
+               }
+           }
+       }
+       break;
+#endif
+#ifdef USE_GRENT_BUFFER
+    case OP_GGRNAM:
+    case OP_GGRGID:
+    case OP_GGRENT:
+       {
+           if (PL_reentrant_buffer->_grent_size <= REENTRANTHALFMAXSIZE) {
+               Gid_t gid;
+               PL_reentrant_buffer->_grent_size *= 2;
+               Renew(PL_reentrant_buffer->_grent_buffer,
+                     PL_reentrant_buffer->_grent_size, char);
+               switch (PL_op->op_type) {
+               case OP_GGRNAM:
+                   p0 = va_arg(ap, void *);
+                   retptr = getgrnam(p0); break;
+               case OP_GGRGID:
+                   gid = va_arg(ap, Gid_t);
+                   retptr = getgrgid(gid); break;
+               case OP_GGRENT:
+                   retptr = getgrent(); break;
+               default:
+                   break;
+               }
+           }
+       }
+       break;
+#endif
+#ifdef USE_NETENT_BUFFER
+    case OP_GNBYADDR:
+    case OP_GNBYNAME:
+    case OP_GNETENT:
+       {
+           if (PL_reentrant_buffer->_netent_size <= REENTRANTHALFMAXSIZE) {
+               Netdb_net_t net;
+               PL_reentrant_buffer->_netent_size *= 2;
+               Renew(PL_reentrant_buffer->_netent_buffer,
+                     PL_reentrant_buffer->_netent_size, char);
+               switch (PL_op->op_type) {
+               case OP_GNBYADDR:
+                   net = va_arg(ap, Netdb_net_t);
+                   anint = va_arg(ap, int);
+                   retptr = getnetbyaddr(net, anint); break;
+               case OP_GNBYNAME:
+                   p0 = va_arg(ap, void *);
+                   retptr = getnetbyname(p0); break;
+               case OP_GNETENT:
+                   retptr = getnetent(); break;
+               default:
+                   break;
+               }
+           }
+       }
+       break;
+#endif
+#ifdef USE_PWENT_BUFFER
+    case OP_GPWNAM:
+    case OP_GPWUID:
+    case OP_GPWENT:
+       {
+           if (PL_reentrant_buffer->_pwent_size <= REENTRANTHALFMAXSIZE) {
+               Uid_t uid;
+               PL_reentrant_buffer->_pwent_size *= 2;
+               Renew(PL_reentrant_buffer->_pwent_buffer,
+                     PL_reentrant_buffer->_pwent_size, char);
+               switch (PL_op->op_type) {
+               case OP_GPWNAM:
+                   p0 = va_arg(ap, void *);
+                   retptr = getpwnam(p0); break;
+               case OP_GPWUID:
+                   uid = va_arg(ap, Uid_t);
+                   retptr = getpwuid(uid); break;
+               case OP_GPWENT:
+                   retptr = getpwent(); break;
+               default:
+                   break;
+               }
+           }
+       }
+       break;
+#endif
+#ifdef USE_PROTOENT_BUFFER
+    case OP_GPBYNAME:
+    case OP_GPBYNUMBER:
+    case OP_GPROTOENT:
+       {
+           if (PL_reentrant_buffer->_protoent_size <= REENTRANTHALFMAXSIZE) {
+               PL_reentrant_buffer->_protoent_size *= 2;
+               Renew(PL_reentrant_buffer->_protoent_buffer,
+                     PL_reentrant_buffer->_protoent_size, char);
+               switch (PL_op->op_type) {
+               case OP_GPBYNAME:
+                   p0 = va_arg(ap, void *);
+                   retptr = getprotobyname(p0); break;
+               case OP_GPBYNUMBER:
+                   anint = va_arg(ap, int);
+                   retptr = getprotobynumber(anint); break;
+               case OP_GPROTOENT:
+                   retptr = getprotoent(); break;
+               default:
+                   break;
+               }
+           }
+       }
+       break;
+#endif
+#ifdef USE_SERVENT_BUFFER
+    case OP_GSBYNAME:
+    case OP_GSBYPORT:
+    case OP_GSERVENT:
+       {
+           if (PL_reentrant_buffer->_servent_size <= REENTRANTHALFMAXSIZE) {
+               PL_reentrant_buffer->_servent_size *= 2;
+               Renew(PL_reentrant_buffer->_servent_buffer,
+                     PL_reentrant_buffer->_servent_size, char);
+               switch (PL_op->op_type) {
+               case OP_GSBYNAME:
+                   p0 = va_arg(ap, void *);
+                   p1 = va_arg(ap, void *);
+                   retptr = getservbyname(p0, p1); break;
+               case OP_GSBYPORT:
+                   anint = va_arg(ap, int);
+                   p0 = va_arg(ap, void *);
+                   retptr = getservbyport(anint, p0); break;
+               case OP_GSERVENT:
+                   retptr = getservent(); break;
+               default:
+                   break;
+               }
+           }
+       }
+       break;
+#endif
+    default:
+       /* Not known how to retry, so just fail. */
+       break;
+    }
+
+    va_end(ap);
+#endif
+    return retptr;
+}
+
 EOF
 
 __DATA__
 asctime S      |time   |const struct tm|B_SB|B_SBI|I_SB|I_SBI
-crypt CC       |crypt  |struct crypt_data|B_CCS
+crypt CC       |crypt  |struct crypt_data|B_CCS|B_CCD|D=CRYPTD*
 ctermid        B       |stdio  |               |B_B
 ctime S                |time   |const time_t   |B_SB|B_SBI|I_SB|I_SBI
 drand48                |stdlib |struct drand48_data    |I_ST|T=double*
 endgrent       |grp    |               |I_H|V_H
-endhostent     |netdb  |struct hostent_data    |I_S|V_S
-endnetent      |netdb  |struct netent_data     |I_S|V_S
-endprotoent    |netdb  |struct protoent_data   |I_S|V_S
+endhostent     |netdb  |               |I_D|V_D|D=struct hostent_data*
+endnetent      |netdb  |               |I_D|V_D|D=struct netent_data*
+endprotoent    |netdb  |               |I_D|V_D|D=struct protoent_data*
 endpwent       |pwd    |               |I_H|V_H
-endservent     |netdb  |struct servent_data    |I_S|V_S
+endservent     |netdb  |               |I_D|V_D|D=struct servent_data*
 getgrent       |grp    |struct group   |I_SBWR|I_SBIR|S_SBW|S_SBI|I_SBI|I_SBIH
 getgrgid T     |grp    |struct group   |I_TSBWR|I_TSBIR|I_TSBI|S_TSBI|T=gid_t
 getgrnam C     |grp    |struct group   |I_CSBWR|I_CSBIR|S_CBI|I_CSBI|S_CSBI