Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Re: rel2abs of a path with env (updated)

by haukex (Bishop)
on Jun 07, 2021 at 15:16 UTC ( #11133627=note: print w/replies, xml ) Need Help??


in reply to rel2abs of a path with env

I agree with hippo that this seems to be moving into XY Problem territory. What about /a/b/c/\$USER? Or /a/b/c/\\$USER? Or malformed inputs like /a/b/c/${USER? And what other possible inputs haven't you told us about?

Enough rope to shoot yourself in the foot:

use warnings; use strict; sub interpolate { local $_ = shift; my $vars = shift; my @out; pos=undef; while (1) { if ( m{\G ( [^\\\$]+ ) }xmsgc ) { push @out, $1 } elsif ( m{\G \$ (?| (\w+) | \{(\w+)\} ) }xmsgc ) { push @out, $vars->{$1} } elsif ( m{\G \\ (.) }xmsgc ) { $1 eq "\\" or $1 eq "\$" or die "unexpected backslash escape"; push @out, $1; } else { last } } die "parse of '$_' failed at pos ".(pos//0) if !defined pos || pos!=length; return join '', @out; } use Test::More; sub exception (&) { eval { shift->(); 1 } ? undef : ($@ || die) } my %env = ( USER => "foobar", quz => "\$baz \\\\ \\\$" ); is interpolate("USER", \%env), "USER"; like exception { interpolate("\\USER"), \%env }, qr/\bunexpected backslash\b/; is interpolate("\\\\USER", \%env), "\\USER"; is interpolate("\$USER", \%env), "foobar"; is interpolate("\${USER}", \%env), "foobar"; is interpolate("\\\$USER", \%env), "\$USER"; is interpolate("\\\\\$USER", \%env), "\\foobar"; is interpolate("\\\\\\\$USER", \%env), "\\\$USER"; is interpolate("\\\\\\\\\$USER", \%env), "\\\\foobar"; is interpolate("\\\\\\\\\${USER}", \%env), "\\\\foobar"; is interpolate("\$quz", \%env), "\$baz \\\\ \\\$"; like exception { interpolate("USER\$"), \%env }, qr/\bparse of 'USER\$' failed\b/; like exception { interpolate("\${USER"), \%env }, qr/\bparse of '\$\{USER' failed\b/; done_testing;

I wouldn't necessarily recommend doing much more (e.g. String::Interpolate), as otherwise you may end up opening a security hole.

Update: I realized that the code I posted originally (below) would also unescape backslashes and $s in the values of variables interpolated into the string, so I rewrote the parser using m/\G/gc regexes above. It should now also be more roboust in the face of invalid inputs. The only minor downside is that now integrating String::Unescape isn't quite as easy.

Original code:

use warnings; use strict; use Test::More; sub exception (&) { eval { shift->(); 1 } ? undef : ($@ || die) } my %_interp_map = ( '\\'=>'\\', '$'=>'$' ); # or use String::Unescape sub interpolate { my $str = shift; $str =~ s{ (?<!\\) ((?:\\\\)*) \$ (?| (\w+) | \{(\w+)\} ) } { $1.$ENV{$2} }xeg; $str =~ s{ \\ (.) } { $_interp_map{$1} || die "unexpected backslash escape" }xeg; return $str; } local $ENV{USER} = "foobar"; is interpolate("USER"), "USER"; like exception { interpolate("\\USER") }, qr/unexpected backslash/i; is interpolate("\\\\USER"), "\\USER"; is interpolate("\$USER"), "foobar"; is interpolate("\${USER}"), "foobar"; is interpolate("\\\$USER"), "\$USER"; is interpolate("\\\\\$USER"), "\\foobar"; is interpolate("\\\\\\\$USER"), "\\\$USER"; is interpolate("\\\\\\\\\$USER"), "\\\\foobar"; is interpolate("\\\\\\\\\${USER}"), "\\\\foobar"; done_testing;

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11133627]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (2)
As of 2021-07-31 12:40 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?