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   41270 use strict;
  3         5  
  3         75  
3 3     3   9 use warnings FATAL => 'all';
  3         3  
  3         103  
4 3     3   9 use base 'Exporter';
  3         5  
  3         249  
5 3     3   12 use Carp;
  3         3  
  3         2142  
6              
7             our $VERSION = '0.003001';
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 69301 return join q{ }, quote_system_list(@_);
26             }
27              
28             sub quote_cmd {
29 47     47 1 250 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 194 return map { quote_literal($_, 1) } @_;
  144         218  
35             }
36              
37             sub quote_system_string {
38 47     47 1 257 my $args = quote_native(@_);
39              
40 47 100       89 if (_has_shell_metachars($args)) {
41 11         21 $args = cmd_escape($args);
42             }
43 47         112 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       156 if ($string =~ /[\r\n\0]/) {
70 6         641 croak "can't quote newlines to pass through cmd.exe";
71             }
72 52         426 $string =~ s/([()%!^"<>&|])/^$1/g;
73 52         153 return $string;
74             }
75              
76             sub quote_literal {
77 144     144 1 193 my ($text, $force) = @_;
78              
79             # basic argument quoting. uses backslashes and quotes to escape
80             # everything.
81 144 50 33     476 if (!$force && $text ne '' && $text !~ /[ \t\n\x0b"]/) {
      33        
82             # no quoting needed
83             }
84             else {
85 144         1753 $text =~ s{(\\*)(?="|\z)}{$1$1}g;
86 144         348 $text =~ s{"}{\\"}g;
87 144         265 $text = qq{"$text"};
88             }
89              
90 144         575 return $text;
91             }
92              
93             # derived from rules in code in win32.c
94             sub _has_shell_metachars {
95 47     47   54 my $string = shift;
96              
97 47 100       111 return 1
98             if $string =~ /%/;
99 43         222 $string =~ s/(['"]).*?(\1|\z)//sg;
100 43         118 return $string =~ /[<>|]/;
101             }
102              
103             sub unquote_native {
104 53     53 0 22152 local ($_) = @_;
105 53         53 my @argv;
106              
107 53 100       103 my $length = length
108             or return @argv;
109              
110 51         150 m/\G\s*/gc;
111              
112 51         79 ARGS: until ( pos == $length ) {
113 71         56 my $quote_mode;
114 71         53 my $arg = '';
115 71         104 CHARS: until ( pos == $length ) {
116 313 100 100     999 if ( m/\G((?:\\\\)+)(?=\\?(")?)/gc ) {
    100          
    100          
    100          
    50          
117 10 100       14 if (defined $2) {
118 7         24 $arg .= '\\' x (length($1) / 2);
119             }
120             else {
121 3         5 $arg .= $1;
122             }
123             }
124             elsif ( m/\G\\"/gc ) {
125 16         23 $arg .= '"';
126             }
127             elsif ( m/\G"/gc ) {
128 131 100 100     275 if ( $quote_mode && m/\G"/gc ) {
129 14         14 $arg .= '"';
130             }
131 131         182 $quote_mode = !$quote_mode;
132             }
133             elsif ( !$quote_mode && m/\G\s+/gc ) {
134 23         17 last;
135             }
136             elsif ( m/\G(.)/sgc ) {
137 133         230 $arg .= $1;
138             }
139             }
140 71         128 push @argv, $arg;
141             }
142              
143 51         139 return @argv;
144             }
145              
146             sub cmd_unescape {
147 13     13 0 2009 my ($string) = @_;
148              
149 3     3   17 no warnings 'uninitialized';
  3         3  
  3         267  
150 13         151 $string =~ s/\^(.?)|([^^"]+)|("[^"]*(?:"|\z))/$1$2$3/gs;
151              
152 13         22 return $string;
153             }
154              
155             1;
156              
157             __END__