Support crypt_r(const char*,const char*, CRYPTD*).
[p5sagit/p5-mst-13.2.git] / reentr.pl
index 3d9a159..ae56377 100644 (file)
--- a/reentr.pl
+++ b/reentr.pl
@@ -336,6 +336,9 @@ EOF
 EOF
 }
 
+define('BUFFER',  'B',
+       qw(getgrent getgrgid getgrnam));
+
 define('PTR',  'R',
        qw(getgrent getgrgid getgrnam));
 define('PTR',  'R',
@@ -348,6 +351,9 @@ define('FPTR', 'H',
 define('FPTR', 'H',
        qw(getpwent getpwnam getpwuid));
 
+define('BUFFER',  'B',
+       qw(getpwent getpwgid getpwnam));
+
 define('PTR', 'R',
        qw(gethostent gethostbyaddr gethostbyname));
 define('PTR', 'R',
@@ -357,6 +363,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',
@@ -380,18 +395,27 @@ 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;
@@ -441,7 +465,7 @@ EOF
 #           ifdef __sgi
        PL_reentrant_buffer->_${g}_size = BUFSIZ;
 #           else
-       PL_reentrant_buffer->_${g}_size = 2048;
+       PL_reentrant_buffer->_${g}_size = 256;
 #           endif
 #       endif
 #   endif 
@@ -527,7 +551,6 @@ 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";
@@ -585,9 +608,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
@@ -668,11 +698,195 @@ Perl_reentrant_free(pTHX) {
 #endif /* USE_REENTRANT_API */
 }
 
+void*
+Perl_reentrant_retry(const char *f, ...)
+{
+    dTHX;
+    void *retptr = NULL;
+#ifdef USE_REENTRANT_API
+    void *p0, *p1;
+    size_t asize;
+    int anint;
+    va_list ap;
+
+    va_start(ap, f);
+
+#define REENTRANTHALFMAXSIZE 32768 /* The maximum may end up twice this. */
+
+    switch (PL_op->op_type) {
+#ifdef USE_GETHOSTENT_BUFFER
+    case OP_GHBYADDR:
+    case OP_GHBYNAME:
+    case OP_GHOSTENT:
+       {
+           if (PL_reentrant_buffer->_gethostent_size <= REENTRANTHALFMAXSIZE) {
+               PL_reentrant_buffer->_gethostent_size *= 2;
+               Renew(PL_reentrant_buffer->_gethostent_buffer,
+                     PL_reentrant_buffer->_gethostent_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_GETGRENT_BUFFER
+    case OP_GGRNAM:
+    case OP_GGRGID:
+    case OP_GGRENT:
+       {
+           if (PL_reentrant_buffer->_getgrent_size <= REENTRANTHALFMAXSIZE) {
+               Gid_t gid;
+               PL_reentrant_buffer->_getgrent_size *= 2;
+               Renew(PL_reentrant_buffer->_getgrent_buffer,
+                     PL_reentrant_buffer->_getgrent_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_GETNETENT_BUFFER
+    case OP_GNBYADDR:
+    case OP_GNBYNAME:
+    case OP_GNETENT:
+       {
+           if (PL_reentrant_buffer->_getnetent_size <= REENTRANTHALFMAXSIZE) {
+               Netdb_net_t net;
+               PL_reentrant_buffer->_getnetent_size *= 2;
+               Renew(PL_reentrant_buffer->_getnetent_buffer,
+                     PL_reentrant_buffer->_getnetent_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_GETPWENT_BUFFER
+    case OP_GPWNAM:
+    case OP_GPWUID:
+    case OP_GPWENT:
+       {
+           if (PL_reentrant_buffer->_getpwent_size <= REENTRANTHALFMAXSIZE) {
+               Uid_t uid;
+               PL_reentrant_buffer->_getpwent_size *= 2;
+               Renew(PL_reentrant_buffer->_getpwent_buffer,
+                     PL_reentrant_buffer->_getpwent_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_GETPROTOENT_BUFFER
+    case OP_GPBYNAME:
+    case OP_GPBYNUMBER:
+    case OP_GPROTOENT:
+       {
+           if (PL_reentrant_buffer->_getprotoent_size <= REENTRANTHALFMAXSIZE) {
+               PL_reentrant_buffer->_getprotoent_size *= 2;
+               Renew(PL_reentrant_buffer->_getprotoent_buffer,
+                     PL_reentrant_buffer->_getprotoent_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_GETSERVENT_BUFFER
+    case OP_GSBYNAME:
+    case OP_GSBYPORT:
+    case OP_GSERVENT:
+       {
+           if (PL_reentrant_buffer->_getservent_size <= REENTRANTHALFMAXSIZE) {
+               PL_reentrant_buffer->_getservent_size *= 2;
+               Renew(PL_reentrant_buffer->_getservent_buffer,
+                     PL_reentrant_buffer->_getservent_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*