This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
reentr.[ch]: Add gmtime_r, localtime_r
[perl5.git] / regen / reentr.pl
1 #!/usr/bin/perl -w
2 #
3 # Regenerate (overwriting only if changed):
4 #
5 #    reentr.h
6 #    reentr.c
7 #
8 # from information stored in the DATA section of this file.
9 #
10 # With the -U option, it also unconditionally regenerates the relevant
11 # metaconfig units:
12 #
13 #    d_${func}_r.U
14 #
15 # Also accepts the standard regen_lib -q and -v args.
16 #
17 # This script is normally invoked from regen.pl.
18
19 BEGIN {
20     # Get function prototypes
21     require './regen/regen_lib.pl';
22 }
23
24 use strict;
25 use Getopt::Std;
26 my %opts;
27 getopts('Uv', \%opts);
28
29 my %map = (
30            V => "void",
31            A => "char*",        # as an input argument
32            B => "char*",        # as an output argument
33            C => "const char*",  # as a read-only input argument
34            I => "int",
35            L => "long",
36            W => "size_t",
37            H => "FILE**",
38            E => "int*",
39           );
40
41 # (See the definitions after __DATA__.)
42 # In func|inc|type|... a "S" means "type*", and a "R" means "type**".
43 # (The "types" are often structs, such as "struct passwd".)
44 #
45 # After the prototypes one can have |X=...|Y=... to define more types.
46 # A commonly used extra type is to define D to be equal to "type_data",
47 # for example "struct_hostent_data to" go with "struct hostent".
48 #
49 # Example #1: I_XSBWR means int  func_r(X, type, char*, size_t, type**)
50 # Example #2: S_SBIE  means type func_r(type, char*, int, int*)
51 # Example #3: S_CBI   means type func_r(const char*, char*, int)
52
53 sub open_print_header {
54     my ($file, $quote) = @_;
55     return open_new($file, '>',
56                     { by => 'regen/reentr.pl',
57                       from => 'data in regen/reentr.pl',
58                       file => $file, style => '*',
59                       copyright => [2002, 2003, 2005 .. 2007],
60                       quote => $quote });
61 }
62
63 my $h = open_print_header('reentr.h');
64 print $h <<EOF;
65 #ifndef PERL_REENTR_H_
66 #define PERL_REENTR_H_
67
68 /* If compiling for a threaded perl, we will macro-wrap the system/library
69  * interfaces (e.g. getpwent()) which have threaded versions
70  * (e.g. getpwent_r()), which will handle things correctly for
71  * the Perl interpreter.  This is done automatically for the perl core and
72  * extensions, but not generally for XS modules unless they
73  *    #define PERL_REENTRANT
74  * See L<perlxs/Thread-aware system interfaces>.
75  *
76  * For a function 'foo', use the compile-time directive
77  *    #ifdef PERL_REENTR_USING_FOO_R
78  * to test if the function actually did get replaced by the reentrant version.
79  * (If it isn't getting replaced, it might mean it uses a different prototype
80  * on the given platform than any we are expecting.  To fix that, add the
81  * prototype to the __DATA__ section of regen/reentr.pl.)
82  */
83
84 #ifndef PERL_REENTR_API
85 #  if defined(PERL_CORE) || defined(PERL_EXT) || defined(PERL_REENTRANT)
86 #    define PERL_REENTR_API 1
87 #  else
88 #    define PERL_REENTR_API 0
89 #  endif
90 #endif
91
92 #ifdef USE_REENTRANT_API
93
94 /* Deprecations: some platforms have the said reentrant interfaces
95  * but they are declared obsolete and are not to be used.  Often this
96  * means that the platform has threadsafed the interfaces (hopefully).
97  * All this is OS version dependent, so we are of course fooling ourselves.
98  * If you know of more deprecations on some platforms, please add your own
99  * (by editing reentr.pl, mind!) */
100
101 #  ifdef __hpux
102 #    undef HAS_CRYPT_R
103 #    undef HAS_ENDGRENT_R
104 #    undef HAS_ENDPWENT_R
105 #    undef HAS_GETGRENT_R
106 #    undef HAS_GETPWENT_R
107 #    undef HAS_SETLOCALE_R
108 #    undef HAS_STRERROR_R
109 #    define NETDB_R_OBSOLETE
110 #  endif
111
112 #  if defined(__osf__) && defined(__alpha) /* Tru64 aka Digital UNIX */
113 #    undef HAS_CRYPT_R
114 #    undef HAS_STRERROR_R
115 #    define NETDB_R_OBSOLETE
116 #  endif
117
118 #  if defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 24))
119 #    undef HAS_READDIR_R
120 #    undef HAS_READDIR64_R
121 #  endif
122
123 /*
124  * As of OpenBSD 3.7, reentrant functions are now working, they just are
125  * incompatible with everyone else.  To make OpenBSD happy, we have to
126  * memzero out certain structures before calling the functions.
127  */
128 #  if defined(__OpenBSD__)
129 #    define REENTR_MEMZERO(a,b) memzero(a,b)
130 #  else
131 #    define REENTR_MEMZERO(a,b) 0
132 #  endif
133
134 #  ifdef NETDB_R_OBSOLETE
135 #    undef HAS_ENDHOSTENT_R
136 #    undef HAS_ENDNETENT_R
137 #    undef HAS_ENDPROTOENT_R
138 #    undef HAS_ENDSERVENT_R
139 #    undef HAS_GETHOSTBYADDR_R
140 #    undef HAS_GETHOSTBYNAME_R
141 #    undef HAS_GETHOSTENT_R
142 #    undef HAS_GETNETBYADDR_R
143 #    undef HAS_GETNETBYNAME_R
144 #    undef HAS_GETNETENT_R
145 #    undef HAS_GETPROTOBYNAME_R
146 #    undef HAS_GETPROTOBYNUMBER_R
147 #    undef HAS_GETPROTOENT_R
148 #    undef HAS_GETSERVBYNAME_R
149 #    undef HAS_GETSERVBYPORT_R
150 #    undef HAS_GETSERVENT_R
151 #    undef HAS_SETHOSTENT_R
152 #    undef HAS_SETNETENT_R
153 #    undef HAS_SETPROTOENT_R
154 #    undef HAS_SETSERVENT_R
155 #  endif
156
157 #  ifdef I_PWD
158 #    include <pwd.h>
159 #  endif
160 #  ifdef I_GRP
161 #    include <grp.h>
162 #  endif
163 #  ifdef I_NETDB
164 #    include <netdb.h>
165 #  endif
166 #  ifdef I_CRYPT
167 #    ifdef I_CRYPT
168 #      include <crypt.h>
169 #    endif
170 #  endif
171 #  ifdef HAS_GETSPNAM_R
172 #    ifdef I_SHADOW
173 #      include <shadow.h>
174 #    endif
175 #  endif
176
177 EOF
178
179 my %seenh; # the different prototypes signatures for this function
180 my %seena; # the different prototypes signatures for this function in order
181 my @seenf; # all the seen functions
182 my %seenp; # the different prototype signatures for all functions
183 my %seent; # the return type of this function
184 my %seens; # the type of this function's "S"
185 my %seend; # the type of this function's "D"
186 my %seenm; # all the types
187 my %seenu; # the length of the argument list of this function
188
189 while (<DATA>) { # Read in the protoypes.
190     next if /^\s+$/;
191     chomp;
192     my ($func, $hdr, $type, @p) = split(/\s*\|\s*/, $_, -1);
193     my $u;
194     # Split off the real function name and the argument list.
195     ($func, $u) = split(' ', $func);
196     $seenu{$func} = defined $u ? length $u : 0;
197     my $FUNC = uc $func; # for output.
198     push @seenf, $func;
199     my %m = %map;
200     if ($type) {
201         $m{S} = "$type*";
202         $m{R} = "$type**";
203     }
204
205     # Set any special mapping variables (like X=x_t)
206     if (@p) {
207         while ($p[-1] =~ /=/) {
208             my ($k, $v) = ($p[-1] =~ /^([A-Za-z])\s*=\s*(.*)/);
209             $m{$k} = $v;
210             pop @p;
211         }
212     }
213
214     # If given the -U option open up the metaconfig unit for this function.
215     if ($opts{U} && open(U, ">", "d_${func}_r.U"))  {
216         binmode U;
217     }
218
219     if ($opts{U}) {
220         # The metaconfig units needs prerequisite dependencies.
221         my $prereqs  = '';
222         my $prereqh  = '';
223         my $prereqsh = '';
224         if ($hdr ne 'stdio') { # There's no i_stdio.
225             $prereqs  = "i_$hdr";
226             $prereqh  = "$hdr.h";
227             $prereqsh = "\$$prereqs $prereqh";
228         }
229         my @prereq = qw(Inlibc Protochk Hasproto i_systypes usethreads);
230         push @prereq, $prereqs;
231         my $hdrs = "\$i_systypes sys/types.h define stdio.h $prereqsh";
232         if ($hdr eq 'time') {
233             $hdrs .= " \$i_systime sys/time.h";
234             push @prereq, 'i_systime';
235         }
236         # Output the metaconfig unit header.
237         print U <<"EOF";
238 ?RCS: \$Id: d_${func}_r.U,v $
239 ?RCS:
240 ?RCS: Copyright (c) 2002,2003 Jarkko Hietaniemi
241 ?RCS:
242 ?RCS: You may distribute under the terms of either the GNU General Public
243 ?RCS: License or the Artistic License, as specified in the README file.
244 ?RCS:
245 ?RCS: Generated by the reentr.pl from the Perl 5.8 distribution.
246 ?RCS:
247 ?MAKE:d_${func}_r ${func}_r_proto: @prereq
248 ?MAKE:  -pick add \$@ %<
249 ?S:d_${func}_r:
250 ?S:     This variable conditionally defines the HAS_${FUNC}_R symbol,
251 ?S:     which indicates to the C program that the ${func}_r()
252 ?S:     routine is available.
253 ?S:.
254 ?S:${func}_r_proto:
255 ?S:     This variable encodes the prototype of ${func}_r.
256 ?S:     It is zero if d_${func}_r is undef, and one of the
257 ?S:     REENTRANT_PROTO_T_ABC macros of reentr.h if d_${func}_r
258 ?S:     is defined.
259 ?S:.
260 ?C:HAS_${FUNC}_R:
261 ?C:     This symbol, if defined, indicates that the ${func}_r routine
262 ?C:     is available to ${func} re-entrantly.
263 ?C:.
264 ?C:${FUNC}_R_PROTO:
265 ?C:     This symbol encodes the prototype of ${func}_r.
266 ?C:     It is zero if d_${func}_r is undef, and one of the
267 ?C:     REENTRANT_PROTO_T_ABC macros of reentr.h if d_${func}_r
268 ?C:     is defined.
269 ?C:.
270 ?H:#\$d_${func}_r HAS_${FUNC}_R    /**/
271 ?H:#define ${FUNC}_R_PROTO \$${func}_r_proto       /**/
272 ?H:.
273 ?T:try hdrs d_${func}_r_proto
274 ?LINT:set d_${func}_r
275 ?LINT:set ${func}_r_proto
276 : see if ${func}_r exists
277 set ${func}_r d_${func}_r
278 eval \$inlibc
279 case "\$d_${func}_r" in
280 "\$define")
281 EOF
282         print U <<"EOF";
283         hdrs="$hdrs"
284         case "\$d_${func}_r_proto:\$usethreads" in
285         ":define")      d_${func}_r_proto=define
286                 set d_${func}_r_proto ${func}_r \$hdrs
287                 eval \$hasproto ;;
288         *)      ;;
289         esac
290         case "\$d_${func}_r_proto" in
291         define)
292 EOF
293     }
294     for my $p (@p) {
295         my ($r, $a) = ($p =~ /^(.)_(.+)/);
296         my $v = join(", ", map { $m{$_} } split '', $a);
297         if ($opts{U}) {
298             print U <<"EOF";
299         case "\$${func}_r_proto" in
300         ''|0) try='$m{$r} ${func}_r($v);'
301         ./protochk "extern \$try" \$hdrs && ${func}_r_proto=$p ;;
302         esac
303 EOF
304         }
305         $seenh{$func}->{$p}++;
306         push @{$seena{$func}}, $p;
307         $seenp{$p}++;
308         $seent{$func} = $type;
309         $seens{$func} = $m{S};
310         $seend{$func} = $m{D};
311         $seenm{$func} = \%m;
312     }
313     if ($opts{U}) {
314         print U <<"EOF";
315         case "\$${func}_r_proto" in
316         ''|0)   d_${func}_r=undef
317                 ${func}_r_proto=0
318                 echo "Disabling ${func}_r, cannot determine prototype." >&4 ;;
319         * )     case "\$${func}_r_proto" in
320                 REENTRANT_PROTO*) ;;
321                 *) ${func}_r_proto="REENTRANT_PROTO_\$${func}_r_proto" ;;
322                 esac
323                 echo "Prototype: \$try" ;;
324         esac
325         ;;
326         *)      case "\$usethreads" in
327                 define) echo "${func}_r has no prototype, not using it." >&4 ;;
328                 esac
329                 d_${func}_r=undef
330                 ${func}_r_proto=0
331                 ;;
332         esac
333         ;;
334 *)      ${func}_r_proto=0
335         ;;
336 esac
337
338 EOF
339         close(U);
340     }
341 }
342
343 close DATA;
344
345 {
346     # Write out all the known prototype signatures.
347     my $i = 1;
348     for my $p (sort keys %seenp) {
349         print $h "#  define REENTRANT_PROTO_${p}        ${i}\n";
350         $i++;
351     }
352 }
353
354 my @struct; # REENTR struct members
355 my @size;   # struct member buffer size initialization code
356 my @init;   # struct member buffer initialization (malloc) code
357 my @free;   # struct member buffer release (free) code
358 my @wrap;   # the wrapper (foo(a) -> foo_r(a,...)) cpp code
359 my @define; # defines for optional features
360
361 sub ifprotomatch {
362     my $FUNC = shift;
363     join " || ", map { "${FUNC}_R_PROTO == REENTRANT_PROTO_$_" } @_;
364 }
365
366 sub pushssif {
367     push @struct, @_;
368     push @size, @_;
369     push @init, @_;
370     push @free, @_;
371 }
372
373 sub pushinitfree {
374     my $func = shift;
375     push @init, <<EOF;
376         Newx(PL_reentrant_buffer->_${func}_buffer, PL_reentrant_buffer->_${func}_size, char);
377 EOF
378     push @free, <<EOF;
379         Safefree(PL_reentrant_buffer->_${func}_buffer);
380 EOF
381 }
382
383 sub define {
384     my ($n, $p, @F) = @_;
385     my @H;
386     my $H = uc $F[0];
387     push @define, <<EOF;
388 /* The @F using \L$n? */
389
390 EOF
391     my $GENFUNC;
392     for my $func (@F) {
393         my $FUNC = uc $func;
394         my $HAS = "${FUNC}_R_HAS_$n";
395         push @H, $HAS;
396         my @h = grep { /$p/ } @{$seena{$func}};
397         unless (defined $GENFUNC) {
398             $GENFUNC = $FUNC;
399             $GENFUNC =~ s/^GET//;
400         }
401         if (@h) {
402             push @define, "#  if defined(HAS_${FUNC}_R) && (" . join(" || ", map { "${FUNC}_R_PROTO == REENTRANT_PROTO_$_" } @h) . ")\n";
403
404             push @define, <<EOF;
405 #    define $HAS
406 #  else
407 #    undef  $HAS
408 #  endif
409 EOF
410         }
411     }
412     return if @F == 1;
413     push @define, <<EOF;
414
415 /* Any of the @F using \L$n? */
416
417 EOF
418     push @define, "#  if (" . join(" || ", map { "defined($_)" } @H) . ")\n";
419     push @define, <<EOF;
420 #    define USE_${GENFUNC}_$n
421 #  else
422 #    undef  USE_${GENFUNC}_$n
423 #  endif
424
425 EOF
426 }
427
428 define('BUFFER',  'B',
429        qw(getgrent getgrgid getgrnam));
430
431 define('PTR',  'R',
432        qw(getgrent getgrgid getgrnam));
433 define('PTR',  'R',
434        qw(getpwent getpwnam getpwuid));
435 define('PTR',  'R',
436        qw(getspent getspnam));
437
438 define('FPTR', 'H',
439        qw(getgrent getgrgid getgrnam setgrent endgrent));
440 define('FPTR', 'H',
441        qw(getpwent getpwnam getpwuid setpwent endpwent));
442
443 define('BUFFER',  'B',
444        qw(getpwent getpwgid getpwnam));
445
446 define('BUFFER',  'B',
447        qw(getspent getspnam));
448
449 define('PTR', 'R',
450        qw(gethostent gethostbyaddr gethostbyname));
451 define('PTR', 'R',
452        qw(getnetent getnetbyaddr getnetbyname));
453 define('PTR', 'R',
454        qw(getprotoent getprotobyname getprotobynumber));
455 define('PTR', 'R',
456        qw(getservent getservbyname getservbyport));
457
458 define('BUFFER', 'B',
459        qw(gethostent gethostbyaddr gethostbyname));
460 define('BUFFER', 'B',
461        qw(getnetent getnetbyaddr getnetbyname));
462 define('BUFFER', 'B',
463        qw(getprotoent getprotobyname getprotobynumber));
464 define('BUFFER', 'B',
465        qw(getservent getservbyname getservbyport));
466
467 define('ERRNO', 'E',
468        qw(gethostent gethostbyaddr gethostbyname));
469 define('ERRNO', 'E',
470        qw(getnetent getnetbyaddr getnetbyname));
471
472 # The following loop accumulates the "ssif" (struct, size, init, free)
473 # sections that declare the struct members (in reentr.h), and the buffer
474 # size initialization, buffer initialization (malloc), and buffer
475 # release (free) code (in reentr.c).
476 #
477 # The loop also contains a lot of intrinsic logic about groups of
478 # functions (since functions of certain kind operate the same way).
479
480 for my $func (@seenf) {
481     my $FUNC = uc $func;
482     my $ifdef = "#  ifdef HAS_${FUNC}_R\n";
483     my $endif = "#  endif /* HAS_${FUNC}_R */\n\n";
484     if (exists $seena{$func}) {
485         my @p = @{$seena{$func}};
486         if ($func =~ /^(asctime|ctime|getlogin|setlocale|strerror|ttyname)$/) {
487             pushssif $ifdef;
488             push @struct, <<EOF;
489         char*   _${func}_buffer;
490         size_t  _${func}_size;
491 EOF
492             push @size, <<EOF;
493         PL_reentrant_buffer->_${func}_size = REENTRANTSMALLSIZE;
494 EOF
495             pushinitfree $func;
496             pushssif $endif;
497         }
498         elsif ($func =~ /^(gm|local)time$/) {
499             pushssif $ifdef;
500             push @struct, <<EOF;    # Fixed size
501         $seent{$func} _${func}_struct;
502 EOF
503             pushssif $endif;
504         }
505         elsif ($func =~ /^(crypt)$/) {
506             pushssif $ifdef;
507             push @struct, <<EOF;
508 #  if CRYPT_R_PROTO == REENTRANT_PROTO_B_CCD
509         $seend{$func} _${func}_data;
510 #  else
511         $seent{$func} *_${func}_struct_buffer;
512 #  endif
513 EOF
514             push @init, <<EOF;
515 #  if CRYPT_R_PROTO != REENTRANT_PROTO_B_CCD
516         PL_reentrant_buffer->_${func}_struct_buffer = 0;
517 #  endif
518 EOF
519             push @free, <<EOF;
520 #  if CRYPT_R_PROTO != REENTRANT_PROTO_B_CCD
521         Safefree(PL_reentrant_buffer->_${func}_struct_buffer);
522 #  endif
523 EOF
524             pushssif $endif;
525         }
526         elsif ($func =~ /^(getgrnam|getpwnam|getspnam)$/) {
527             pushssif $ifdef;
528             # 'genfunc' can be read either as 'generic' or 'genre',
529             # it represents a group of functions.
530             my $genfunc = $func;
531             $genfunc =~ s/nam/ent/g;
532             $genfunc =~ s/^get//;
533             my $GENFUNC = uc $genfunc;
534             push @struct, <<EOF;
535         $seent{$func}   _${genfunc}_struct;
536         char*   _${genfunc}_buffer;
537         size_t  _${genfunc}_size;
538 EOF
539             push @struct, <<EOF;
540 #   ifdef USE_${GENFUNC}_PTR
541         $seent{$func}*  _${genfunc}_ptr;
542 #   endif
543 EOF
544             push @struct, <<EOF;
545 #   ifdef USE_${GENFUNC}_FPTR
546         FILE*   _${genfunc}_fptr;
547 #   endif
548 EOF
549             push @init, <<EOF;
550 #   ifdef USE_${GENFUNC}_FPTR
551         PL_reentrant_buffer->_${genfunc}_fptr = NULL;
552 #   endif
553 EOF
554             my $sc = $genfunc eq 'grent' ?
555                     '_SC_GETGR_R_SIZE_MAX' : '_SC_GETPW_R_SIZE_MAX';
556             my $sz = "_${genfunc}_size";
557             push @size, <<EOF;
558 #    if defined(HAS_SYSCONF) && defined($sc) && !defined(__GLIBC__)
559         PL_reentrant_buffer->$sz = sysconf($sc);
560         if (PL_reentrant_buffer->$sz == (size_t) -1)
561                 PL_reentrant_buffer->$sz = REENTRANTUSUALSIZE;
562 #    elif defined(__osf__) && defined(__alpha) && defined(SIABUFSIZ)
563         PL_reentrant_buffer->$sz = SIABUFSIZ;
564 #    elif defined(__sgi)
565         PL_reentrant_buffer->$sz = BUFSIZ;
566 #    else
567         PL_reentrant_buffer->$sz = REENTRANTUSUALSIZE;
568 #    endif
569 EOF
570             pushinitfree $genfunc;
571             pushssif $endif;
572         }
573         elsif ($func =~ /^(gethostbyname|getnetbyname|getservbyname|getprotobyname)$/) {
574             pushssif $ifdef;
575             my $genfunc = $func;
576             $genfunc =~ s/byname/ent/;
577             $genfunc =~ s/^get//;
578             my $GENFUNC = uc $genfunc;
579             my $D = ifprotomatch($FUNC, grep {/D/} @p);
580             my $d = $seend{$func};
581             $d =~ s/\*$//; # snip: we need the base type.
582             push @struct, <<EOF;
583         $seent{$func}   _${genfunc}_struct;
584 #   if $D
585         $d      _${genfunc}_data;
586 #   else
587         char*   _${genfunc}_buffer;
588         size_t  _${genfunc}_size;
589 #   endif
590 #   ifdef USE_${GENFUNC}_PTR
591         $seent{$func}*  _${genfunc}_ptr;
592 #   endif
593 EOF
594             push @struct, <<EOF;
595 #   ifdef USE_${GENFUNC}_ERRNO
596         int     _${genfunc}_errno;
597 #   endif
598 EOF
599             push @size, <<EOF;
600 #  if !($D)
601         PL_reentrant_buffer->_${genfunc}_size = REENTRANTUSUALSIZE;
602 #  endif
603 EOF
604             push @init, <<EOF;
605 #  if !($D)
606         Newx(PL_reentrant_buffer->_${genfunc}_buffer, PL_reentrant_buffer->_${genfunc}_size, char);
607 #  endif
608 EOF
609             push @free, <<EOF;
610 #  if !($D)
611         Safefree(PL_reentrant_buffer->_${genfunc}_buffer);
612 #  endif
613 EOF
614             pushssif $endif;
615         }
616         elsif ($func =~ /^(readdir|readdir64)$/) {
617             pushssif $ifdef;
618             my $R = ifprotomatch($FUNC, grep {/R/} @p);
619             push @struct, <<EOF;
620         $seent{$func}*  _${func}_struct;
621         size_t  _${func}_size;
622 #   if $R
623         $seent{$func}*  _${func}_ptr;
624 #   endif
625 EOF
626             push @size, <<EOF;
627         /* This is the size Solaris recommends.
628          * (though we go static, should use pathconf() instead) */
629         PL_reentrant_buffer->_${func}_size = sizeof($seent{$func}) + MAXPATHLEN + 1;
630 EOF
631             push @init, <<EOF;
632         PL_reentrant_buffer->_${func}_struct = ($seent{$func}*)safemalloc(PL_reentrant_buffer->_${func}_size);
633 EOF
634             push @free, <<EOF;
635         Safefree(PL_reentrant_buffer->_${func}_struct);
636 EOF
637             pushssif $endif;
638         }
639
640         push @wrap, $ifdef;
641
642         push @wrap, <<EOF;
643 #    if defined(PERL_REENTR_API) && (PERL_REENTR_API+0 == 1)
644 #      undef $func
645 EOF
646
647         # Write out what we have learned.
648         
649         my @v = 'a'..'z';
650         my $v = join(", ", @v[0..$seenu{$func}-1]);
651         for my $p (@p) {
652             my ($r, $a) = split '_', $p;
653             my $test = $r eq 'I' ? ' == 0' : '';
654             my $true  = 1;
655             my $genfunc = $func;
656             if ($genfunc =~ /^(?:get|set|end)(pw|gr|host|net|proto|serv|sp)/) {
657                 $genfunc = "${1}ent";
658             }
659             my $b = $a;
660             my $w = '';
661             substr($b, 0, $seenu{$func}) = '';
662             if ($b =~ /R/) {
663                 $true = "PL_reentrant_buffer->_${genfunc}_ptr";
664             } elsif ($b =~ /S/) {
665                 if ($func =~ /^readdir/) {
666                     $true = "PL_reentrant_buffer->_${genfunc}_struct";
667                 } else {
668                     $true = "&PL_reentrant_buffer->_${genfunc}_struct";
669                 }
670             } elsif ($b =~ /B/) {
671                 $true = "PL_reentrant_buffer->_${genfunc}_buffer";
672             }
673             if (length $b) {
674                 $w = join ", ",
675                          map {
676                              $_ eq 'R' ?
677                                  "&PL_reentrant_buffer->_${genfunc}_ptr" :
678                              $_ eq 'E' ?
679                                  "&PL_reentrant_buffer->_${genfunc}_errno" :
680                              $_ eq 'B' ?
681                                  "PL_reentrant_buffer->_${genfunc}_buffer" :
682                              $_ =~ /^[WI]$/ ?
683                                  "PL_reentrant_buffer->_${genfunc}_size" :
684                              $_ eq 'H' ?
685                                  "&PL_reentrant_buffer->_${genfunc}_fptr" :
686                              $_ eq 'D' ?
687                                  "&PL_reentrant_buffer->_${genfunc}_data" :
688                              $_ eq 'S' ?
689                                  ($func =~ /^readdir\d*$/ ?
690                                   "PL_reentrant_buffer->_${genfunc}_struct" :
691                                   $func =~ /^crypt$/ ?
692                                   "PL_reentrant_buffer->_${genfunc}_struct_buffer" :
693                                   "&PL_reentrant_buffer->_${genfunc}_struct") :
694                                  $_
695                          } split '', $b;
696                 $w = ", $w" if length $v;
697             }
698
699             # This needs a special case, see its definition in config.h
700             my $setup = ($func eq 'localtime') ? "L_R_TZSET " : "";
701
702             my $call = "$setup${func}_r($v$w)";
703
704             # Must make OpenBSD happy
705             my $memzero = '';
706             if($p =~ /D$/ &&
707                 ($genfunc eq 'protoent' || $genfunc eq 'servent')) {
708                 $memzero = 'REENTR_MEMZERO(&PL_reentrant_buffer->_' . $genfunc . '_data, sizeof(PL_reentrant_buffer->_' . $genfunc . '_data)),';
709             }
710             push @wrap, <<EOF;
711 #      if !defined($func) && ${FUNC}_R_PROTO == REENTRANT_PROTO_$p
712 EOF
713             if ($r eq 'V' || $r eq 'B') {
714                 push @wrap, <<EOF;
715 #        define $func($v) $call
716 EOF
717             } else {
718                 if ($func =~ /^get/) {
719                     my $rv = $v ? ", $v" : "";
720                     if ($r eq 'I') {
721                         push @wrap, <<EOF;
722 #        define $func($v) ($memzero(PL_reentrant_retint = $call)$test ? $true : ((PL_reentrant_retint == ERANGE) ? ($seent{$func} *) Perl_reentrant_retry("$func"$rv) : 0))
723 EOF
724                     } else {
725                         push @wrap, <<EOF;
726 #        define $func($v) ($call$test ? $true : ((errno == ERANGE) ? ($seent{$func} *) Perl_reentrant_retry("$func"$rv) : 0))
727 EOF
728                     }
729                 } else {
730                     push @wrap, <<EOF;
731 #        define $func($v) ($call$test ? $true : 0)
732 EOF
733                 }
734             }
735             push @wrap, <<EOF;  #  !defined(xxx) && XXX_R_PROTO == REENTRANT_PROTO_Y_TS
736 #      endif
737 EOF
738         }
739                     push @wrap, <<EOF;
740 #      if defined($func)
741 #        define PERL_REENTR_USING_${FUNC}_R
742 #      endif
743 EOF
744
745             push @wrap, <<EOF;  #  defined(PERL_REENTR_API) && (PERL_REENTR_API+0 == 1)
746 #    endif
747 EOF
748
749         push @wrap, $endif, "\n";
750     }
751 }
752
753 local $" = '';
754
755 print $h <<EOF;
756
757 /* Defines for indicating which special features are supported. */
758
759 @define
760 typedef struct {
761
762 @struct
763     int dummy; /* cannot have empty structs */
764 } REENTR;
765
766 /* The wrappers. */
767
768 @wrap
769
770 /* Special case this; if others came along, could automate it */
771 #  ifdef HAS_GETSPNAM_R
772 #    define KEY_getspnam -1
773 #  endif
774
775 #endif /* USE_REENTRANT_API */
776
777 #endif
778 EOF
779
780 read_only_bottom_close_and_rename($h);
781
782 # Prepare to write the reentr.c.
783
784 my $c = open_print_header('reentr.c', <<'EOQ');
785  */
786
787 /*
788  * "Saruman," I said, standing away from him, "only one hand at a time can
789  *  wield the One, and you know that well, so do not trouble to say we!"
790  *
791  *     [p.260 of _The Lord of the Rings_, II/ii: "The Council of Elrond"]
792  */
793
794 /*
795  * This file contains a collection of automatically created wrappers
796  * (created by running reentr.pl) for reentrant (thread-safe) versions of
797  * various library calls, such as getpwent_r.  The wrapping is done so
798  * that other files like pp_sys.c calling those library functions need not
799  * care about the differences between various platforms' idiosyncrasies
800  * regarding these reentrant interfaces.
801  */
802 EOQ
803
804 print $c <<"EOF";
805 #include "EXTERN.h"
806 #define PERL_IN_REENTR_C
807 #include "perl.h"
808 #include "reentr.h"
809 #include "keywords.h"
810
811 #define RenewDouble(data_pointer, size_pointer, type) \\
812     STMT_START { \\
813         const size_t size = *(size_pointer) * 2; \\
814         Renew((data_pointer), (size), type); \\
815         *(size_pointer) = size; \\
816     } STMT_END
817
818 void
819 Perl_reentrant_size(pTHX) {
820         PERL_UNUSED_CONTEXT;
821
822         /* Set the sizes of the reentrant buffers */
823
824 #ifdef USE_REENTRANT_API
825 #  define REENTRANTSMALLSIZE     256    /* Make something up. */
826 #  define REENTRANTUSUALSIZE    4096    /* Make something up. */
827
828 @size
829 #endif /* USE_REENTRANT_API */
830
831 }
832
833 void
834 Perl_reentrant_init(pTHX) {
835         PERL_UNUSED_CONTEXT;
836
837         /* Initialize the whole thing */
838
839 #ifdef USE_REENTRANT_API
840
841         Newx(PL_reentrant_buffer, 1, REENTR);
842         Perl_reentrant_size(aTHX);
843
844 @init
845 #endif /* USE_REENTRANT_API */
846
847 }
848
849 void
850 Perl_reentrant_free(pTHX) {
851         PERL_UNUSED_CONTEXT;
852
853         /* Tear down */
854
855 #ifdef USE_REENTRANT_API
856
857 @free
858         Safefree(PL_reentrant_buffer);
859
860 #endif /* USE_REENTRANT_API */
861 }
862
863 void*
864 Perl_reentrant_retry(const char *f, ...)
865 {
866     /* This function is set up to be called if the normal function returns
867      * failure with errno ERANGE, which indicates the buffer is too small.
868      * This function calls the failing one again with a larger buffer.
869      *
870      * What has happened is that, due to the magic of C preprocessor macro
871      * expansion, when the original code called function 'foo(args)', it was
872      * instead compiled into something like a call of 'foo_r(args, buffer)'
873      * Below we retry with 'foo', but the preprocessor has changed that into
874      * 'foo_r', so this function will end up calling itself recursively, each
875      * time with a larger buffer.  If PERL_REENTRANT_MAXSIZE is defined, it
876      * won't increase beyond that, instead failing. */
877
878     void *retptr = NULL;
879     va_list ap;
880
881     I32 key = 0;
882
883 #ifdef USE_REENTRANT_API
884
885     dTHX;
886
887     key = Perl_keyword (aTHX_ f, strlen(f), FALSE /* not feature enabled */);
888
889     /* Easier to special case this here than in embed.pl. (Look at what it
890        generates for proto.h) */
891     PERL_ARGS_ASSERT_REENTRANT_RETRY;
892
893 #endif
894
895     if (key == 0) {
896
897 #ifdef HAS_GETSPNAM_R
898
899         /* This is a #define as has no corresponding keyword */
900         if (strEQ(f, "getspnam")) {
901             key = KEY_getspnam;
902         }
903
904 #endif
905
906     }
907     else if (key < 0) {
908         key = -key;
909     }
910
911     va_start(ap, f);
912
913 #ifdef USE_REENTRANT_API
914
915     switch (key) {
916
917 #  ifdef USE_HOSTENT_BUFFER
918
919     case KEY_gethostbyaddr:
920     case KEY_gethostbyname:
921     case KEY_endhostent:
922         {
923             char * host_addr;
924             Size_t asize;
925             char * host_name;
926             int anint;
927
928 #    ifdef PERL_REENTRANT_MAXSIZE
929             if (PL_reentrant_buffer->_hostent_size <=
930                 PERL_REENTRANT_MAXSIZE / 2)
931 #    endif
932             RenewDouble(PL_reentrant_buffer->_hostent_buffer,
933                     &PL_reentrant_buffer->_hostent_size, char);
934             switch (key) {
935                 case KEY_gethostbyaddr:
936                     host_addr = va_arg(ap, char *);
937                     asize = va_arg(ap, Size_t);
938                     anint  = va_arg(ap, int);
939                     /* socklen_t is what Posix 2001 says this should be */
940                     retptr = gethostbyaddr(host_addr, (socklen_t) asize, anint); break;
941                 case KEY_gethostbyname:
942                     host_name = va_arg(ap, char *);
943                     retptr = gethostbyname(host_name); break;
944                 case KEY_endhostent:
945                     retptr = gethostent(); break;
946                 default:
947                     SETERRNO(ERANGE, LIB_INVARG);
948                     break;
949             }
950         }
951         break;
952
953 #  endif
954 #  ifdef USE_GRENT_BUFFER
955
956     case KEY_getgrent:
957     case KEY_getgrgid:
958     case KEY_getgrnam:
959         {
960             char * name;
961             Gid_t gid;
962
963 #    ifdef PERL_REENTRANT_MAXSIZE
964             if (PL_reentrant_buffer->_grent_size <=
965                 PERL_REENTRANT_MAXSIZE / 2)
966 #    endif
967             RenewDouble(PL_reentrant_buffer->_grent_buffer,
968                     &PL_reentrant_buffer->_grent_size, char);
969             switch (key) {
970                 case KEY_getgrnam:
971                     name = va_arg(ap, char *);
972                     retptr = getgrnam(name); break;
973                 case KEY_getgrgid:
974 #    if Gid_t_size < INTSIZE
975                     gid = (Gid_t)va_arg(ap, int);
976 #    else
977                     gid = va_arg(ap, Gid_t);
978 #    endif
979                     retptr = getgrgid(gid); break;
980                 case KEY_getgrent:
981                     retptr = getgrent(); break;
982                 default:
983                     SETERRNO(ERANGE, LIB_INVARG);
984                     break;
985             }
986         }
987         break;
988
989 #  endif
990 #  ifdef USE_NETENT_BUFFER
991
992     case KEY_getnetbyaddr:
993     case KEY_getnetbyname:
994     case KEY_getnetent:
995         {
996             char * name;
997             Netdb_net_t net;
998             int anint;
999
1000 #    ifdef PERL_REENTRANT_MAXSIZE
1001             if (PL_reentrant_buffer->_netent_size <=
1002                 PERL_REENTRANT_MAXSIZE / 2)
1003 #    endif
1004             RenewDouble(PL_reentrant_buffer->_netent_buffer,
1005                     &PL_reentrant_buffer->_netent_size, char);
1006             switch (key) {
1007                 case KEY_getnetbyaddr:
1008                     net = va_arg(ap, Netdb_net_t);
1009                     anint = va_arg(ap, int);
1010                     retptr = getnetbyaddr(net, anint); break;
1011                 case KEY_getnetbyname:
1012                     name = va_arg(ap, char *);
1013                     retptr = getnetbyname(name); break;
1014                 case KEY_getnetent:
1015                     retptr = getnetent(); break;
1016                 default:
1017                     SETERRNO(ERANGE, LIB_INVARG);
1018                     break;
1019             }
1020         }
1021         break;
1022
1023 #  endif
1024 #  ifdef USE_PWENT_BUFFER
1025
1026     case  KEY_getpwnam:
1027     case  KEY_getpwuid:
1028     case  KEY_getpwent:
1029         {
1030             Uid_t uid;
1031             char * name;
1032
1033 #    ifdef PERL_REENTRANT_MAXSIZE
1034             if (PL_reentrant_buffer->_pwent_size <=
1035                 PERL_REENTRANT_MAXSIZE / 2)
1036
1037 #    endif
1038             RenewDouble(PL_reentrant_buffer->_pwent_buffer,
1039                     &PL_reentrant_buffer->_pwent_size, char);
1040             switch (key) {
1041                 case KEY_getpwnam:
1042                     name = va_arg(ap, char *);
1043                     retptr = getpwnam(name); break;
1044                 case KEY_getpwuid:
1045
1046 #    if Uid_t_size < INTSIZE
1047                     uid = (Uid_t)va_arg(ap, int);
1048 #    else
1049                     uid = va_arg(ap, Uid_t);
1050 #    endif
1051                     retptr = getpwuid(uid); break;
1052
1053 #  if defined(HAS_GETPWENT) || defined(HAS_GETPWENT_R)
1054
1055                 case KEY_getpwent:
1056                     retptr = getpwent(); break;
1057 #  endif
1058                 default:
1059                     SETERRNO(ERANGE, LIB_INVARG);
1060                     break;
1061             }
1062         }
1063         break;
1064
1065 #  endif
1066 #  ifdef USE_SPENT_BUFFER
1067
1068     case KEY_getspnam:
1069         {
1070             char * name;
1071
1072 #    ifdef PERL_REENTRANT_MAXSIZE
1073             if (PL_reentrant_buffer->_spent_size <=
1074                 PERL_REENTRANT_MAXSIZE / 2)
1075
1076 #    endif
1077             RenewDouble(PL_reentrant_buffer->_spent_buffer,
1078                     &PL_reentrant_buffer->_spent_size, char);
1079             switch (key) {
1080                 case KEY_getspnam:
1081                     name = va_arg(ap, char *);
1082                     retptr = getspnam(name); break;
1083                 default:
1084                     SETERRNO(ERANGE, LIB_INVARG);
1085                     break;
1086             }
1087         }
1088         break;
1089
1090 #  endif
1091 #  ifdef USE_PROTOENT_BUFFER
1092
1093     case KEY_getprotobyname:
1094     case KEY_getprotobynumber:
1095     case KEY_getprotoent:
1096         {
1097             char * name;
1098             int anint;
1099
1100 #    ifdef PERL_REENTRANT_MAXSIZE
1101             if (PL_reentrant_buffer->_protoent_size <=
1102                 PERL_REENTRANT_MAXSIZE / 2)
1103 #    endif
1104             RenewDouble(PL_reentrant_buffer->_protoent_buffer,
1105                     &PL_reentrant_buffer->_protoent_size, char);
1106             switch (key) {
1107                 case KEY_getprotobyname:
1108                     name = va_arg(ap, char *);
1109                     retptr = getprotobyname(name); break;
1110                 case KEY_getprotobynumber:
1111                     anint = va_arg(ap, int);
1112                     retptr = getprotobynumber(anint); break;
1113                 case KEY_getprotoent:
1114                     retptr = getprotoent(); break;
1115                 default:
1116                     SETERRNO(ERANGE, LIB_INVARG);
1117                     break;
1118             }
1119         }
1120         break;
1121
1122 #  endif
1123 #  ifdef USE_SERVENT_BUFFER
1124
1125     case KEY_getservbyname:
1126     case KEY_getservbyport:
1127     case KEY_getservent:
1128         {
1129             char * name;
1130             char * proto;
1131             int anint;
1132
1133 #    ifdef PERL_REENTRANT_MAXSIZE
1134             if (PL_reentrant_buffer->_servent_size <=
1135                 PERL_REENTRANT_MAXSIZE / 2)
1136 #    endif
1137             RenewDouble(PL_reentrant_buffer->_servent_buffer,
1138                     &PL_reentrant_buffer->_servent_size, char);
1139             switch (key) {
1140                 case KEY_getservbyname:
1141                     name = va_arg(ap, char *);
1142                     proto = va_arg(ap, char *);
1143                     retptr = getservbyname(name, proto); break;
1144                 case KEY_getservbyport:
1145                     anint = va_arg(ap, int);
1146                     name = va_arg(ap, char *);
1147                     retptr = getservbyport(anint, name); break;
1148                 case KEY_getservent:
1149                     retptr = getservent(); break;
1150                 default:
1151                     SETERRNO(ERANGE, LIB_INVARG);
1152                     break;
1153             }
1154         }
1155         break;
1156
1157 #  endif
1158
1159     default:
1160         /* Not known how to retry, so just fail. */
1161         break;
1162     }
1163
1164 #else
1165
1166     PERL_UNUSED_ARG(f);
1167
1168 #endif
1169
1170     va_end(ap);
1171     return retptr;
1172 }
1173 EOF
1174
1175 read_only_bottom_close_and_rename($c);
1176
1177 # The meanings of the flags are derivable from %map above
1178 # Fnc, arg flags| hdr   | ? struct type | prototypes...
1179 __DATA__
1180 asctime S       |time   |const struct tm|B_SB|B_SBI|I_SB|I_SBI
1181 crypt CC        |crypt  |struct crypt_data|B_CCS|B_CCD|D=CRYPTD*
1182 ctermid B       |stdio  |               |B_B
1183 ctime S         |time   |const time_t   |B_SB|B_SBI|I_SB|I_SBI
1184 endgrent        |grp    |               |I_H|V_H
1185 endhostent      |netdb  |               |I_D|V_D|D=struct hostent_data*
1186 endnetent       |netdb  |               |I_D|V_D|D=struct netent_data*
1187 endprotoent     |netdb  |               |I_D|V_D|D=struct protoent_data*
1188 endpwent        |pwd    |               |I_H|V_H
1189 endservent      |netdb  |               |I_D|V_D|D=struct servent_data*
1190 getgrent        |grp    |struct group   |I_SBWR|I_SBIR|S_SBW|S_SBI|I_SBI|I_SBIH
1191 getgrgid T      |grp    |struct group   |I_TSBWR|I_TSBIR|I_TSBI|S_TSBI|T=gid_t
1192 getgrnam C      |grp    |struct group   |I_CSBWR|I_CSBIR|S_CBI|I_CSBI|S_CSBI
1193 gethostbyaddr CWI       |netdb  |struct hostent |I_CWISBWRE|S_CWISBWIE|S_CWISBIE|S_TWISBIE|S_CIISBIE|S_CSBIE|S_TSBIE|I_CWISD|I_CIISD|I_CII|I_TsISBWRE|D=struct hostent_data*|T=const void*|s=socklen_t
1194 gethostbyname C |netdb  |struct hostent |I_CSBWRE|S_CSBIE|I_CSD|D=struct hostent_data*
1195 gethostent      |netdb  |struct hostent |I_SBWRE|I_SBIE|S_SBIE|S_SBI|I_SBI|I_SD|D=struct hostent_data*
1196 getlogin        |unistd |char           |I_BW|I_BI|B_BW|B_BI
1197 getnetbyaddr LI |netdb  |struct netent  |I_UISBWRE|I_LISBI|S_TISBI|S_LISBI|I_TISD|I_LISD|I_IISD|I_uISBWRE|D=struct netent_data*|T=in_addr_t|U=unsigned long|u=uint32_t
1198 getnetbyname C  |netdb  |struct netent  |I_CSBWRE|I_CSBI|S_CSBI|I_CSD|D=struct netent_data*
1199 getnetent       |netdb  |struct netent  |I_SBWRE|I_SBIE|S_SBIE|S_SBI|I_SBI|I_SD|D=struct netent_data*
1200 getprotobyname C|netdb  |struct protoent|I_CSBWR|S_CSBI|I_CSD|D=struct protoent_data*
1201 getprotobynumber I      |netdb  |struct protoent|I_ISBWR|S_ISBI|I_ISD|D=struct protoent_data*
1202 getprotoent     |netdb  |struct protoent|I_SBWR|I_SBI|S_SBI|I_SD|D=struct protoent_data*
1203 getpwent        |pwd    |struct passwd  |I_SBWR|I_SBIR|S_SBW|S_SBI|I_SBI|I_SBIH
1204 getpwnam C      |pwd    |struct passwd  |I_CSBWR|I_CSBIR|S_CSBI|I_CSBI
1205 getpwuid T      |pwd    |struct passwd  |I_TSBWR|I_TSBIR|I_TSBI|S_TSBI|T=uid_t
1206 getservbyname CC|netdb  |struct servent |I_CCSBWR|S_CCSBI|I_CCSD|D=struct servent_data*
1207 getservbyport IC|netdb  |struct servent |I_ICSBWR|S_ICSBI|I_ICSD|D=struct servent_data*
1208 getservent      |netdb  |struct servent |I_SBWR|I_SBI|S_SBI|I_SD|D=struct servent_data*
1209 getspnam C      |shadow |struct spwd    |I_CSBWR|S_CSBI
1210 gmtime T        |time   |struct tm      |S_TS|T=time_t*
1211 localtime T     |time   |struct tm      |S_TS|T=time_t*
1212 readdir T       |dirent |struct dirent  |I_TSR|I_TS|T=DIR*
1213 readdir64 T     |dirent |struct dirent64|I_TSR|I_TS|T=DIR*
1214 setgrent        |grp    |               |I_H|V_H
1215 sethostent I    |netdb  |               |I_ID|V_ID|D=struct hostent_data*
1216 setlocale IC    |locale |               |I_ICBI
1217 setnetent I     |netdb  |               |I_ID|V_ID|D=struct netent_data*
1218 setprotoent I   |netdb  |               |I_ID|V_ID|D=struct protoent_data*
1219 setpwent        |pwd    |               |I_H|V_H
1220 setservent I    |netdb  |               |I_ID|V_ID|D=struct servent_data*
1221 strerror I      |string |               |I_IBW|I_IBI|B_IBW
1222 tmpnam B        |stdio  |               |B_B
1223 ttyname I       |unistd |               |I_IBW|I_IBI|B_IBI