#!/usr/bin/perl -w # # Generate the reentr.c and reentr.h, # and optionally also the relevant metaconfig units (-U option). # use strict; use Getopt::Std; my %opts; getopts('U', \%opts); my %map = ( V => "void", A => "char*", # as an input argument B => "char*", # as an output argument C => "const char*", # as a read-only input argument I => "int", L => "long", W => "size_t", H => "FILE**", E => "int*", ); # (See the definitions after __DATA__.) # In func|inc|type|... a "S" means "type*", and a "R" means "type**". # (The "types" are often structs, such as "struct passwd".) # # After the prototypes one can have |X=...|Y=... to define more types. # A commonly used extra type is to define D to be equal to "type_data", # for example "struct_hostent_data to" go with "struct hostent". # # Example #1: I_XSBWR means int func_r(X, type, char*, size_t, type**) # Example #2: S_SBIE means type func_r(type, char*, int, int*) # Example #3: S_CBI means type func_r(const char*, char*, int) die "reentr.h: $!" unless open(H, ">reentr.h"); select H; print < #endif #ifdef I_GRP # include #endif #ifdef I_NETDB # include #endif #ifdef I_STDLIB # include /* drand48_data */ #endif #ifdef I_CRYPT # ifdef I_CRYPT # include # endif #endif #ifdef HAS_GETSPNAM_R # ifdef I_SHADOW # include # endif #endif EOF my %seenh; my %seena; my @seenf; my %seenp; my %seent; my %seens; my %seend; my %seenu; while () { next if /^\s+$/; chomp; my ($f, $h, $t, @p) = split(/\s*\|\s*/, $_, -1); my $u; ($f, $u) = split(' ', $f); $seenu{$f} = defined $u ? length $u : 0; my $F = uc $f; push @seenf, $f; my %m = %map; if ($t) { $m{S} = "$t*"; $m{R} = "$t**"; } if (@p) { while ($p[-1] =~ /=/) { my ($k, $v) = ($p[-1] =~ /^([A-Za-z])\s*=\s*(.*)/); $m{$k} = $v; pop @p; } } if ($opts{U} && open(U, ">d_${f}_r.U")) { select U; } my $prereqs = ''; my $prereqh = ''; my $prereqsh = ''; if ($h ne 'stdio') { # There's no i_stdio. $prereqs = "i_$h"; $prereqh = "$h.h"; $prereqsh = "\$$prereqs $prereqh"; } if ($opts{U}) { my @prereq = qw(Inlibc Protochk Hasproto i_systypes usethreads); push @prereq, $prereqs; my $hdrs = "\$i_systypes sys/types.h define stdio.h $prereqsh"; if ($h eq 'time') { $hdrs .= " \$i_systime sys/time.h"; push @prereq, 'i_systime'; } print <{$p}++; push @{$seena{$f}}, $p; $seenp{$p}++; $seent{$f} = $t; $seens{$f} = $m{S}; $seend{$f} = $m{D}; } if ($opts{U}) { print <&4 ;; * ) case "\$${f}_r_proto" in REENTRANT_PROTO*) ;; *) ${f}_r_proto="REENTRANT_PROTO_\$${f}_r_proto" ;; esac 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 EOF close(U); } } close DATA; select H; { my $i = 1; for my $p (sort keys %seenp) { print "#define REENTRANT_PROTO_${p} ${i}\n"; $i++; } } sub ifprotomatch { my $F = shift; join " || ", map { "${F}_R_PROTO == REENTRANT_PROTO_$_" } @_; } my @struct; my @size; my @init; my @free; my @wrap; my @define; sub pushssif { push @struct, @_; push @size, @_; push @init, @_; push @free, @_; } sub pushinitfree { my $f = shift; push @init, <_${f}_buffer, PL_reentrant_buffer->_${f}_size, char); EOF push @free, <_${f}_buffer); EOF } sub define { my ($n, $p, @F) = @_; my @H; my $H = uc $F[0]; push @define, <_${f}_size = REENTRANTSMALLSIZE; EOF pushinitfree $f; pushssif $endif; } elsif ($f =~ /^(crypt)$/) { pushssif $ifdef; push @struct, <_${f}_struct.initialized = 0; #endif EOF pushssif $endif; } elsif ($f =~ /^(drand48|gmtime|localtime|random)$/) { pushssif $ifdef; push @struct, <_${g}_size = 1024; EOF } else { push @struct, <_${g}_fptr = NULL; # endif 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, <_${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; # else # ifdef __sgi PL_reentrant_buffer->_${g}_size = BUFSIZ; # else PL_reentrant_buffer->_${g}_size = REENTRANTUSUALSIZE; # endif # endif # endif EOF } pushinitfree $g; pushssif $endif; } elsif ($f =~ /^(gethostbyname|getnetbyname|getservbyname|getprotobyname)$/) { 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, <_${g}_size = REENTRANTUSUALSIZE; #endif EOF push @init, <_${g}_buffer, PL_reentrant_buffer->_${g}_size, char); #endif EOF push @free, <_${g}_buffer); #endif EOF pushssif $endif; } elsif ($f =~ /^(readdir|readdir64)$/) { pushssif $ifdef; my $R = ifprotomatch($F, grep {/R/} @p); push @struct, <_${f}_size = sizeof($seent{$f}) + MAXPATHLEN + 1; EOF push @init, <_${f}_struct = ($seent{$f}*)safemalloc(PL_reentrant_buffer->_${f}_size); EOF push @free, <_${f}_struct); EOF pushssif $endif; } push @wrap, $ifdef; push @wrap, <_${g}_ptr" : $_ eq 'E' ? "&PL_reentrant_buffer->_${g}_errno" : $_ eq 'B' ? "PL_reentrant_buffer->_${g}_buffer" : $_ =~ /^[WI]$/ ? "PL_reentrant_buffer->_${g}_size" : $_ eq 'H' ? "&PL_reentrant_buffer->_${g}_fptr" : $_ eq 'D' ? "&PL_reentrant_buffer->_${g}_data" : $_ eq 'S' ? ($f =~ /^readdir/ ? "PL_reentrant_buffer->_${g}_struct" : "&PL_reentrant_buffer->_${g}_struct" ) : $_ eq 'T' && $f eq 'drand48' ? "&PL_reentrant_buffer->_${g}_double" : $_ } split '', $b; $w = ", $w" if length $v; } my $call = "${f}_r($v$w)"; $call = "((errno = $call))" if $r eq 'I'; push @wrap, <reentr.c"); select C; print <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|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 | |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 | |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 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|D=struct hostent_data*|T=const void* gethostbyname C |netdb |struct hostent |I_CSBWRE|S_CSBIE|I_CSD|D=struct hostent_data* gethostent |netdb |struct hostent |I_SBWRE|I_SBIE|S_SBIE|S_SBI|I_SBI|I_SD|D=struct hostent_data* getlogin |unistd | |I_BW|I_BI|B_BW|B_BI getnetbyaddr LI |netdb |struct netent |I_UISBWRE|I_LISBI|S_TISBI|S_LISBI|I_TISD|I_LISD|I_IISD|D=struct netent_data*|T=in_addr_t|U=unsigned long getnetbyname C |netdb |struct netent |I_CSBWRE|I_CSBI|S_CSBI|I_CSD|D=struct netent_data* getnetent |netdb |struct netent |I_SBWRE|I_SBIE|S_SBIE|S_SBI|I_SBI|I_SD|D=struct netent_data* getprotobyname C|netdb |struct protoent|I_CSBWR|S_CSBI|I_CSD|D=struct protoent_data* getprotobynumber I |netdb |struct protoent|I_ISBWR|S_ISBI|I_ISD|D=struct protoent_data* getprotoent |netdb |struct protoent|I_SBWR|I_SBI|S_SBI|I_SD|D=struct protoent_data* getpwent |pwd |struct passwd |I_SBWR|I_SBIR|S_SBW|S_SBI|I_SBI|I_SBIH getpwnam C |pwd |struct passwd |I_CSBWR|I_CSBIR|S_CSBI|I_CSBI getpwuid T |pwd |struct passwd |I_TSBWR|I_TSBIR|I_TSBI|S_TSBI|T=uid_t getservbyname CC|netdb |struct servent |I_CCSBWR|S_CCSBI|I_CCSD|D=struct servent_data* getservbyport IC|netdb |struct servent |I_ICSBWR|S_ICSBI|I_ICSD|D=struct servent_data* getservent |netdb |struct servent |I_SBWR|I_SBI|S_SBI|I_SD|D=struct servent_data* getspnam C |shadow |struct spwd |I_CSBWR|S_CSBI gmtime T |time |struct tm |S_TS|I_TS|T=const time_t* localtime T |time |struct tm |S_TS|I_TS|T=const time_t* random |stdlib |struct random_data|I_TS|T=int* readdir T |dirent |struct dirent |I_TSR|I_TS|T=DIR* readdir64 T |dirent |struct dirent64|I_TSR|I_TS|T=DIR* setgrent |grp | |I_H|V_H sethostent I |netdb | |I_ID|V_ID|D=struct hostent_data* setlocale IC |locale | |I_ICBI setnetent I |netdb | |I_ID|V_ID|D=struct netent_data* setprotoent I |netdb | |I_ID|V_ID|D=struct protoent_data* setpwent |pwd | |I_H|V_H setservent I |netdb | |I_ID|V_ID|D=struct servent_data* srand48 L |stdlib |struct drand48_data |I_LS srandom T |stdlib |struct random_data|I_TS|T=unsigned int strerror I |string | |I_IBW|I_IBI|B_IBW tmpnam B |stdio | |B_B ttyname I |unistd | |I_IBW|I_IBI|B_IBI