our
$DATE
=
'2019-09-12'
;
our
$VERSION
=
'0.004005'
;
my
$has_globstar
;
sub
import
{
my
$pkg
=
shift
;
my
$caller
=
caller
;
for
my
$sym
(
@_
) {
if
(
$sym
eq
'list_modules'
) { *{
"$caller\::$sym"
} = \&{
$sym
} }
else
{
die
"$sym is not exported!"
}
}
}
sub
list_modules($$) {
my
(
$prefix
,
$options
) =
@_
;
my
$trivial_syntax
=
$options
->{trivial_syntax};
my
(
$root_leaf_rx
,
$root_notleaf_rx
);
my
(
$notroot_leaf_rx
,
$notroot_notleaf_rx
);
if
(
$trivial_syntax
) {
$root_leaf_rx
=
$notroot_leaf_rx
=
qr#:?(?:[^/:]+:)*[^/:]+:?#
;
$root_notleaf_rx
=
$notroot_notleaf_rx
=
qr#:?(?:[^/:]+:)*[^/:]+#
;
}
else
{
$root_leaf_rx
=
$root_notleaf_rx
=
qr/[a-zA-Z_][0-9a-zA-Z_]*/
;
$notroot_leaf_rx
=
$notroot_notleaf_rx
=
qr/[0-9a-zA-Z_]+/
;
}
my
$recurse
=
$options
->{recurse};
my
$re_wildcard
;
if
(
$options
->{wildcard}) {
my
$orig_prefix
=
$prefix
;
my
@prefix_parts
=
split
/::/,
$prefix
;
$prefix
=
""
;
my
$has_wildcard
;
while
(
defined
(
my
$part
=
shift
@prefix_parts
)) {
if
(String::Wildcard::Bash::contains_wildcard(
$part
)) {
$has_wildcard
++;
$recurse
= 1
if
@prefix_parts
;
last
;
}
else
{
$prefix
.=
"$part\::"
;
}
}
if
(
$has_wildcard
) {
$re_wildcard
= convert_wildcard_to_re(
$orig_prefix
);
}
$recurse
= 1
if
$has_globstar
;
}
die
"bad module name prefix `$prefix'"
unless
$prefix
=~ /\A(?:${root_notleaf_rx}::
(?:${notroot_notleaf_rx}::)*)?\z/x &&
$prefix
!~ /(?:\A|[^:]::)\.\.?::/;
my
$list_modules
=
$options
->{list_modules};
my
$list_prefixes
=
$options
->{list_prefixes};
my
$list_pod
=
$options
->{list_pod};
my
$use_pod_dir
=
$options
->{use_pod_dir};
return
{}
unless
$list_modules
||
$list_prefixes
||
$list_pod
;
my
$return_path
=
$options
->{return_path};
my
$all
=
$options
->{all};
my
@prefixes
= (
$prefix
);
my
%seen_prefixes
;
my
%results
;
while
(
@prefixes
) {
my
$prefix
=
pop
(
@prefixes
);
my
@dir_suffix
=
split
(/::/,
$prefix
);
my
$module_rx
=
$prefix
eq
""
?
$root_leaf_rx
:
$notroot_leaf_rx
;
my
$pm_rx
=
qr/\A($module_rx)\.pmc?\z/
;
my
$pod_rx
=
qr/\A($module_rx)\.pod\z/
;
my
$dir_rx
=
$prefix
eq
""
?
$root_notleaf_rx
:
$notroot_notleaf_rx
;
$dir_rx
=
qr/\A$dir_rx\z/
;
foreach
my
$incdir
(
@INC
) {
my
$dir
=
join
(
"/"
,
$incdir
,
@dir_suffix
);
opendir
(
my
$dh
,
$dir
) or
next
;
while
(
defined
(
my
$entry
=
readdir
(
$dh
))) {
if
((
$list_modules
&&
$entry
=~
$pm_rx
) ||
(
$list_pod
&&
$entry
=~
$pod_rx
)) {
my
$key
=
$prefix
.$1;
next
if
$re_wildcard
&&
$key
!~
$re_wildcard
;
$results
{
$key
} =
$return_path
? (
$all
? [@{
$results
{
$key
} || [] },
"$dir/$entry"
] :
"$dir/$entry"
) :
undef
if
$all
&&
$return_path
|| !
exists
(
$results
{
$key
});
}
elsif
((
$list_prefixes
||
$recurse
) &&
(
$entry
ne
'.'
&&
$entry
ne
'..'
) &&
$entry
=~
$dir_rx
&&
-d
join
(
"/"
,
$dir
,
$entry
)) {
my
$newmod
=
$prefix
.
$entry
;
my
$newpfx
=
$newmod
.
"::"
;
next
if
exists
$seen_prefixes
{
$newpfx
};
$results
{
$newpfx
} =
$return_path
? (
$all
? [@{
$results
{
$newpfx
} || [] },
"$dir/$entry/"
] :
"$dir/$entry/"
) :
undef
if
(
$all
&&
$return_path
|| !
exists
(
$results
{
$newpfx
})) &&
$list_prefixes
;
push
@prefixes
,
$newpfx
if
$recurse
;
}
}
next
unless
$list_pod
&&
$use_pod_dir
;
$dir
=
join
(
"/"
,
$dir
,
"pod"
);
opendir
(
$dh
,
$dir
) or
next
;
while
(
defined
(
my
$entry
=
readdir
(
$dh
))) {
if
(
$entry
=~
$pod_rx
) {
my
$key
=
$prefix
.$1;
next
if
$re_wildcard
&&
$key
!~
$re_wildcard
;
$results
{
$key
} =
$return_path
? (
$all
? [@{
$results
{
$key
} || [] },
"$dir/$entry"
] :
"$dir/$entry"
) :
undef
;
}
}
}
}
if
(
$list_prefixes
&&
$re_wildcard
) {
for
my
$k
(
keys
%results
) {
next
unless
$k
=~ /::\z/;
(
my
$k_nocolon
=
$k
) =~ s/::\z//;
delete
$results
{
$k
}
unless
$k
=~
$re_wildcard
||
$k_nocolon
=~
$re_wildcard
;
}
}
return
\
%results
;
}
sub
convert_wildcard_to_re {
$has_globstar
= 0;
my
$re
= _convert_wildcard_to_re(
@_
);
$re
=
qr/\A$re\z/
;
$re
;
}
sub
_convert_wildcard_to_re {
my
$opts
=
ref
$_
[0] eq
'HASH'
?
shift
: {};
my
$str
=
shift
;
my
$opt_brace
=
$opts
->{brace} // 1;
my
@res
;
my
$p
;
while
(
$str
=~ /
$String::Wildcard::Bash::RE_WILDCARD_BASH
/g) {
my
%m
= %+;
if
(
defined
(
$p
=
$m
{bash_brace_content})) {
push
@res
,
quotemeta
(
$m
{slashes_before_bash_brace})
if
$m
{slashes_before_bash_brace};
if
(
$opt_brace
) {
my
@elems
;
while
(
$p
=~ /(
$String::Wildcard::Bash::re_bash_brace_element
)(,|\z)/g) {
push
@elems
, $1;
last
unless
$2;
}
push
@res
,
"(?:"
,
join
(
"|"
,
map
{
convert_wildcard_to_re({
bash_brace
=> 0,
},
$_
)}
@elems
),
")"
;
}
else
{
push
@res
,
quotemeta
(
$m
{bash_brace});
}
}
elsif
(
defined
(
$p
=
$m
{bash_joker})) {
if
(
$p
eq
'?'
) {
push
@res
,
'[^:]'
;
}
elsif
(
$p
eq
'*'
) {
push
@res
,
'[^:]*'
;
}
elsif
(
$p
eq
'**'
) {
$has_globstar
++;
push
@res
,
'.*'
;
}
}
elsif
(
defined
(
$p
=
$m
{literal_brace_single_element})) {
push
@res
,
quotemeta
(
$p
);
}
elsif
(
defined
(
$p
=
$m
{bash_class})) {
push
@res
,
$p
;
}
elsif
(
defined
(
$p
=
$m
{sql_joker})) {
push
@res
,
quotemeta
(
$p
);
}
elsif
(
defined
(
$p
=
$m
{literal})) {
push
@res
,
quotemeta
(
$p
);
}
}
join
""
,
@res
;
}
1;