Ted Zlatanov <tzz@xxxxxxxxxxxx> writes: > + unless (scalar @entries) { > + if ($!) { > + log_verbose("Unable to open $file: $!"); > + } > + else { } else { > + log_verbose("No netrc entries found in $file"); > + } > + > + if ($gpgmode) { > + # typical shell character escapes from http://www.slac.stanford.edu/slac/www/resource/how-to-use/cgi-rexx/cgi-esc.html > + my $f = $file; > + $f =~ s/([;<>\*\|`&\$!#\(\)\[\]\{\}:'"])/\\$1/g; Yuck. If you really have to quote, it is often far simpler to take advantage of the fact that quoting rule for shell is much simpler inside '', i.e. sub sq { my ($string) = @_; $string =~ s|'|'\\''|g; return "'$string'"; } The only thing you have to worry about is a single quote, which would close the single quote you want to be in, and you express it by first closing the single quote you opened, put the single quote by emitting a backslash and a single quote, and then immediately open another single quote. > + # GPG doesn't work well with 2- or 3-argument open I think I commented on this in a separate message. > + # Net::Netrc does this, but the functionality is merged with the file > + # detection logic, so we have to extract just the part we need > + my @netrc_entries = net_netrc_loader($io); > + > + # these entries will use the credential helper protocol token names > + my @entries; > + > + foreach my $nentry (@netrc_entries) { > + my %entry; > + my $num_port; > + > + if (defined $nentry->{port} && $nentry->{port} =~ m/^\d+$/) { > + $num_port = $nentry->{port}; > + delete $nentry->{port}; > + } > + > + # create the new entry for the credential helper protocol > + $entry{$options{tmap}->{$_}} = $nentry->{$_} foreach keys %$nentry; > + > + # for "host X port Y" where Y is an integer (captured by > + # $num_port above), set the host to "X:Y" > + if (defined $entry{host} && defined $num_port) { > + $entry{host} = join(':', $entry{host}, $num_port); > + } > + > + push @entries, \%entry; > + } > + > + return @entries; > +} I'll leave this part to Peff to comment on. > +sub net_netrc_loader { > + my $fh = shift @_; > + my @entries; > + my ($mach, $macdef, $tok, @tok); > + > + LINE: > + while (<$fh>) { > + undef $macdef if /\A\n\Z/; > + > + if ($macdef) { > + next LINE; > + } > + > + s/^\s*//; > + chomp; > + > + while (length && s/^("((?:[^"]+|\\.)*)"|((?:[^\\\s]+|\\.)*))\s*//) { > + (my $tok = $+) =~ s/\\(.)/$1/g; > + push(@tok, $tok); > + } > + > + TOKEN: > + while (@tok) { > + if ($tok[0] eq "default") { > + shift(@tok); > + undef $mach; # ignore 'default' lines I think it is saner to do something like this instead here: $mach = { machine => undef } Otherwise your log_debug() will be filled by the tokens used for the default entry, and also this "undef $mach" here will break your macdef skipping logic if the default entry has a macdef, I think. You can ignore an entry with undefined "machine" in the loop at the end of load_netrc. > + next TOKEN; > + } > + > + $tok = shift(@tok); > + > + if ($tok eq "machine") { > + my $host = shift @tok; > + $mach = { machine => $host }; > + push @entries, $mach; > + } > + elsif (exists $options{tmap}->{$tok}) { > + unless ($mach) { > + log_debug("Skipping token $tok because no machine was given"); > + next TOKEN; > + } > + > + my $value = shift @tok; > + unless (defined $value) { > + log_debug("Token $tok had no value, skipping it."); > + next TOKEN; > + } > + > + # Following line added by rmerrell to remove '/' escape char in .netrc > + $value =~ s/\/\\/\\/g; > + $mach->{$tok} = $value; > + } > + elsif ($tok eq "macdef") { # we ignore macros > + next TOKEN unless $mach; > + my $value = shift @tok; > + $macdef = 1; > + } > + } > + } > + > + return @entries; > +} > + > +sub read_credential_data_from_stdin { > + # the query: start with every token with no value > + my %q = map { $_ => undef } values(%{$options{tmap}}); > + > + while (<STDIN>) { > + next unless m/^([^=]+)=(.+)/; > + > + my ($token, $value) = ($1, $2); > + die "Unknown search token $token" unless exists $q{$token}; > + $q{$token} = $value; > + log_debug("We were given search token $token and value $value"); > + } > + > + foreach (sort keys %q) { > + log_debug("Searching for %s = %s", $_, $q{$_} || '(any value)'); > + } > + > + return \%q; > +} > + > +# takes the search tokens and then a list of entries > +# each entry is a hash reference > +sub find_netrc_entry { > + my $query = shift @_; > + > + ENTRY: > + foreach my $entry (@_) > + { > + my $entry_text = join ', ', map { "$_=$entry->{$_}" } keys %$entry; > + foreach my $check (sort keys %$query) { > + if (defined $query->{$check}) { > + log_debug("compare %s [%s] to [%s] (entry: %s)", > + $check, > + $entry->{$check}, > + $query->{$check}, > + $entry_text); > + unless ($query->{$check} eq $entry->{$check}) { > + next ENTRY; > + } > + } > + else { > + log_debug("OK: any value satisfies check $check"); > + } > + } > + > + return $entry; > + } > + > + # nothing was found > + return; > +} I'll leave this part to Peff to comment on. > + > +sub print_credential_data { > + my $entry = shift @_; > + my $query = shift @_; > + > + log_debug("entry has passed all the search checks"); > + TOKEN: > + foreach my $git_token (sort keys %$entry) { > + log_debug("looking for useful token $git_token"); > + # don't print unknown (to the credential helper protocol) tokens > + next TOKEN unless exists $query->{$git_token}; > + > + # don't print things asked in the query (the entry matches them) > + next TOKEN if defined $query->{$git_token}; > + > + log_debug("FOUND: $git_token=$entry->{$git_token}"); > + printf "%s=%s\n", $git_token, $entry->{$git_token}; > + } > +} > +sub log_verbose { > + return unless $options{verbose}; > + printf STDERR @_; > + printf STDERR "\n"; > +} > + > +sub log_debug { > + return unless $options{debug}; > + printf STDERR @_; > + printf STDERR "\n"; > +} Otherwise, looks almost ready to me. Thanks. -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html