Use inlineable proxy constant subs for Socket
[p5sagit/p5-mst-13.2.git] / lib / ExtUtils / Constant / ProxySubs.pm
CommitLineData
6d7fb585 1package ExtUtils::Constant::ProxySubs;
2
3use strict;
64bb7586 4use vars qw($VERSION @ISA %type_to_struct %type_from_struct %type_to_sv
5 %type_to_C_value %type_is_a_problem %type_num_args);
6d7fb585 6use Carp;
7require ExtUtils::Constant::XS;
8use ExtUtils::Constant::Utils qw(C_stringify);
9use ExtUtils::Constant::XS qw(%XS_TypeSet);
10
11$VERSION = '0.01';
12@ISA = 'ExtUtils::Constant::XS';
13
14%type_to_struct =
15 (
16 IV => '{const char *name; I32 namelen; IV value;}',
64bb7586 17 NV => '{const char *name; I32 namelen; NV value;}',
18 UV => '{const char *name; I32 namelen; UV value;}',
19 YES => '{const char *name; I32 namelen;}',
20 NO => '{const char *name; I32 namelen;}',
6d7fb585 21 '' => '{const char *name; I32 namelen;} ',
22 );
23
64bb7586 24%type_from_struct =
25 (
26 IV => sub { $_[0] . '->value' },
27 NV => sub { $_[0] . '->value' },
28 UV => sub { $_[0] . '->value' },
29 YES => sub {},
30 NO => sub {},
31 '' => sub {},
32 );
33
6d7fb585 34%type_to_sv =
35 (
64bb7586 36 IV => sub { "newSViv($_[0])" },
37 NV => sub { "newSVnv($_[0])" },
38 UV => sub { "newSVuv($_[0])" },
39 YES => sub { '&PL_sv_yes' },
40 NO => sub { '&PL_sv_no' },
6d7fb585 41 '' => sub { '&PL_sv_yes' },
2ebbb0c3 42 SV => sub {"SvREFCNT_inc($_[0])"},
6d7fb585 43 );
44
45%type_to_C_value =
46 (
64bb7586 47 YES => sub {},
48 NO => sub {},
6d7fb585 49 '' => sub {},
50 );
51
64bb7586 52sub type_to_C_value {
53 my ($self, $type) = @_;
54 return $type_to_C_value{$type} || sub {return map {ref $_ ? @$_ : $_} @_};
55}
56
6d7fb585 57%type_is_a_problem =
58 (
2ebbb0c3 59 # The documentation says *mortal SV*, but we now need a non-mortal copy.
6d7fb585 60 SV => 1,
61 );
62
63while (my ($type, $value) = each %XS_TypeSet) {
64bb7586 64 $type_num_args{$type}
65 = defined $value ? ref $value ? scalar @$value : 1 : 0;
6d7fb585 66}
67$type_num_args{''} = 0;
68
69sub partition_names {
70 my ($self, $default_type, @items) = @_;
71 my (%found, @notfound, @trouble);
72
73 while (my $item = shift @items) {
74 my $default = delete $item->{default};
75 if ($default) {
76 # If we find a default value, convert it into a regular item and
77 # append it to the queue of items to process
78 my $default_item = {%$item};
79 $default_item->{invert_macro} = 1;
80 $default_item->{pre} = delete $item->{def_pre};
81 $default_item->{post} = delete $item->{def_post};
82 $default_item->{type} = shift @$default;
83 $default_item->{value} = $default;
84 push @items, $default_item;
85 } else {
86 # It can be "not found" unless it's the default (invert the macro)
87 # or the "macro" is an empty string (ie no macro)
88 push @notfound, $item unless $item->{invert_macro}
89 or !$self->macro_to_ifdef($self->macro_from_name($item));
90 }
91
64bb7586 92 if ($item->{pre} or $item->{post} or $item->{not_constant}
93 or $type_is_a_problem{$item->{type}}) {
6d7fb585 94 push @trouble, $item;
95 } else {
96 push @{$found{$item->{type}}}, $item;
97 }
98 }
99 # use Data::Dumper; print Dumper \%found;
100 (\%found, \@notfound, \@trouble);
101}
102
103sub boottime_iterator {
104 my ($self, $type, $iterator, $hash, $subname) = @_;
64bb7586 105 my $extractor = $type_from_struct{$type};
106 die "Can't find extractor code for type $type"
107 unless defined $extractor;
6d7fb585 108 my $generator = $type_to_sv{$type};
109 die "Can't find generator code for type $type"
110 unless defined $generator;
111
112 my $athx = $self->C_constant_prefix_param();
113
64bb7586 114 return sprintf <<"EOBOOT", &$generator(&$extractor($iterator));
6d7fb585 115 while ($iterator->name) {
116 $subname($athx $hash, $iterator->name,
117 $iterator->namelen, %s);
118 ++$iterator;
119 }
120EOBOOT
121}
122
64bb7586 123sub name_len_value_macro {
124 my ($self, $item) = @_;
125 my $name = $item->{name};
126 my $value = $item->{value};
127 $value = $item->{name} unless defined $value;
128
129 my $namelen = length $name;
130 if ($name =~ tr/\0-\377// != $namelen) {
131 # the hash API signals UTF-8 by passing the length negated.
132 utf8::encode($name);
133 $namelen = -length $name;
134 }
135 $name = C_stringify($name);
136
137 my $macro = $self->macro_from_name($item);
138 ($name, $namelen, $value, $macro);
139}
140
6d7fb585 141sub WriteConstants {
142 my $self = shift;
143 my $ARGS = shift;
144
145 my ($c_fh, $xs_fh, $c_subname, $xs_subname, $default_type, $package)
146 = @{$ARGS}{qw(c_fh xs_fh c_subname xs_subname default_type package)};
147
148 $xs_subname ||= 'constant';
149
150 croak("Package name '$package' contains % characters") if $package =~ /%/;
151
152 # All the types we see
153 my $what = {};
154 # A hash to lookup items with.
155 my $items = {};
156
157 my @items = $self->normalise_items ({disable_utf8_duplication => 1},
158 $default_type, $what, $items, @_);
159
160 # Partition the values by type. Also include any defaults in here
161 # Everything that doesn't have a default needs alternative code for
162 # "I'm missing"
163 # And everything that has pre or post code ends up in a private block
164 my ($found, $notfound, $trouble)
165 = $self->partition_names($default_type, @items);
166
6d7fb585 167 my $pthx = $self->C_constant_prefix_param_defintion();
168 my $athx = $self->C_constant_prefix_param();
169 my $symbol_table = C_stringify($package) . '::';
170
64bb7586 171 print $c_fh $self->header(), <<"EOADD";
6d7fb585 172void ${c_subname}_add_symbol($pthx HV *hash, const char *name, I32 namelen, SV *value) {
173 SV *rv = newRV_noinc(value);
174 if (!hv_store(hash, name, namelen, rv, TRUE)) {
175 SvREFCNT_dec(rv);
64bb7586 176 Perl_croak($athx "Couldn't add key '%s' to %%%s::", name, "$package");
6d7fb585 177 }
178}
179
180static HV *${c_subname}_missing = NULL;
181
182EOADD
183
184 print $xs_fh <<"EOBOOT";
185BOOT:
186 {
187#ifdef dTHX
188 dTHX;
189#endif
190 HV *symbol_table = get_hv("$symbol_table", TRUE);
191EOBOOT
192
193 my %iterator;
194
195 $found->{''}
196 = [map {{%$_, type=>'', invert_macro => 1}} @$notfound];
197
198 foreach my $type (sort keys %$found) {
199 my $struct = $type_to_struct{$type};
64bb7586 200 my $type_to_value = $self->type_to_C_value($type);
6d7fb585 201 my $number_of_args = $type_num_args{$type};
202 die "Can't find structure definition for type $type"
203 unless defined $struct;
204
205 my $struct_type = $type ? lc($type) . '_s' : 'notfound_s';
206 print $c_fh "struct $struct_type $struct;\n";
207
208 my $array_name = 'values_for_' . ($type ? lc $type : 'notfound');
209 print $xs_fh <<"EOBOOT";
210
211 static const struct $struct_type $array_name\[] =
212 {
213EOBOOT
214
215
216 foreach my $item (@{$found->{$type}}) {
64bb7586 217 my ($name, $namelen, $value, $macro)
218 = $self->name_len_value_macro($item);
6d7fb585 219
6d7fb585 220 my $ifdef = $self->macro_to_ifdef($macro);
221 if (!$ifdef && $item->{invert_macro}) {
222 carp("Attempting to supply a default for '$name' which has no conditional macro");
223 next;
224 }
225 print $xs_fh $ifdef;
226 if ($item->{invert_macro}) {
227 print $xs_fh
228 " /* This is the default value: */\n" if $type;
229 print $xs_fh "#else\n";
230 }
231 print $xs_fh " { ", join (', ', "\"$name\"", $namelen,
232 &$type_to_value($value)), " },\n",
233 $self->macro_to_endif($macro);
234 }
235
236
237 # Terminate the list with a NULL
238 print $xs_fh " { NULL, 0", (", 0" x $number_of_args), " } };\n";
239
240 $iterator{$type} = "value_for_" . ($type ? lc $type : 'notfound');
241
242 print $xs_fh <<"EOBOOT";
243 const struct $struct_type *$iterator{$type} = $array_name;
244
245EOBOOT
246 }
247
248 delete $found->{''};
249 foreach my $type (sort keys %$found) {
250 print $xs_fh $self->boottime_iterator($type, $iterator{$type},
251 'symbol_table',
252 "${c_subname}_add_symbol");
253 }
254 print $xs_fh <<"EOBOOT";
255
256 ${c_subname}_missing = newHV();
257 while (value_for_notfound->name) {
258 if (!hv_store(${c_subname}_missing, value_for_notfound->name,
259 value_for_notfound->namelen, &PL_sv_yes, TRUE))
64bb7586 260 Perl_croak($athx "Couldn't add key '%s' to missing_hash",
6d7fb585 261 value_for_notfound->name);
262 ++value_for_notfound;
263 }
6d7fb585 264EOBOOT
265
64bb7586 266 foreach my $item (@$trouble) {
267 my ($name, $namelen, $value, $macro)
268 = $self->name_len_value_macro($item);
269 my $ifdef = $self->macro_to_ifdef($macro);
270 my $type = $item->{type};
271 my $type_to_value = $self->type_to_C_value($type);
272
273 print $xs_fh $ifdef;
274 if ($item->{invert_macro}) {
275 print $xs_fh
276 " /* This is the default value: */\n" if $type;
277 print $xs_fh "#else\n";
278 }
279 my $generator = $type_to_sv{$type};
280 die "Can't find generator code for type $type"
281 unless defined $generator;
282
2ebbb0c3 283 print $xs_fh " {\n";
284 print $xs_fh " $item->{pre}\n" if $item->{pre};
64bb7586 285 printf $xs_fh <<"EOBOOT", $name, &$generator(&$type_to_value($value));
2ebbb0c3 286 ${c_subname}_add_symbol($athx symbol_table, "%s",
287 $namelen, %s);
64bb7586 288EOBOOT
2ebbb0c3 289 print $xs_fh " $item->{post}\n" if $item->{post};
290 print $xs_fh " }\n";
64bb7586 291
292 print $xs_fh $self->macro_to_endif($macro);
293 }
294
295 print $xs_fh <<EOCONSTANT
296 }
6d7fb585 297
298void
299$xs_subname(sv)
300 PREINIT:
301 STRLEN len;
302 INPUT:
303 SV * sv;
304 const char * s = SvPV(sv, len);
305 PPCODE:
306 if (hv_exists(${c_subname}_missing, s, SvUTF8(sv) ? -len : len)) {
307 sv = newSVpvf("Your vendor has not defined $package macro %" SVf
308 ", used", sv);
309 } else {
310 sv = newSVpvf("%" SVf " is not a valid $package macro", sv);
311 }
312 PUSHs(sv_2mortal(sv));
313EOCONSTANT
314}
315
3161;