Tue Aug 9 18:35:43 2022 UTC ()
lintpksrc: fix parsing of the ':S' modifier in makefiles


(rillig)
diff -r1.57 -r1.58 pkgsrc/pkgtools/lintpkgsrc/files/lintpkgsrc.pl
diff -r1.5 -r1.6 pkgsrc/pkgtools/lintpkgsrc/files/t/glob.t

cvs diff -r1.57 -r1.58 pkgsrc/pkgtools/lintpkgsrc/files/lintpkgsrc.pl (expand / switch to unified diff)

--- pkgsrc/pkgtools/lintpkgsrc/files/lintpkgsrc.pl 2022/08/09 18:14:22 1.57
+++ pkgsrc/pkgtools/lintpkgsrc/files/lintpkgsrc.pl 2022/08/09 18:35:43 1.58
@@ -1,16 +1,16 @@ @@ -1,16 +1,16 @@
1#!@PERL5@ 1#!@PERL5@
2 2
3# $NetBSD: lintpkgsrc.pl,v 1.57 2022/08/09 18:14:22 rillig Exp $ 3# $NetBSD: lintpkgsrc.pl,v 1.58 2022/08/09 18:35:43 rillig Exp $
4 4
5# Written by David Brownlee <abs@netbsd.org>. 5# Written by David Brownlee <abs@netbsd.org>.
6# 6#
7# Caveats: 7# Caveats:
8# The 'Makefile parsing' algorithm used to obtain package versions and 8# The 'Makefile parsing' algorithm used to obtain package versions and
9# DEPENDS information is geared towards speed rather than perfection, 9# DEPENDS information is geared towards speed rather than perfection,
10# though it has gotten somewhat better over time, it only parses the 10# though it has gotten somewhat better over time, it only parses the
11# simpler Makefile conditionals. 11# simpler Makefile conditionals.
12# 12#
13# TODO: Handle fun DEPENDS like avifile-devel with 13# TODO: Handle fun DEPENDS like avifile-devel with
14# {qt2-designer>=2.2.4,qt2-designer-kde>=2.3.1nb1} 14# {qt2-designer>=2.2.4,qt2-designer-kde>=2.3.1nb1}
15 15
16use locale; 16use locale;
@@ -869,68 +869,74 @@ sub list_pkgsrc_pkgdirs($$) { @@ -869,68 +869,74 @@ sub list_pkgsrc_pkgdirs($$) {
869 && $_ ne 'pkg' 869 && $_ ne 'pkg'
870 && $_ ne 'CVS' 870 && $_ ne 'CVS'
871 && substr($_, 0, 1) ne '.', 871 && substr($_, 0, 1) ne '.',
872 readdir(CAT)); 872 readdir(CAT));
873 closedir(CAT); 873 closedir(CAT);
874 @pkgdirs; 874 @pkgdirs;
875} 875}
876 876
877# Convert the glob pattern to a regular expression. 877# Convert the glob pattern to a regular expression.
878# Return '' if the regular expression equals the glob expression. 878# Return '' if the regular expression equals the glob expression.
879# Return undef on error. 879# Return undef on error.
880sub glob2regex($) { 880sub glob2regex($) {
881 my ($glob) = @_; 881 my ($glob) = @_;
882 my (@chars, $in_alt); 
883 my ($regex); 
884 882
885 @chars = split(//, $glob); 883 my @chars = split(//, $glob);
 884 my $alternative_depth = 0;
 885 my $regex = '';
886 while (defined($_ = shift @chars)) { 886 while (defined($_ = shift @chars)) {
887 if ($_ eq '*') { 887 if ($_ eq '*') {
888 $regex .= '.*'; 888 $regex .= '.*';
889 } elsif ($_ eq '?') { 889 } elsif ($_ eq '?') {
890 $regex .= '.'; 890 $regex .= '.';
891 } elsif ($_ eq '+') { 891 } elsif ($_ eq '+') {
892 $regex .= '\\+'; 892 $regex .= '\\+';
893 } elsif ($_ eq '\\') { 893 } elsif ($_ eq '\\' && @chars > 0) {
894 $regex .= $_ . shift @chars; 894 my $next = shift @chars;
 895 $regex .= $next =~ /\w/ ? "$next" : "\\$next";
895 } elsif ($_ eq '.' || $_ eq '|') { 896 } elsif ($_ eq '.' || $_ eq '|') {
896 $regex .= quotemeta; 897 $regex .= quotemeta;
897 } elsif ($_ eq '{') { 898 } elsif ($_ eq '{') {
898 $regex .= '('; 899 $regex .= '(';
899 ++$in_alt; 900 ++$alternative_depth;
900 } elsif ($_ eq '}') { 901 } elsif ($_ eq '}') {
901 if (!$in_alt) { 902 if ($alternative_depth == 0) {
902 # Error 903 # Error
903 return undef; 904 return undef;
904 } 905 }
905 $regex .= ')'; 906 $regex .= ')';
906 --$in_alt; 907 --$alternative_depth;
907 } elsif ($_ eq ',' && $in_alt) { 908 } elsif ($_ eq ',' && $alternative_depth) {
908 $regex .= '|'; 909 $regex .= '|';
 910 } elsif ($_ eq '[') {
 911 $regex .= '[';
 912 while (defined($_ = shift @chars)) {
 913 $regex .= $_;
 914 if ($_ eq ']') {
 915 last;
 916 } elsif ($_ eq '\\' && @chars > 0) {
 917 $regex .= shift @chars;
 918 }
 919 }
 920 return undef if $_ ne ']';
909 } else { 921 } else {
910 $regex .= $_; 922 $regex .= $_;
911 } 923 }
912 } 924 }
913 925
914 if ($in_alt) { 926 return undef if $alternative_depth > 0;
915 # Error 927 return '' if $regex eq $glob; # XXX: why?
916 return undef; 928
917 } 929 $opt{D} and print "glob2regex: $glob -> $regex\n";
918 if ($regex eq $glob) { 
919 return (''); 
920 } 
921 if ($opt{D}) { 
922 print "glob2regex: $glob -> $regex\n"; 
923 } 
924 '^' . $regex . '$'; 930 '^' . $regex . '$';
925} 931}
926 932
927# Perform some (reasonable) subset of 'pkg_info -e' / glob(3) 933# Perform some (reasonable) subset of 'pkg_info -e' / glob(3)
928# Returns (sometimes best guess at) package name, 934# Returns (sometimes best guess at) package name,
929# and either 'problem version' or undef if all OK 935# and either 'problem version' or undef if all OK
930# 936#
931sub package_globmatch($) { 937sub package_globmatch($) {
932 my ($pkgmatch) = @_; 938 my ($pkgmatch) = @_;
933 my ($matchpkgname, $matchver, $regex); 939 my ($matchpkgname, $matchver, $regex);
934 940
935 if ($pkgmatch =~ /^([^*?[]+)(<|>|<=|>=|-)(\d[^*?[{]*)$/) { 941 if ($pkgmatch =~ /^([^*?[]+)(<|>|<=|>=|-)(\d[^*?[{]*)$/) {
936 942

cvs diff -r1.5 -r1.6 pkgsrc/pkgtools/lintpkgsrc/files/t/glob.t (expand / switch to unified diff)

--- pkgsrc/pkgtools/lintpkgsrc/files/t/glob.t 2022/08/09 18:14:22 1.5
+++ pkgsrc/pkgtools/lintpkgsrc/files/t/glob.t 2022/08/09 18:35:43 1.6
@@ -1,56 +1,59 @@ @@ -1,56 +1,59 @@
1# $NetBSD: glob.t,v 1.5 2022/08/09 18:14:22 rillig Exp $ 1# $NetBSD: glob.t,v 1.6 2022/08/09 18:35:43 rillig Exp $
2 2
3use strict; 3use strict;
4use warnings; 4use warnings;
5use Test; 5use Test;
6 6
7BEGIN { plan tests => 12, onfail => sub { die } } 7BEGIN { plan tests => 12, onfail => sub { die } }
8 8
9require('../lintpkgsrc.pl'); 9require('../lintpkgsrc.pl');
10 10
11sub test_glob2regex() { 11sub test_glob2regex() {
12 12
13 ok(glob2regex('*'), '^.*$'); 13 ok(glob2regex('*'), '^.*$');
 14 ok(glob2regex('\*'), '');
14 15
15 ok(glob2regex('?'), '^.$'); 16 ok(glob2regex('?'), '^.$');
 17 ok(glob2regex('\?'), '');
16 18
17 ok(glob2regex('[a-z]'), ''); 19 # Ordinary characters in glob patterns.
 20 ok(glob2regex('+'), '^\+$');
 21 ok(glob2regex('\+'), '');
 22 ok(glob2regex('|'), '^\|$');
 23 ok(glob2regex('\|'), '');
 24
 25 ok(glob2regex('\.'), '');
 26 ok(glob2regex('\n'), '^n$');
 27 ok(glob2regex('\\\\'), '');
 28 ok(glob2regex('\['), '');
 29 ok(glob2regex('\{'), '');
 30 ok(glob2regex('\-'), '');
18 31
 32 ok(glob2regex('[a-z]'), '');
19 ok(glob2regex('[a-z0-9]'), ''); 33 ok(glob2regex('[a-z0-9]'), '');
20 
21 ok(glob2regex('[a-z0-9_]'), ''); 34 ok(glob2regex('[a-z0-9_]'), '');
22 35 ok(glob2regex('[*]'), '');
23 # Outside of braces, the ',' is a regular character. 
24 ok(glob2regex('a,b'), ''); 
25 
26 # FIXME: Inside brackets, the '*' is a literal '*'. 
27 ok(glob2regex('[*]'), '^[.*]$'); 
28 
29 ok(glob2regex('\*'), ''); 
30 36
31 ok(glob2regex('*.[ch]'), '^.*\.[ch]$'); 37 ok(glob2regex('*.[ch]'), '^.*\.[ch]$');
32 38
 39 # Outside of braces, the ',' is a regular character.
 40 ok(glob2regex('a,b'), '');
33 ok(glob2regex('{one,two}'), '^(one|two)$'); 41 ok(glob2regex('{one,two}'), '^(one|two)$');
34 
35 ok(glob2regex('{{thi,fou}r,fif}teen'), '^((thi|fou)r|fif)teen$'); 42 ok(glob2regex('{{thi,fou}r,fif}teen'), '^((thi|fou)r|fif)teen$');
36 43
37 # There is an unbalanced '}' at the very end. 44 # There is an unbalanced '}' at the very end.
38 ok(glob2regex('{{thi,fou}r,fif}teen}'), undef); 45 ok(glob2regex('{four,fif}teen}'), undef);
39 
40 ok(glob2regex('a+b|c'), '^a\+b\|c$'); 
41 46
 47 # An escaped '[' does not start a character class.
42 ok(glob2regex('a\[b*'), '^a\[b.*$'); 48 ok(glob2regex('a\[b*'), '^a\[b.*$');
43 49
44 ok(glob2regex('a\+b'), ''); 50 ok(glob2regex('a\n*'), '^an.*$');
45 
46 ok(glob2regex('a\?b'), ''); 
47 
48 # XXX: Depending on the exact implementation, the '\n' may be 
49 # interpreted as a newline, a literal 'n' or a literal '\' 'n'. 
50 ok(glob2regex('a\n*'), '^a\n.*$'); 
51 51
52 # https://gnats.netbsd.org/12996 52 # https://gnats.netbsd.org/12996
53 ok(glob2regex('libsigc++'), '^libsigc\+\+$'); 53 ok(glob2regex('libsigc++'), '^libsigc\+\+$');
 54
 55 my $re = 'a\nb';
 56 ok("a\nb" =~ $re, 1);
54} 57}
55 58
56test_glob2regex(); 59test_glob2regex();