summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarl Williamson <khw@cpan.org>2015-09-07 10:03:27 -0600
committerKarl Williamson <khw@cpan.org>2015-09-08 10:05:56 -0600
commit308482c27259302fb2ca8c60b8383609a0e9f314 (patch)
tree5e15ba76b2ea0b5365c1d8b99a65cc0d6f64d923
parentd8f8a4817f5910267c45439ddb7764b371f06276 (diff)
downloadperl-308482c27259302fb2ca8c60b8383609a0e9f314.tar.gz
t/loc_tools.pl: Fix some bugs in locales_enabled()
This code assumed that all locale categories were represented by non-negative whole numbers. However, it turns out that this assumption is wrong, as on AIX, LC_ALL is -1. This commit changes our assumption to take into account that reality; it now assumes that all categories are larger than a much more negative number, and now the new assumption is tested for, and if wrong, the code dies instead of silently doing the wrong thing. There was also a bug where if a locale category wasn't defined on the machine, but the corresponding #ifdef for using that category was still set, the category was improperly assumed to exist
-rw-r--r--lib/locale.t14
-rw-r--r--t/loc_tools.pl57
2 files changed, 57 insertions, 14 deletions
diff --git a/lib/locale.t b/lib/locale.t
index 3a2005f481..6b5616c522 100644
--- a/lib/locale.t
+++ b/lib/locale.t
@@ -116,6 +116,20 @@ sub check_taint_not ($;$) {
ok((not is_tainted($_[0])), "verify that isn't tainted$message_tail");
}
+foreach my $category (qw(ALL COLLATE CTYPE MESSAGES MONETARY NUMERIC TIME)) {
+ my $short_result = locales_enabled($category);
+ ok ($short_result == 0 || $short_result == 1,
+ "Verify locales_enabled('$category') returns 0 or 1");
+ debug("locales_enabled('$category') returned '$short_result'");
+ my $long_result = locales_enabled("LC_$category");
+ if (! ok ($long_result == $short_result,
+ " and locales_enabled('LC_$category') returns "
+ . "the same value")
+ ) {
+ debug("locales_enabled('LC_$category') returned $long_result");
+ }
+}
+
"\tb\t" =~ /^m?(\s)(.*)\1$/;
check_taint_not $&, "not tainted outside 'use locale'";
;
diff --git a/t/loc_tools.pl b/t/loc_tools.pl
index 541e08f1b4..86d8e483ea 100644
--- a/t/loc_tools.pl
+++ b/t/loc_tools.pl
@@ -80,20 +80,38 @@ sub _decode_encodings { # For use only by other functions in this file!
return @enc;
}
+# LC_ALL can be -1 on some platforms. And, in fact the implementors could
+# legally use any integer to represent any category. But it makes the most
+# sense for them to have used small integers. Below, we create new locale
+# numbers for ones missing from this machine. We make them very negative,
+# hopefully more negative than anything likely to be a valid category on the
+# platform, but also below is a check to be sure that our guess is valid.
+my $max_bad_category_number = -1000000;
+
# Initialize this hash so that it looks like e.g.,
# 6 => 'CTYPE',
# where 6 is the value of &POSIX::LC_CTYPE
my %category_name;
eval { require POSIX; import POSIX 'locale_h'; };
unless ($@) {
- my $number_for_missing_category = 0;
+ my $number_for_missing_category = $max_bad_category_number;
foreach my $name (qw(ALL COLLATE CTYPE MESSAGES MONETARY NUMERIC TIME)) {
my $number = eval "&POSIX::LC_$name";
- # Use a negative number if the platform doesn't support this category,
- # so we have an entry for all ones that might be specified in calls to
- # us.
- $number = --$number_for_missing_category if $@;
+ if ($@) {
+ # Use a negative number (smaller than any legitimate category
+ # number) if the platform doesn't support this category, so we
+ # have an entry for all the ones that might be specified in calls
+ # to us.
+ $number = $number_for_missing_category-- if $@;
+ }
+ elsif ( $number !~ / ^ -? \d+ $ /x
+ || $number <= $max_bad_category_number)
+ {
+ # We think this should be an int. And it has to be larger than
+ # any of our synthetic numbers.
+ die "Unexpected locale category number '$number' for LC_$name"
+ }
$category_name{$number} = "$name";
}
@@ -129,19 +147,30 @@ sub locales_enabled(;$) {
if (defined $categories_ref) {
$categories_ref = [ $categories_ref ] if ! ref $categories_ref;
my @local_categories_copy = @$categories_ref;
- for my $category (@local_categories_copy) {
- if ($category =~ / ^ -? \d+ $ /x) {
- die "Invalid locale category number '$category'"
- unless grep { $category == $_ } keys %category_name;
- $category = $category_name{$category};
+ for my $category_name_or_number (@local_categories_copy) {
+ my $name;
+ my $number;
+ if ($category_name_or_number =~ / ^ -? \d+ $ /x) {
+ $number = $category_name_or_number;
+ die "Invalid locale category number '$number'"
+ unless grep { $number == $_ } keys %category_name;
+ $name = $category_name{$number};
}
else {
- $category =~ s/ ^ LC_ //x;
- die "Invalid locale category name '$category'"
- unless grep { $category eq $_ } values %category_name;
+ $name = $category_name_or_number;
+ $name =~ s/ ^ LC_ //x;
+ foreach my $trial (keys %category_name) {
+ if ($category_name{$trial} eq $name) {
+ $number = $trial;
+ last;
+ }
+ }
+ die "Invalid locale category name '$name'"
+ unless defined $number;
}
- return 0 if $Config{ccflags} =~ /\bD?NO_LOCALE_$category\b/;
+ return 0 if $number <= $max_bad_category_number
+ || $Config{ccflags} =~ /\bD?NO_LOCALE_$name\b/;
}
}