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