ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/staticperl/perl/lib/ExtUtils/Constant/Base.pm
Revision: 1.1
Committed: Thu Jun 30 14:27:11 2005 UTC (21 years, 4 months ago) by root
Branch: MAIN
CVS Tags: PERL-5-8-7, HEAD
Branch point for: PERL
Log Message:
*** empty log message ***

File Contents

# Content
1 package ExtUtils::Constant::Base;
2
3 use strict;
4 use vars qw($VERSION $is_perl56);
5 use Carp;
6 use Text::Wrap;
7 use ExtUtils::Constant::Utils qw(C_stringify perl_stringify);
8
9 $VERSION = '0.01';
10
11 $is_perl56 = ($] < 5.007 && $] > 5.005_50);
12
13
14 =head1 NAME
15
16 ExtUtils::Constant::Base - base class for ExtUtils::Constant objects
17
18 =head1 SYNOPSIS
19
20 require ExtUtils::Constant::Base;
21 @ISA = 'ExtUtils::Constant::Base';
22
23 =head1 DESCRIPTION
24
25 ExtUtils::Constant::Base provides a base implementation of methods to
26 generate C code to give fast constant value lookup by named string. Currently
27 it's mostly used ExtUtils::Constant::XS, which generates the lookup code
28 for the constant() subroutine found in many XS modules.
29
30 =head1 USAGE
31
32 ExtUtils::Constant::Base exports no subroutines. The following methods are
33 available
34
35 =over 4
36
37 =cut
38
39 sub valid_type {
40 # Default to assuming that you don't need different types of return data.
41 1;
42 }
43 sub default_type {
44 '';
45 }
46
47 =item header
48
49 A method returning a scalar containing definitions needed, typically for a
50 C header file.
51
52 =cut
53
54 sub header {
55 ''
56 }
57
58 # This might actually be a return statement. Note that you are responsible
59 # for any space you might need before your value, as it lets to perform
60 # "tricks" such as "return KEY_" and have strings appended.
61 sub assignment_clause_for_type;
62 # In which case this might be an empty string
63 sub return_statement_for_type {undef};
64 sub return_statement_for_notdef;
65 sub return_statement_for_notfound;
66
67 # "#if 1" is true to a C pre-processor
68 sub macro_from_name {
69 1;
70 }
71
72 sub name_param {
73 'name';
74 }
75
76 # This is possibly buggy, in that it's not mandatory (below, in the main
77 # C_constant parameters, but is expected to exist here, if it's needed)
78 # Buggy because if you're definitely pure 8 bit only, and will never be
79 # presented with your constants in utf8, the default form of C_constant can't
80 # be told not to do the utf8 version.
81
82 sub is_utf8_param {
83 'utf8';
84 }
85
86 sub memEQ {
87 "!memcmp";
88 }
89
90 =item memEQ_clause args_hashref
91
92 A method to return a suitable C C<if> statement to check whether I<name>
93 is equal to the C variable C<name>. If I<checked_at> is defined, then it
94 is used to avoid C<memEQ> for short names, or to generate a comment to
95 highlight the position of the character in the C<switch> statement.
96
97 If i<checked_at> is a reference to a scalar, then instead it gives
98 the characters pre-checked at the beginning, (and the number of chars by
99 which the C variable name has been advanced. These need to be chopped from
100 the front of I<name>).
101
102 =cut
103
104 sub memEQ_clause {
105 # if (memEQ(name, "thingy", 6)) {
106 # Which could actually be a character comparison or even ""
107 my ($self, $args) = @_;
108 my ($name, $checked_at, $indent) = @{$args}{qw(name checked_at indent)};
109 $indent = ' ' x ($indent || 4);
110 my $front_chop;
111 if (ref $checked_at) {
112 # regexp won't work on 5.6.1 without use utf8; in turn that won't work
113 # on 5.005_03.
114 substr ($name, 0, length $$checked_at,) = '';
115 $front_chop = C_stringify ($$checked_at);
116 undef $checked_at;
117 }
118 my $len = length $name;
119
120 if ($len < 2) {
121 return $indent . "{\n"
122 if (defined $checked_at and $checked_at == 0) or $len == 0;
123 # We didn't switch, drop through to the code for the 2 character string
124 $checked_at = 1;
125 }
126
127 my $name_param = $self->name_param;
128
129 if ($len < 3 and defined $checked_at) {
130 my $check;
131 if ($checked_at == 1) {
132 $check = 0;
133 } elsif ($checked_at == 0) {
134 $check = 1;
135 }
136 if (defined $check) {
137 my $char = C_stringify (substr $name, $check, 1);
138 # Placate 5.005 with a break in the string. I can't see a good way of
139 # getting it to not take [ as introducing an array lookup, even with
140 # ${name_param}[$check]
141 return $indent . "if ($name_param" . "[$check] == '$char') {\n";
142 }
143 }
144 if (($len == 2 and !defined $checked_at)
145 or ($len == 3 and defined ($checked_at) and $checked_at == 2)) {
146 my $char1 = C_stringify (substr $name, 0, 1);
147 my $char2 = C_stringify (substr $name, 1, 1);
148 return $indent .
149 "if ($name_param" . "[0] == '$char1' && $name_param" . "[1] == '$char2') {\n";
150 }
151 if (($len == 3 and defined ($checked_at) and $checked_at == 1)) {
152 my $char1 = C_stringify (substr $name, 0, 1);
153 my $char2 = C_stringify (substr $name, 2, 1);
154 return $indent .
155 "if ($name_param" . "[0] == '$char1' && $name_param" . "[2] == '$char2') {\n";
156 }
157
158 my $pointer = '^';
159 my $have_checked_last = defined ($checked_at) && $len == $checked_at + 1;
160 if ($have_checked_last) {
161 # Checked at the last character, so no need to memEQ it.
162 $pointer = C_stringify (chop $name);
163 $len--;
164 }
165
166 $name = C_stringify ($name);
167 my $memEQ = $self->memEQ();
168 my $body = $indent . "if ($memEQ($name_param, \"$name\", $len)) {\n";
169 # Put a little ^ under the letter we checked at
170 # Screws up for non printable and non-7 bit stuff, but that's too hard to
171 # get right.
172 if (defined $checked_at) {
173 $body .= $indent . "/* " . (' ' x length $memEQ)
174 . (' ' x length $name_param)
175 . (' ' x $checked_at) . $pointer
176 . (' ' x ($len - $checked_at + length $len)) . " */\n";
177 } elsif (defined $front_chop) {
178 $body .= $indent . "/* $front_chop"
179 . (' ' x ($len + 1 + length $len)) . " */\n";
180 }
181 return $body;
182 }
183
184 =item dump_names arg_hashref, ITEM...
185
186 An internal function to generate the embedded perl code that will regenerate
187 the constant subroutines. I<default_type>, I<types> and I<ITEM>s are the
188 same as for C_constant. I<indent> is treated as number of spaces to indent
189 by. If C<declare_types> is true a C<$types> is always declared in the perl
190 code generated, if defined and false never declared, and if undefined C<$types>
191 is only declared if the values in I<types> as passed in cannot be inferred from
192 I<default_types> and the I<ITEM>s.
193
194 =cut
195
196 sub dump_names {
197 my ($self, $args, @items) = @_;
198 my ($default_type, $what, $indent, $declare_types)
199 = @{$args}{qw(default_type what indent declare_types)};
200 $indent = ' ' x ($indent || 0);
201
202 my $result;
203 my (@simple, @complex, %used_types);
204 foreach (@items) {
205 my $type;
206 if (ref $_) {
207 $type = $_->{type} || $default_type;
208 if ($_->{utf8}) {
209 # For simplicity always skip the bytes case, and reconstitute this entry
210 # from its utf8 twin.
211 next if $_->{utf8} eq 'no';
212 # Copy the hashref, as we don't want to mess with the caller's hashref.
213 $_ = {%$_};
214 unless ($is_perl56) {
215 utf8::decode ($_->{name});
216 } else {
217 $_->{name} = pack 'U*', unpack 'U0U*', $_->{name};
218 }
219 delete $_->{utf8};
220 }
221 } else {
222 $_ = {name=>$_};
223 $type = $default_type;
224 }
225 $used_types{$type}++;
226 if ($type eq $default_type
227 # grr 5.6.1
228 and length $_->{name}
229 and length $_->{name} == ($_->{name} =~ tr/A-Za-z0-9_//)
230 and !defined ($_->{macro}) and !defined ($_->{value})
231 and !defined ($_->{default}) and !defined ($_->{pre})
232 and !defined ($_->{post}) and !defined ($_->{def_pre})
233 and !defined ($_->{def_post}) and !defined ($_->{weight})) {
234 # It's the default type, and the name consists only of A-Za-z0-9_
235 push @simple, $_->{name};
236 } else {
237 push @complex, $_;
238 }
239 }
240
241 if (!defined $declare_types) {
242 # Do they pass in any types we weren't already using?
243 foreach (keys %$what) {
244 next if $used_types{$_};
245 $declare_types++; # Found one in $what that wasn't used.
246 last; # And one is enough to terminate this loop
247 }
248 }
249 if ($declare_types) {
250 $result = $indent . 'my $types = {map {($_, 1)} qw('
251 . join (" ", sort keys %$what) . ")};\n";
252 }
253 local $Text::Wrap::huge = 'overflow';
254 local $Text::Wrap::columns = 80;
255 $result .= wrap ($indent . "my \@names = (qw(",
256 $indent . " ", join (" ", sort @simple) . ")");
257 if (@complex) {
258 foreach my $item (sort {$a->{name} cmp $b->{name}} @complex) {
259 my $name = perl_stringify $item->{name};
260 my $line = ",\n$indent {name=>\"$name\"";
261 $line .= ", type=>\"$item->{type}\"" if defined $item->{type};
262 foreach my $thing (qw (macro value default pre post def_pre def_post)) {
263 my $value = $item->{$thing};
264 if (defined $value) {
265 if (ref $value) {
266 $line .= ", $thing=>[\""
267 . join ('", "', map {perl_stringify $_} @$value) . '"]';
268 } else {
269 $line .= ", $thing=>\"" . perl_stringify($value) . "\"";
270 }
271 }
272 }
273 $line .= "}";
274 # Ensure that the enclosing C comment doesn't end
275 # by turning */ into *" . "/
276 $line =~ s!\*\/!\*" . "/!gs;
277 # gcc -Wall doesn't like finding /* inside a comment
278 $line =~ s!\/\*!/" . "\*!gs;
279 $result .= $line;
280 }
281 }
282 $result .= ");\n";
283
284 $result;
285 }
286
287 =item assign arg_hashref, VALUE...
288
289 A method to return a suitable assignment clause. If I<type> is aggregate
290 (eg I<PVN> expects both pointer and length) then there should be multiple
291 I<VALUE>s for the components. I<pre> and I<post> if defined give snippets
292 of C code to proceed and follow the assignment. I<pre> will be at the start
293 of a block, so variables may be defined in it.
294
295 =cut
296 # Hmm. value undef to to NOTDEF? value () to do NOTFOUND?
297
298 sub assign {
299 my $self = shift;
300 my $args = shift;
301 my ($indent, $type, $pre, $post, $item)
302 = @{$args}{qw(indent type pre post item)};
303 $post ||= '';
304 my $clause;
305 my $close;
306 if ($pre) {
307 chomp $pre;
308 $close = "$indent}\n";
309 $clause = $indent . "{\n";
310 $indent .= " ";
311 $clause .= "$indent$pre";
312 $clause .= ";" unless $pre =~ /;$/;
313 $clause .= "\n";
314 }
315 confess "undef \$type" unless defined $type;
316 confess "Can't generate code for type $type"
317 unless $self->valid_type($type);
318
319 $clause .= join '', map {"$indent$_\n"}
320 $self->assignment_clause_for_type({type=>$type,item=>$item}, @_);
321 chomp $post;
322 if (length $post) {
323 $clause .= "$post";
324 $clause .= ";" unless $post =~ /;$/;
325 $clause .= "\n";
326 }
327 my $return = $self->return_statement_for_type($type);
328 $clause .= "$indent$return\n" if defined $return;
329 $clause .= $close if $close;
330 return $clause;
331 }
332
333 =item return_clause arg_hashref, ITEM
334
335 A method to return a suitable C<#ifdef> clause. I<ITEM> is a hashref
336 (as passed to C<C_constant> and C<match_clause>. I<indent> is the number
337 of spaces to indent, defaulting to 6.
338
339 =cut
340
341 sub return_clause {
342
343 ##ifdef thingy
344 # *iv_return = thingy;
345 # return PERL_constant_ISIV;
346 ##else
347 # return PERL_constant_NOTDEF;
348 ##endif
349 my ($self, $args, $item) = @_;
350 my $indent = $args->{indent};
351
352 my ($name, $value, $macro, $default, $pre, $post, $def_pre, $def_post, $type)
353 = @$item{qw (name value macro default pre post def_pre def_post type)};
354 $value = $name unless defined $value;
355 $macro = $self->macro_from_name($item) unless defined $macro;
356 # "#if 1" is true to a C pre-processor
357 $macro = 1 if !defined $macro or $macro eq '';
358 $indent = ' ' x ($indent || 6);
359 unless (defined $type) {
360 # use Data::Dumper; print STDERR Dumper ($item);
361 confess "undef \$type";
362 }
363
364 my $clause;
365
366 ##ifdef thingy
367 if (ref $macro) {
368 $clause = $macro->[0];
369 } elsif ($macro ne "1") {
370 $clause = "#ifdef $macro\n";
371 }
372
373 # *iv_return = thingy;
374 # return PERL_constant_ISIV;
375 $clause
376 .= $self->assign ({indent=>$indent, type=>$type, pre=>$pre, post=>$post,
377 item=>$item}, ref $value ? @$value : $value);
378
379 if (ref $macro or $macro ne "1") {
380 ##else
381 $clause .= "#else\n";
382
383 # return PERL_constant_NOTDEF;
384 if (!defined $default) {
385 my $notdef = $self->return_statement_for_notdef();
386 $clause .= "$indent$notdef\n" if defined $notdef;
387 } else {
388 my @default = ref $default ? @$default : $default;
389 $type = shift @default;
390 $clause .= $self->assign ({indent=>$indent, type=>$type, pre=>$pre,
391 post=>$post, item=>$item}, @default);
392 }
393
394 ##endif
395 if (ref $macro) {
396 $clause .= $macro->[1];
397 } else {
398 $clause .= "#endif\n";
399 }
400 }
401 return $clause;
402 }
403
404 sub match_clause {
405 # $offset defined if we have checked an offset.
406 my ($self, $args, $item) = @_;
407 my ($offset, $indent) = @{$args}{qw(checked_at indent)};
408 $indent = ' ' x ($indent || 4);
409 my $body = '';
410 my ($no, $yes, $either, $name, $inner_indent);
411 if (ref $item eq 'ARRAY') {
412 ($yes, $no) = @$item;
413 $either = $yes || $no;
414 confess "$item is $either expecting hashref in [0] || [1]"
415 unless ref $either eq 'HASH';
416 $name = $either->{name};
417 } else {
418 confess "$item->{name} has utf8 flag '$item->{utf8}', should be false"
419 if $item->{utf8};
420 $name = $item->{name};
421 $inner_indent = $indent;
422 }
423
424 $body .= $self->memEQ_clause ({name => $name, checked_at => $offset,
425 indent => length $indent});
426 # If we've been presented with an arrayref for $item, then the user string
427 # contains in the range 128-255, and we need to check whether it was utf8
428 # (or not).
429 # In the worst case we have two named constants, where one's name happens
430 # encoded in UTF8 happens to be the same byte sequence as the second's
431 # encoded in (say) ISO-8859-1.
432 # In this case, $yes and $no both have item hashrefs.
433 if ($yes) {
434 $body .= $indent . " if (" . $self->is_utf8_param . ") {\n";
435 } elsif ($no) {
436 $body .= $indent . " if (!" . $self->is_utf8_param . ") {\n";
437 }
438 if ($either) {
439 $body .= $self->return_clause ({indent=>4 + length $indent}, $either);
440 if ($yes and $no) {
441 $body .= $indent . " } else {\n";
442 $body .= $self->return_clause ({indent=>4 + length $indent}, $no);
443 }
444 $body .= $indent . " }\n";
445 } else {
446 $body .= $self->return_clause ({indent=>2 + length $indent}, $item);
447 }
448 $body .= $indent . "}\n";
449 }
450
451
452 =item switch_clause arg_hashref, NAMELEN, ITEMHASH, ITEM...
453
454 An internal method to generate a suitable C<switch> clause, called by
455 C<C_constant> I<ITEM>s are in the hash ref format as given in the description
456 of C<C_constant>, and must all have the names of the same length, given by
457 I<NAMELEN>. I<ITEMHASH> is a reference to a hash, keyed by name, values being
458 the hashrefs in the I<ITEM> list. (No parameters are modified, and there can
459 be keys in the I<ITEMHASH> that are not in the list of I<ITEM>s without
460 causing problems - the hash is passed in to save generating it afresh for
461 each call).
462
463 =cut
464
465 sub switch_clause {
466 my ($self, $args, $namelen, $items, @items) = @_;
467 my ($indent, $comment) = @{$args}{qw(indent comment)};
468 $indent = ' ' x ($indent || 2);
469
470 local $Text::Wrap::huge = 'overflow';
471 local $Text::Wrap::columns = 80;
472
473 my @names = sort map {$_->{name}} @items;
474 my $leader = $indent . '/* ';
475 my $follower = ' ' x length $leader;
476 my $body = $indent . "/* Names all of length $namelen. */\n";
477 if (defined $comment) {
478 $body = wrap ($leader, $follower, $comment) . "\n";
479 $leader = $follower;
480 }
481 my @safe_names = @names;
482 foreach (@safe_names) {
483 confess sprintf "Name '$_' is length %d, not $namelen", length
484 unless length == $namelen;
485 # Argh. 5.6.1
486 # next unless tr/A-Za-z0-9_//c;
487 next if tr/A-Za-z0-9_// == length;
488 $_ = '"' . perl_stringify ($_) . '"';
489 # Ensure that the enclosing C comment doesn't end
490 # by turning */ into *" . "/
491 s!\*\/!\*"."/!gs;
492 # gcc -Wall doesn't like finding /* inside a comment
493 s!\/\*!/"."\*!gs;
494 }
495 $body .= wrap ($leader, $follower, join (" ", @safe_names) . " */") . "\n";
496 # Figure out what to switch on.
497 # (RMS, Spread of jump table, Position, Hashref)
498 my @best = (1e38, ~0);
499 # Prefer the last character over the others. (As it lets us shorten the
500 # memEQ clause at no cost).
501 foreach my $i ($namelen - 1, 0 .. ($namelen - 2)) {
502 my ($min, $max) = (~0, 0);
503 my %spread;
504 if ($is_perl56) {
505 # Need proper Unicode preserving hash keys for bytes in range 128-255
506 # here too, for some reason. grr 5.6.1 yet again.
507 tie %spread, 'ExtUtils::Constant::Aaargh56Hash';
508 }
509 foreach (@names) {
510 my $char = substr $_, $i, 1;
511 my $ord = ord $char;
512 confess "char $ord is out of range" if $ord > 255;
513 $max = $ord if $ord > $max;
514 $min = $ord if $ord < $min;
515 push @{$spread{$char}}, $_;
516 # warn "$_ $char";
517 }
518 # I'm going to pick the character to split on that minimises the root
519 # mean square of the number of names in each case. Normally this should
520 # be the one with the most keys, but it may pick a 7 where the 8 has
521 # one long linear search. I'm not sure if RMS or just sum of squares is
522 # actually better.
523 # $max and $min are for the tie-breaker if the root mean squares match.
524 # Assuming that the compiler may be building a jump table for the
525 # switch() then try to minimise the size of that jump table.
526 # Finally use < not <= so that if it still ties the earliest part of
527 # the string wins. Because if that passes but the memEQ fails, it may
528 # only need the start of the string to bin the choice.
529 # I think. But I'm micro-optimising. :-)
530 # OK. Trump that. Now favour the last character of the string, before the
531 # rest.
532 my $ss;
533 $ss += @$_ * @$_ foreach values %spread;
534 my $rms = sqrt ($ss / keys %spread);
535 if ($rms < $best[0] || ($rms == $best[0] && ($max - $min) < $best[1])) {
536 @best = ($rms, $max - $min, $i, \%spread);
537 }
538 }
539 confess "Internal error. Failed to pick a switch point for @names"
540 unless defined $best[2];
541 # use Data::Dumper; print Dumper (@best);
542 my ($offset, $best) = @best[2,3];
543 $body .= $indent . "/* Offset $offset gives the best switch position. */\n";
544
545 my $do_front_chop = $offset == 0 && $namelen > 2;
546 if ($do_front_chop) {
547 $body .= $indent . "switch (*" . $self->name_param() . "++) {\n";
548 } else {
549 $body .= $indent . "switch (" . $self->name_param() . "[$offset]) {\n";
550 }
551 foreach my $char (sort keys %$best) {
552 confess sprintf "'$char' is %d bytes long, not 1", length $char
553 if length ($char) != 1;
554 confess sprintf "char %#X is out of range", ord $char if ord ($char) > 255;
555 $body .= $indent . "case '" . C_stringify ($char) . "':\n";
556 foreach my $thisone (sort {
557 # Deal with the case of an item actually being an array ref to 1 or 2
558 # hashrefs. Don't assign to $a or $b, as they're aliases to the orignal
559 my $l = ref $a eq 'ARRAY' ? ($a->[0] || $->[1]) : $a;
560 my $r = ref $b eq 'ARRAY' ? ($b->[0] || $->[1]) : $b;
561 # Sort by weight first
562 ($r->{weight} || 0) <=> ($l->{weight} || 0)
563 # Sort equal weights by name
564 or $l->{name} cmp $r->{name}}
565 # If this looks evil, maybe it is. $items is a
566 # hashref, and we're doing a hash slice on it
567 @{$items}{@{$best->{$char}}}) {
568 # warn "You are here";
569 if ($do_front_chop) {
570 $body .= $self->match_clause ({indent => 2 + length $indent,
571 checked_at => \$char}, $thisone);
572 } else {
573 $body .= $self->match_clause ({indent => 2 + length $indent,
574 checked_at => $offset}, $thisone);
575 }
576 }
577 $body .= $indent . " break;\n";
578 }
579 $body .= $indent . "}\n";
580 return $body;
581 }
582
583 sub C_constant_return_type {
584 "static int";
585 }
586
587 sub C_constant_prefix_param {
588 '';
589 }
590
591 sub C_constant_prefix_param_defintion {
592 '';
593 }
594
595 sub name_param_definition {
596 "const char *" . $_[0]->name_param;
597 }
598
599 sub namelen_param {
600 'len';
601 }
602
603 sub namelen_param_definition {
604 'size_t ' . $_[0]->namelen_param;
605 }
606
607 sub C_constant_other_params {
608 '';
609 }
610
611 sub C_constant_other_params_defintion {
612 '';
613 }
614
615 =item params WHAT
616
617 An "internal" method, subject to change, currently called to allow an
618 overriding class to cache information that will then be passed into all
619 the C<*param*> calls. (Yes, having to read the source to make sense of this is
620 considered a known bug). I<WHAT> is be a hashref of types the constant
621 function will return. In ExtUtils::Constant::XS this method is used to
622 returns a hashref keyed IV NV PV SV to show which combination of pointers will
623 be needed in the C argument list generated by
624 C_constant_other_params_definition and C_constant_other_params
625
626 =cut
627
628 sub params {
629 '';
630 }
631
632
633 =item dogfood arg_hashref, ITEM...
634
635 An internal function to generate the embedded perl code that will regenerate
636 the constant subroutines. Parameters are the same as for C_constant.
637
638 Currently the base class does nothing and returns an empty string.
639
640 =cut
641
642 sub dogfood {
643 ''
644 }
645
646 =item C_constant arg_hashref, ITEM...
647
648 A function that returns a B<list> of C subroutine definitions that return
649 the value and type of constants when passed the name by the XS wrapper.
650 I<ITEM...> gives a list of constant names. Each can either be a string,
651 which is taken as a C macro name, or a reference to a hash with the following
652 keys
653
654 =over 8
655
656 =item name
657
658 The name of the constant, as seen by the perl code.
659
660 =item type
661
662 The type of the constant (I<IV>, I<NV> etc)
663
664 =item value
665
666 A C expression for the value of the constant, or a list of C expressions if
667 the type is aggregate. This defaults to the I<name> if not given.
668
669 =item macro
670
671 The C pre-processor macro to use in the C<#ifdef>. This defaults to the
672 I<name>, and is mainly used if I<value> is an C<enum>. If a reference an
673 array is passed then the first element is used in place of the C<#ifdef>
674 line, and the second element in place of the C<#endif>. This allows
675 pre-processor constructions such as
676
677 #if defined (foo)
678 #if !defined (bar)
679 ...
680 #endif
681 #endif
682
683 to be used to determine if a constant is to be defined.
684
685 A "macro" 1 signals that the constant is always defined, so the C<#if>/C<#endif>
686 test is omitted.
687
688 =item default
689
690 Default value to use (instead of C<croak>ing with "your vendor has not
691 defined...") to return if the macro isn't defined. Specify a reference to
692 an array with type followed by value(s).
693
694 =item pre
695
696 C code to use before the assignment of the value of the constant. This allows
697 you to use temporary variables to extract a value from part of a C<struct>
698 and return this as I<value>. This C code is places at the start of a block,
699 so you can declare variables in it.
700
701 =item post
702
703 C code to place between the assignment of value (to a temporary) and the
704 return from the function. This allows you to clear up anything in I<pre>.
705 Rarely needed.
706
707 =item def_pre
708
709 =item def_post
710
711 Equivalents of I<pre> and I<post> for the default value.
712
713 =item utf8
714
715 Generated internally. Is zero or undefined if name is 7 bit ASCII,
716 "no" if the name is 8 bit (and so should only match if SvUTF8() is false),
717 "yes" if the name is utf8 encoded.
718
719 The internals automatically clone any name with characters 128-255 but none
720 256+ (ie one that could be either in bytes or utf8) into a second entry
721 which is utf8 encoded.
722
723 =item weight
724
725 Optional sorting weight for names, to determine the order of
726 linear testing when multiple names fall in the same case of a switch clause.
727 Higher comes earlier, undefined defaults to zero.
728
729 =back
730
731 In the argument hashref, I<package> is the name of the package, and is only
732 used in comments inside the generated C code. I<subname> defaults to
733 C<constant> if undefined.
734
735 I<default_type> is the type returned by C<ITEM>s that don't specify their
736 type. It defaults to the value of C<default_type()>. I<types> should be given
737 either as a comma separated list of types that the C subroutine I<subname>
738 will generate or as a reference to a hash. I<default_type> will be added to
739 the list if not present, as will any types given in the list of I<ITEM>s. The
740 resultant list should be the same list of types that C<XS_constant> is
741 given. [Otherwise C<XS_constant> and C<C_constant> may differ in the number of
742 parameters to the constant function. I<indent> is currently unused and
743 ignored. In future it may be used to pass in information used to change the C
744 indentation style used.] The best way to maintain consistency is to pass in a
745 hash reference and let this function update it.
746
747 I<breakout> governs when child functions of I<subname> are generated. If there
748 are I<breakout> or more I<ITEM>s with the same length of name, then the code
749 to switch between them is placed into a function named I<subname>_I<len>, for
750 example C<constant_5> for names 5 characters long. The default I<breakout> is
751 3. A single C<ITEM> is always inlined.
752
753 =cut
754
755 # The parameter now BREAKOUT was previously documented as:
756 #
757 # I<NAMELEN> if defined signals that all the I<name>s of the I<ITEM>s are of
758 # this length, and that the constant name passed in by perl is checked and
759 # also of this length. It is used during recursion, and should be C<undef>
760 # unless the caller has checked all the lengths during code generation, and
761 # the generated subroutine is only to be called with a name of this length.
762 #
763 # As you can see it now performs this function during recursion by being a
764 # scalar reference.
765
766 sub C_constant {
767 my ($self, $args, @items) = @_;
768 my ($package, $subname, $default_type, $what, $indent, $breakout) =
769 @{$args}{qw(package subname default_type types indent breakout)};
770 $package ||= 'Foo';
771 $subname ||= 'constant';
772 # I'm not using this. But a hashref could be used for full formatting without
773 # breaking this API
774 # $indent ||= 0;
775
776 my ($namelen, $items);
777 if (ref $breakout) {
778 # We are called recursively. We trust @items to be normalised, $what to
779 # be a hashref, and pinch %$items from our parent to save recalculation.
780 ($namelen, $items) = @$breakout;
781 } else {
782 if ($is_perl56) {
783 # Need proper Unicode preserving hash keys.
784 require ExtUtils::Constant::Aaargh56Hash;
785 $items = {};
786 tie %$items, 'ExtUtils::Constant::Aaargh56Hash';
787 }
788 $breakout ||= 3;
789 $default_type ||= $self->default_type();
790 if (!ref $what) {
791 # Convert line of the form IV,UV,NV to hash
792 $what = {map {$_ => 1} split /,\s*/, ($what || '')};
793 # Figure out what types we're dealing with, and assign all unknowns to the
794 # default type
795 }
796 my @new_items;
797 foreach my $orig (@items) {
798 my ($name, $item);
799 if (ref $orig) {
800 # Make a copy which is a normalised version of the ref passed in.
801 $name = $orig->{name};
802 my ($type, $macro, $value) = @$orig{qw (type macro value)};
803 $type ||= $default_type;
804 $what->{$type} = 1;
805 $item = {name=>$name, type=>$type};
806
807 undef $macro if defined $macro and $macro eq $name;
808 $item->{macro} = $macro if defined $macro;
809 undef $value if defined $value and $value eq $name;
810 $item->{value} = $value if defined $value;
811 foreach my $key (qw(default pre post def_pre def_post weight)) {
812 my $value = $orig->{$key};
813 $item->{$key} = $value if defined $value;
814 # warn "$key $value";
815 }
816 } else {
817 $name = $orig;
818 $item = {name=>$name, type=>$default_type};
819 $what->{$default_type} = 1;
820 }
821 warn +(ref ($self) || $self)
822 . "doesn't know how to handle values of type $_ used in macro $name"
823 unless $self->valid_type ($item->{type});
824 # tr///c is broken on 5.6.1 for utf8, so my original tr/\0-\177//c
825 # doesn't work. Upgrade to 5.8
826 # if ($name !~ tr/\0-\177//c || $] < 5.005_50) {
827 if ($name =~ tr/\0-\177// == length $name || $] < 5.005_50) {
828 # No characters outside 7 bit ASCII.
829 if (exists $items->{$name}) {
830 die "Multiple definitions for macro $name";
831 }
832 $items->{$name} = $item;
833 } else {
834 # No characters outside 8 bit. This is hardest.
835 if (exists $items->{$name} and ref $items->{$name} ne 'ARRAY') {
836 confess "Unexpected ASCII definition for macro $name";
837 }
838 # Again, 5.6.1 tr broken, so s/5\.6.*/5\.8\.0/;
839 # if ($name !~ tr/\0-\377//c) {
840 if ($name =~ tr/\0-\377// == length $name) {
841 # if ($] < 5.007) {
842 # $name = pack "C*", unpack "U*", $name;
843 # }
844 $item->{utf8} = 'no';
845 $items->{$name}[1] = $item;
846 push @new_items, $item;
847 # Copy item, to create the utf8 variant.
848 $item = {%$item};
849 }
850 # Encode the name as utf8 bytes.
851 unless ($is_perl56) {
852 utf8::encode($name);
853 } else {
854 # warn "Was >$name< " . length ${name};
855 $name = pack 'C*', unpack 'C*', $name . pack 'U*';
856 # warn "Now '${name}' " . length ${name};
857 }
858 if ($items->{$name}[0]) {
859 die "Multiple definitions for macro $name";
860 }
861 $item->{utf8} = 'yes';
862 $item->{name} = $name;
863 $items->{$name}[0] = $item;
864 # We have need for the utf8 flag.
865 $what->{''} = 1;
866 }
867 push @new_items, $item;
868 }
869 @items = @new_items;
870 # use Data::Dumper; print Dumper @items;
871 }
872 my $params = $self->params ($what);
873
874 # Probably "static int"
875 my ($body, @subs);
876 $body = $self->C_constant_return_type($params) . "\n$subname ("
877 # Eg "pTHX_ "
878 . $self->C_constant_prefix_param_defintion($params)
879 # Probably "const char *name"
880 . $self->name_param_definition($params);
881 # Something like ", STRLEN len"
882 $body .= ", " . $self->namelen_param_definition($params)
883 unless defined $namelen;
884 $body .= $self->C_constant_other_params_defintion($params);
885 $body .= ") {\n";
886
887 if (defined $namelen) {
888 # We are a child subroutine. Print the simple description
889 my $comment = 'When generated this function returned values for the list'
890 . ' of names given here. However, subsequent manual editing may have'
891 . ' added or removed some.';
892 $body .= $self->switch_clause ({indent=>2, comment=>$comment},
893 $namelen, $items, @items);
894 } else {
895 # We are the top level.
896 $body .= " /* Initially switch on the length of the name. */\n";
897 $body .= $self->dogfood ({package => $package, subname => $subname,
898 default_type => $default_type, what => $what,
899 indent => $indent, breakout => $breakout},
900 @items);
901 $body .= ' switch ('.$self->namelen_param().") {\n";
902 # Need to group names of the same length
903 my @by_length;
904 foreach (@items) {
905 push @{$by_length[length $_->{name}]}, $_;
906 }
907 foreach my $i (0 .. $#by_length) {
908 next unless $by_length[$i]; # None of this length
909 $body .= " case $i:\n";
910 if (@{$by_length[$i]} == 1) {
911 my $only_thing = $by_length[$i]->[0];
912 if ($only_thing->{utf8}) {
913 if ($only_thing->{utf8} eq 'yes') {
914 # With utf8 on flag item is passed in element 0
915 $body .= $self->match_clause (undef, [$only_thing]);
916 } else {
917 # With utf8 off flag item is passed in element 1
918 $body .= $self->match_clause (undef, [undef, $only_thing]);
919 }
920 } else {
921 $body .= $self->match_clause (undef, $only_thing);
922 }
923 } elsif (@{$by_length[$i]} < $breakout) {
924 $body .= $self->switch_clause ({indent=>4},
925 $i, $items, @{$by_length[$i]});
926 } else {
927 # Only use the minimal set of parameters actually needed by the types
928 # of the names of this length.
929 my $what = {};
930 foreach (@{$by_length[$i]}) {
931 $what->{$_->{type}} = 1;
932 $what->{''} = 1 if $_->{utf8};
933 }
934 $params = $self->params ($what);
935 push @subs, $self->C_constant ({package=>$package,
936 subname=>"${subname}_$i",
937 default_type => $default_type,
938 types => $what, indent => $indent,
939 breakout => [$i, $items]},
940 @{$by_length[$i]});
941 $body .= " return ${subname}_$i ("
942 # Eg "aTHX_ "
943 . $self->C_constant_prefix_param($params)
944 # Probably "name"
945 . $self->name_param($params);
946 $body .= $self->C_constant_other_params($params);
947 $body .= ");\n";
948 }
949 $body .= " break;\n";
950 }
951 $body .= " }\n";
952 }
953 my $notfound = $self->return_statement_for_notfound();
954 $body .= " $notfound\n" if $notfound;
955 $body .= "}\n";
956 return (@subs, $body);
957 }
958
959 1;
960 __END__
961
962 =back
963
964 =head1 BUGS
965
966 Not everything is documented yet.
967
968 Probably others.
969
970 =head1 AUTHOR
971
972 Nicholas Clark <nick@ccl4.org> based on the code in C<h2xs> by Larry Wall and
973 others