# $Id: Utils.pm,v 0.10 2001/09/07 17:23:38 pcollins Exp $ package HTTP::DAV::Utils; $VERSION = sprintf("%d.%02d", q$Revision: 0.10 $ =~ /(\d+)\.(\d+)/); use strict; use vars qw($VERSION); ########################################################################### # Borrowed from Lincoln Stein's CGI.pm # Smart rearrangement of parameters to allow named parameter # calling. We do the rearangement if: # 1. The first parameter begins with a - # 2. The use_named_parameters() method returns true sub rearrange { my($order,@param) = @_; return () unless @param; # IF the user has passed a hashref instead of a hash then flatten it out. if (ref($param[0]) eq 'HASH') { @param = %{$param[0]}; } else { # If the user has specified that they will be explicitly # using named_parameters (by setting &use_named_parameters(1)) # or the first parameter starts with a -, then continue. # Otherwise just return the parameters as they were given to us. return @param unless (defined($param[0]) && substr($param[0],0,1) eq '-') || &use_named_parameters(); } # map parameters into positional indices my ($i,%pos); $i = 0; foreach (@$order) { foreach (ref($_) eq 'ARRAY' ? @$_ : $_) { $pos{$_} = $i; } $i++; } my (@result,%leftover); $#result = $#$order; # preextend while (@param) { my $key = uc(shift(@param)); $key =~ s/^\-//; if (exists $pos{$key}) { $result[$pos{$key}] = shift(@param); } else { $leftover{$key} = shift(@param); } } push (@result,&make_attributes(\%leftover)) if %leftover; @result; } #### Method: use_named_parameters # Borrowed from Lincoln Stein's CGI.pm # Force DAV.pm to use named parameter-style method calls # rather than positional parameters. The same effect # will happen automatically if the first parameter # begins with a -. my $named=0; sub use_named_parameters { my($use_named) = shift; return $named unless defined ($use_named); # stupidity to avoid annoying warnings return $named = $use_named; } # Borrowed from Lincoln Stein's CGI.pm sub make_attributes { my($attr) = @_; return () unless $attr && ref($attr) && ref($attr) eq 'HASH'; my(@att); foreach (keys %{$attr}) { my($key) = $_; $key=~s/^\-//; # get rid of initial - if present $key=~tr/a-z_/A-Z-/; # parameters are upper case, use dashes push(@att,defined($attr->{$_}) ? qq/$key="$attr->{$_}"/ : qq/$key/); } return @att; } ########################################################################### sub bad { my($str) = @_; print STDERR "Error: $str\n"; exit; } sub bad_node { my($node,$str) = @_; print STDERR "XML error in " . $node->getNodeName . ": $str"; print STDERR "\n"; print STDERR "DUMP:\n"; print STDERR $node->toString if $node; exit; } ########################################################################### # This method searches for any text-based data in the children of # the node supplied. It will croak if the node has anything other # than text values (such as Elements or Comments). sub get_only_cdata { my($node) = @_; my $return_cdata = ""; my $nodes = $node->getChildNodes(); my $n = $nodes->getLength; for (my $i = 0; $i < $n; $i++) { my $node = $nodes->item($i); if ( $node->getNodeTypeName eq "TEXT_NODE" ) { $return_cdata .= $node->getNodeValue; } else { #bad_node($node, "node has non TEXT children"); } } return $return_cdata; } # This is a sibling to the XML::DOM's getElementsByTagName(). # The main difference here is that it ignores the namespace # component of the element. This was done because it # Takes a node and returns a list of nodes. # Note that the real getElementsByTagName allows you to # specify recurse or not. This routine doesn't allow recurse. sub get_elements_by_tag_name { my ($node, $elemname ) = @_; return unless $node; my @return_nodes; # This is gruesome. Because we don't yet support namespaces, it # just lops off the first half of the Element name $elemname =~ s/.*?:(.*)$/$1/g; my $nodelist = $node->getChildNodes(); my $length = $nodelist->getLength(); for ( my $i=0; $i < $length; $i++ ) { my $node = $nodelist->item($i); if ( $node->getNodeName() =~ /:$elemname$/ ) { push(@return_nodes,$node); } } return @return_nodes; } sub get_only_element { my($node,$elemname) = @_; return unless $node; # Find the one child element of a specific name if ( $elemname ) { # This is gruesome. Because we don't yet support namespaces, it # just lops off the first half of the Element name. $elemname =~ s/.*?:(.*)$/$1/g; #my $nodes = $node->getElementsByTagName($elemname,0); my $nodelist = $node->getChildNodes(); my $length = $nodelist->getLength(); for ( my $i=0; $i < $length; $i++ ) { my $node = $nodelist->item($i); return $node if $node->getNodeName() =~ /$elemname/; } # if ( $nodes->getLength > 1 ) { # bad_node($node, "Too many \"$elemname\" in node"); # } elsif ( $nodes->getLength < 1 ) { # return; # #bad_node($node, "No node found matching \"$elemname\" in node"); # } # return $nodes->item(0); # Just get the first child element. } else { my $nodelist = $node->getChildNodes(); my $length = $nodelist->getLength(); for ( my $i=0; $i < $length; $i++ ) { my $node = $nodelist->item($i); if ($node->getNodeTypeName eq "ELEMENT_NODE" ) { return $nodelist->item($i); } } } } ########################################################################### sub XML_remove_namespace { #print "XML: $_[0] -> "; $_[0] =~ s/.*?:(.*)/$1/g; #$_[0] =~ s/(.*?)\s.*/$1/g; #print "$_[0]\n"; return $_[0]; } ########################################################################### sub make_uri { my $uri = shift; if ( ref($uri) =~ /URI/ ) { $uri = $uri->as_string; } #$uri =~ "http://$uri" unless $uri=~ /^http:\/\//; #if $uri = "" return URI->new(); # Remove double slashes from the url $uri =URI->new($uri); my $path =$uri->path; $path =~ s#//#/#g; #print "make_uri: $uri->$path\n"; $uri->path($path); #print "make_uri: $uri\n"; return $uri; } sub make_trail_slash { my ($uri) = @_; $uri =~ s#/*$##g; $uri.="/"; return $uri; } sub compare_uris { my ($uri1,$uri2) = @_; $uri1 = make_uri($uri1); $uri2 = make_uri($uri2); $uri1=~s#\/$##g; $uri2=~s#\/$##g; $uri1 eq $uri2; } # This subroutine takes a URI and gets the last portion # of it: the filename. # e.g. /dir1/dir2/file.txt => file.txt # /dir1/dir2/ => dir2 # / => undef sub get_leafname { my($url) = shift; my $leaf; ($url,$leaf) = &split_leaf($url); return $leaf; } # This subroutine takes a URI and splits the leaf from the path. # It returns both. # of it: the filename. # e.g. /dir1/dir2/file.txt => file.txt # /dir1/dir2/ => dir2 # / => undef sub split_leaf { my($url) = shift; $url =~ s#[\/\\]$##; #Remove trailing slashes. $url = HTTP::DAV::Utils::make_uri($url); # Remove the leaf from the path. my $path = $url->path_query(); my @path = split(/[\/\\]+/,$path); my $leaf = pop @path || ""; $path = join('/',@path); #Now put the path back into the URL. $url->path_query($path); return ($url,$leaf); } # Turns a file-oriented glob # into a regular expression. # BTW, I recommend you eval any regex command you use on # this outputted regex value. # If somebody types uses an incorrect glob and you try to /$regex/ it # then perl will bomb with a fatal regex error. # For instance, /file[ab.txt/ would bomb. sub glob2regex { my($f) = @_; # Turn the leafname glob into a regex. # Substitute \ for \\ # Substitute . for \. # Substitute * for .* # Substitute ? for . # No need to substitute [...] $f =~ s/\\/\\\\/g; $f =~ s/\./\\./g; $f =~ s/\*/.*/g; $f =~ s/\?/./g; print "Glob regex becomes $f\n" if $HTTP::DAV::DEBUG>1; return $f; } 1;