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