File Coverage

blib/lib/Win32/ShellQuote.pm
Criterion Covered Total %
statement 61 68 89.7
branch 22 28 78.5
condition 8 12 66.6
subroutine 14 16 87.5
pod 8 10 80.0
total 113 134 84.3


line stmt bran cond sub pod time code
1             package Win32::ShellQuote;
2 3     3   66303 use strict;
  3         8  
  3         100  
3 3     3   18 use warnings FATAL => 'all';
  3         6  
  3         122  
4 3     3   16 use base 'Exporter';
  3         5  
  3         327  
5 3     3   20 use Carp;
  3         10  
  3         3403  
6              
7             our $VERSION = '0.003000';
8             $VERSION = eval $VERSION;
9              
10             our @EXPORT_OK = qw(
11             quote_native
12             quote_cmd
13             quote_system_list
14             quote_system_string
15             quote_system
16             quote_system_cmd
17             quote_literal
18             cmd_escape
19             unquote_native
20             cmd_unescape
21             );
22             our %EXPORT_TAGS = (all => [@EXPORT_OK]);
23              
24             sub quote_native {
25 141     141 1 50647 return join q{ }, quote_system_list(@_);
26             }
27              
28             sub quote_cmd {
29 47     47 1 261 return cmd_escape(quote_native(@_));
30             }
31              
32             sub quote_system_list {
33             # have to force quoting, or perl might try to use cmd anyway
34 141     141 1 197 return map { quote_literal($_, 1) } @_;
  144         258  
35             }
36              
37             sub quote_system_string {
38 47     47 1 260 my $args = quote_native(@_);
39              
40 47 100       103 if (_has_shell_metachars($args)) {
41 11         20 $args = cmd_escape($args);
42             }
43 47         124 return $args;
44             }
45              
46             sub quote_system {
47 0 0   0 1 0 if (@_ > 1) {
48 0         0 return quote_system_list(@_);
49             }
50             else {
51 0         0 return quote_system_string(@_);
52             }
53             }
54              
55             sub quote_system_cmd {
56             # force cmd, even when running through system
57 0     0 1 0 my $args = quote_native(@_);
58              
59 0 0       0 if (! _has_shell_metachars($args)) {
60             # IT BURNS LOOK AWAY
61 0         0 return '%PATH:~0,0%' . cmd_escape($args);
62             }
63 0         0 return cmd_escape($args);
64             }
65              
66              
67             sub cmd_escape {
68 58     58 1 81 my $string = shift;
69 58 100       159 if ($string =~ /[\r\n\0]/) {
70 6         813 croak "can't quote newlines to pass through cmd.exe";
71             }
72 52         414 $string =~ s/([()%!^"<>&|])/^$1/g;
73 52         157 return $string;
74             }
75              
76             sub quote_literal {
77 144     144 1 265 my ($text, $force) = @_;
78              
79             # basic argument quoting. uses backslashes and quotes to escape
80             # everything.
81 144 50 33     443 if (!$force && $text ne '' && $text !~ /[ \t\n\x0b"]/) {
      33        
82             # no quoting needed
83             }
84             else {
85 144         1596 $text =~ s{(\\*)(?="|\z)}{$1$1}g;
86 144         372 $text =~ s{"}{\\"}g;
87 144         291 $text = qq{"$text"};
88             }
89              
90 144         584 return $text;
91             }
92              
93             # derived from rules in code in win32.c
94             sub _has_shell_metachars {
95 47     47   62 my $string = shift;
96              
97 47 100       120 return 1
98             if $string =~ /%/;
99 43         205 $string =~ s/(['"]).*?(\1|\z)//sg;
100 43         137 return $string =~ /[<>|]/;
101             }
102              
103             sub unquote_native {
104 51     51 0 23587 local ($_) = @_;
105 51         71 my @argv;
106              
107 51 100       125 my $length = length
108             or return @argv;
109              
110 49         151 m/\G\s*/gc;
111              
112 49         118 ARGS: until ( pos == $length ) {
113 68         75 my $quote_mode;
114 68         84 my $arg = '';
115 68         135 CHARS: until ( pos == $length ) {
116 297 100 100     1577 if ( m/\G((?:\\\\)+)(?=\\?(")?)/gc ) {
    100          
    100          
    100          
    50          
117 10 100       20 if (defined $2) {
118 7         27 $arg .= '\\' x (length($1) / 2);
119             }
120             else {
121 3         8 $arg .= $1;
122             }
123             }
124             elsif ( m/\G\\"/gc ) {
125 16         38 $arg .= '"';
126             }
127             elsif ( m/\G"/gc ) {
128 127 100 100     399 if ( $quote_mode && m/\G"/gc ) {
129 14         21 $arg .= '"';
130             }
131 127         294 $quote_mode = !$quote_mode;
132             }
133             elsif ( !$quote_mode && m/\G\s+\z?/gc ) {
134 20         29 last;
135             }
136             elsif ( m/\G(.)/sgc ) {
137 124         334 $arg .= $1;
138             }
139             }
140 68         214 push @argv, $arg;
141             }
142              
143 49         207 return @argv;
144             }
145              
146             sub cmd_unescape {
147 13     13 0 1594 my ($string) = @_;
148              
149 3     3   22 no warnings 'uninitialized';
  3         5  
  3         395  
150 13         312 $string =~ s/\^(.?)|([^^"]+)|("[^"]*(?:"|\z))/$1$2$3/gs;
151              
152 13         35 return $string;
153             }
154              
155             1;
156              
157             __END__