line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package App::sh2p::Parser; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
7
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
43
|
|
4
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
33
|
|
5
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
526
|
use App::sh2p::Compound; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
38
|
|
7
|
1
|
|
|
1
|
|
9
|
use App::sh2p::Trap; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
18
|
|
8
|
1
|
|
|
1
|
|
5
|
use App::sh2p::Utils; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
4231
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
sub convert(\@\@); |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our $VERSION = '0.06'; |
13
|
|
|
|
|
|
|
our $DEBUG = 0; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
########################################################### |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
my %icompound = |
18
|
|
|
|
|
|
|
( 'case' => \&App::sh2p::Compound::Handle_case, |
19
|
|
|
|
|
|
|
'do' => \&App::sh2p::Compound::Handle_do, |
20
|
|
|
|
|
|
|
'done' => \&App::sh2p::Compound::Handle_done, |
21
|
|
|
|
|
|
|
'elif' => \&App::sh2p::Compound::Handle_elif, |
22
|
|
|
|
|
|
|
'else' => \&App::sh2p::Compound::Handle_else, |
23
|
|
|
|
|
|
|
'esac' => \&App::sh2p::Compound::Handle_esac, |
24
|
|
|
|
|
|
|
'fi' => \&App::sh2p::Compound::Handle_fi, |
25
|
|
|
|
|
|
|
'for' => \&App::sh2p::Compound::Handle_for, |
26
|
|
|
|
|
|
|
'function' => \&App::sh2p::Compound::Handle_function, |
27
|
|
|
|
|
|
|
'if' => \&App::sh2p::Compound::Handle_if, |
28
|
|
|
|
|
|
|
'in' => \&App::sh2p::Compound::Ignore, |
29
|
|
|
|
|
|
|
'select' => \&App::sh2p::Compound::Handle_for, |
30
|
|
|
|
|
|
|
'then' => \&App::sh2p::Compound::Handle_then, |
31
|
|
|
|
|
|
|
'time' => 5, |
32
|
|
|
|
|
|
|
'until' => \&App::sh2p::Compound::Handle_until, |
33
|
|
|
|
|
|
|
'while' => \&App::sh2p::Compound::Handle_while, |
34
|
|
|
|
|
|
|
'!' => \&App::sh2p::Compound::Handle_not, |
35
|
|
|
|
|
|
|
'{' => \&App::sh2p::Compound::open_brace, |
36
|
|
|
|
|
|
|
'}' => \&App::sh2p::Compound::close_brace, |
37
|
|
|
|
|
|
|
); |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
my %ioperator = |
40
|
|
|
|
|
|
|
( '&&' => \&App::sh2p::Operators::shortcut, |
41
|
|
|
|
|
|
|
'||' => \&App::sh2p::Operators::shortcut, |
42
|
|
|
|
|
|
|
'|&' => 3, |
43
|
|
|
|
|
|
|
#'&' => 4, January 2009 |
44
|
|
|
|
|
|
|
); |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
my %idelimiter = |
47
|
|
|
|
|
|
|
( '\'' => \&App::sh2p::Handlers::Handle_delimiter, |
48
|
|
|
|
|
|
|
'"' => \&App::sh2p::Handlers::Handle_delimiter, |
49
|
|
|
|
|
|
|
'`' => \&App::sh2p::Handlers::Handle_delimiter, |
50
|
|
|
|
|
|
|
'$(' => \&App::sh2p::Handlers::Handle_2char_qx, |
51
|
|
|
|
|
|
|
'${' => \&App::sh2p::Handlers::Handle_expansion, # Problems, do specific testing? |
52
|
|
|
|
|
|
|
'(' => \&App::sh2p::Handlers::Handle_delimiter, |
53
|
|
|
|
|
|
|
')' => \&App::sh2p::Handlers::Handle_delimiter, |
54
|
|
|
|
|
|
|
'[' => \&App::sh2p::Compound::sh_test, |
55
|
|
|
|
|
|
|
'#' => \&App::sh2p::Handlers::Handle_delimiter, # 'COMMENT', |
56
|
|
|
|
|
|
|
';' => \&App::sh2p::Handlers::Handle_delimiter, |
57
|
|
|
|
|
|
|
'|' => \&App::sh2p::Handlers::Handle_pipe, |
58
|
|
|
|
|
|
|
'[[' => \&App::sh2p::Compound::ksh_test, |
59
|
|
|
|
|
|
|
'((' => \&App::sh2p::Compound::arith, |
60
|
|
|
|
|
|
|
'$((' => \&App::sh2p::Compound::arith, |
61
|
|
|
|
|
|
|
); |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
my %ibuiltins = |
64
|
|
|
|
|
|
|
( ':' => \&App::sh2p::Builtins::do_colon, |
65
|
|
|
|
|
|
|
'.' => \&App::sh2p::Builtins::do_source, |
66
|
|
|
|
|
|
|
'alias' => 2, |
67
|
|
|
|
|
|
|
'autoload' => \&App::sh2p::Builtins::do_autoload, |
68
|
|
|
|
|
|
|
'bg' => 3, |
69
|
|
|
|
|
|
|
'bind' => 4, |
70
|
|
|
|
|
|
|
'break' => \&App::sh2p::Builtins::do_break, |
71
|
|
|
|
|
|
|
'builtin' => 6, |
72
|
|
|
|
|
|
|
'cd' => \&App::sh2p::Builtins::do_cd, |
73
|
|
|
|
|
|
|
'command' => 8, |
74
|
|
|
|
|
|
|
'continue' => \&App::sh2p::Builtins::do_continue, |
75
|
|
|
|
|
|
|
'echo' => \&App::sh2p::Builtins::do_print, |
76
|
|
|
|
|
|
|
'eval' => 2, |
77
|
|
|
|
|
|
|
'exec' => \&App::sh2p::Builtins::do_exec, |
78
|
|
|
|
|
|
|
'exit' => \&App::sh2p::Builtins::do_exit, |
79
|
|
|
|
|
|
|
'export' => \&App::sh2p::Builtins::do_export, |
80
|
|
|
|
|
|
|
'false' => \&App::sh2p::Builtins::do_false, |
81
|
|
|
|
|
|
|
'fc' => 7, |
82
|
|
|
|
|
|
|
'fg' => 8, |
83
|
|
|
|
|
|
|
'functions'=> \&App::sh2p::Builtins::do_functions, |
84
|
|
|
|
|
|
|
'getopts' => 9, |
85
|
|
|
|
|
|
|
'integer' => \&App::sh2p::Builtins::do_integer, |
86
|
|
|
|
|
|
|
'hash' => 10, |
87
|
|
|
|
|
|
|
'jobs' => 11, |
88
|
|
|
|
|
|
|
'kill' => \&App::sh2p::Builtins::do_kill, |
89
|
|
|
|
|
|
|
'let' => \&App::sh2p::Builtins::do_let, |
90
|
|
|
|
|
|
|
'print' => \&App::sh2p::Builtins::do_print, |
91
|
|
|
|
|
|
|
'read' => \&App::sh2p::Builtins::do_read, |
92
|
|
|
|
|
|
|
'readonly' => 7, |
93
|
|
|
|
|
|
|
'return' => \&App::sh2p::Builtins::do_return, |
94
|
|
|
|
|
|
|
'set' => \&App::sh2p::Builtins::do_set, |
95
|
|
|
|
|
|
|
'shift' => \&App::sh2p::Builtins::do_shift, |
96
|
|
|
|
|
|
|
'test' => \&App::sh2p::Compound::sh_test, |
97
|
|
|
|
|
|
|
'[' => \&App::sh2p::Compound::sh_test, |
98
|
|
|
|
|
|
|
'time' => 12, |
99
|
|
|
|
|
|
|
'times' => 13, |
100
|
|
|
|
|
|
|
'tr' => \&App::sh2p::Builtins::do_tr, |
101
|
|
|
|
|
|
|
'trap' => \&App::sh2p::Trap::do_trap, |
102
|
|
|
|
|
|
|
'true' => \&App::sh2p::Builtins::do_true, |
103
|
|
|
|
|
|
|
'typeset' => \&App::sh2p::Builtins::do_typeset, |
104
|
|
|
|
|
|
|
'ulimit' => 17, |
105
|
|
|
|
|
|
|
'umask' => \&App::sh2p::Builtins::do_chmod, |
106
|
|
|
|
|
|
|
'unalias' => 19, |
107
|
|
|
|
|
|
|
'unset' => \&App::sh2p::Builtins::do_unset, |
108
|
|
|
|
|
|
|
'wait' => 21, |
109
|
|
|
|
|
|
|
'whence' => 22, |
110
|
|
|
|
|
|
|
# Bash specifics |
111
|
|
|
|
|
|
|
'declare' => \&App::sh2p::Builtins::do_typeset, |
112
|
|
|
|
|
|
|
'local' => \&App::sh2p::Builtins::do_typeset, |
113
|
|
|
|
|
|
|
'shopt' => \&App::sh2p::Builtins::do_shopt, |
114
|
|
|
|
|
|
|
'source' => \&App::sh2p::Builtins::do_source, |
115
|
|
|
|
|
|
|
); |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
my %perl_builtins = |
118
|
|
|
|
|
|
|
( 'awk' => [\&App::sh2p::Builtins::advise,'Perl code, often split'], |
119
|
|
|
|
|
|
|
'basename'=> [\&App::sh2p::Builtins::advise,'File::Basename::basename'], |
120
|
|
|
|
|
|
|
'cat' => [\&App::sh2p::Builtins::advise,'ExtUtils::Command::cat'], |
121
|
|
|
|
|
|
|
'chmod' => [\&App::sh2p::Builtins::do_chmod], |
122
|
|
|
|
|
|
|
'chown' => [\&App::sh2p::Builtins::do_chown], |
123
|
|
|
|
|
|
|
'chgrp' => [\&App::sh2p::Builtins::do_chown], |
124
|
|
|
|
|
|
|
'cp' => [\&App::sh2p::Builtins::advise,'File::Copy'], |
125
|
|
|
|
|
|
|
'cut' => [\&App::sh2p::Builtins::advise,'split'], |
126
|
|
|
|
|
|
|
'date' => [\&App::sh2p::Builtins::advise,'localtime or POSIX::strftime'], |
127
|
|
|
|
|
|
|
'df' => [\&App::sh2p::Builtins::advise,'Filesys::Df'], |
128
|
|
|
|
|
|
|
'diff' => [\&App::sh2p::Builtins::advise,'File::Compare'], |
129
|
|
|
|
|
|
|
'dirname' => [\&App::sh2p::Builtins::advise,'File::Basename::dirname'], |
130
|
|
|
|
|
|
|
'egrep' => [\&App::sh2p::Builtins::advise,'while(<>){print if /re/} or perl grep'], |
131
|
|
|
|
|
|
|
'eval' => [\&App::sh2p::Builtins::one4one,'eval'], |
132
|
|
|
|
|
|
|
'exec' => [\&App::sh2p::Builtins::advise,'exec or pipe (co-processes) or open (file descriptors)'], |
133
|
|
|
|
|
|
|
'expr' => [\&App::sh2p::Builtins::do_expr], |
134
|
|
|
|
|
|
|
'find' => [\&App::sh2p::Builtins::advise,'File::Find'], |
135
|
|
|
|
|
|
|
'file' => [\&App::sh2p::Builtins::advise,'File::Type'], |
136
|
|
|
|
|
|
|
'ftp' => [\&App::sh2p::Builtins::advise,'Net::Ftp'], |
137
|
|
|
|
|
|
|
'grep' => [\&App::sh2p::Builtins::advise,'while(<>){print if /re/} or perl grep'], |
138
|
|
|
|
|
|
|
'ln' => [\&App::sh2p::Builtins::one4one,'link'], |
139
|
|
|
|
|
|
|
'ln -s' => [\&App::sh2p::Builtins::one4one,'symlink'], |
140
|
|
|
|
|
|
|
'ls' => [\&App::sh2p::Builtins::advise,'glob or opendir/readdir/closedir or stat/lstat'], |
141
|
|
|
|
|
|
|
'mkdir' => [\&App::sh2p::Builtins::one4one,'mkdir'], |
142
|
|
|
|
|
|
|
'mkpath' => [\&App::sh2p::Builtins::advise,'ExtUtils::Command::mkpath'], |
143
|
|
|
|
|
|
|
'mv' => [\&App::sh2p::Builtins::one4one,'rename'], |
144
|
|
|
|
|
|
|
'od' => [\&App::sh2p::Builtins::advise,'ord or printf'], |
145
|
|
|
|
|
|
|
'printf' => [\&App::sh2p::Builtins::one4one,'printf'], |
146
|
|
|
|
|
|
|
'pwd' => [\&App::sh2p::Builtins::advise,'Cwd::getcwd'], |
147
|
|
|
|
|
|
|
'rand' => [\&App::sh2p::Builtins::one4one,'rand'], |
148
|
|
|
|
|
|
|
'rm' => [\&App::sh2p::Builtins::one4one,'unlink'], |
149
|
|
|
|
|
|
|
'rm -f' => [\&App::sh2p::Builtins::advise,'ExtUtils::Command::rm_rf'], |
150
|
|
|
|
|
|
|
'sed' => [\&App::sh2p::Builtins::advise,'s/// (usually)'], |
151
|
|
|
|
|
|
|
'select' => [\&App::sh2p::Builtins::advise,'Shell::POSIX::select'], |
152
|
|
|
|
|
|
|
'sleep' => [\&App::sh2p::Builtins::one4one,'sleep'], |
153
|
|
|
|
|
|
|
'sort' => [\&App::sh2p::Builtins::one4one,'sort'], |
154
|
|
|
|
|
|
|
'tail' => [\&App::sh2p::Builtins::advise,'File::Tail'], |
155
|
|
|
|
|
|
|
'telnet' => [\&App::sh2p::Builtins::advise,'Net::Telnet'], |
156
|
|
|
|
|
|
|
'touch' => [\&App::sh2p::Builtins::do_touch], |
157
|
|
|
|
|
|
|
); |
158
|
|
|
|
|
|
|
########################################################### |
159
|
|
|
|
|
|
|
# $ibuiltins added 0.04 |
160
|
|
|
|
|
|
|
sub get_perl_builtin { |
161
|
0
|
|
|
0
|
0
|
|
my $func = shift; |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
|
164
|
0
|
0
|
|
|
|
|
if (defined $perl_builtins{$func}) { |
|
|
0
|
|
|
|
|
|
165
|
0
|
|
|
|
|
|
return @{$perl_builtins{$func}}; |
|
0
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
elsif (defined $ibuiltins{$func}) { |
168
|
0
|
|
|
|
|
|
return ($ibuiltins{$func}, $func); |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
else { |
171
|
0
|
|
|
|
|
|
return (); |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
########################################################### |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
sub tokenise { |
178
|
0
|
|
|
0
|
0
|
|
my @tokens; |
179
|
0
|
|
|
|
|
|
my $index = 0; |
180
|
0
|
|
|
|
|
|
my $q = 0; |
181
|
0
|
|
|
|
|
|
my $qq = 0; |
182
|
0
|
|
|
|
|
|
my $qx = 0; |
183
|
0
|
|
|
|
|
|
my $qp = 0; # () |
184
|
0
|
|
|
|
|
|
my $qs = 0; # [] |
185
|
0
|
|
|
|
|
|
my $br = 0; # {} |
186
|
0
|
|
|
|
|
|
my $esc = 0; # \ |
187
|
0
|
|
|
|
|
|
my $comment = 0; |
188
|
0
|
|
|
|
|
|
my $heredoc = 0; |
189
|
0
|
|
|
|
|
|
my $variable = 0; |
190
|
|
|
|
|
|
|
|
191
|
0
|
|
|
|
|
|
my ($line) = @_; |
192
|
|
|
|
|
|
|
|
193
|
0
|
|
|
|
|
|
for my $char (split '', $line) { |
194
|
|
|
|
|
|
|
|
195
|
0
|
0
|
|
|
|
|
if ($comment) { |
196
|
0
|
|
|
|
|
|
$tokens[$index] .= $char; |
197
|
|
|
|
|
|
|
next |
198
|
0
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
|
200
|
0
|
0
|
|
|
|
|
if ($heredoc) { |
201
|
|
|
|
|
|
|
#$g_herelabel .= $char; |
202
|
0
|
|
|
|
|
|
$tokens[$index] .= $char; |
203
|
0
|
|
|
|
|
|
next; |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
0
|
0
|
|
|
|
|
if ($esc) { |
207
|
0
|
|
|
|
|
|
$tokens[$index] .= $char; |
208
|
0
|
|
|
|
|
|
$esc = 0; |
209
|
0
|
|
|
|
|
|
next; |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
0
|
0
|
|
|
|
|
if ($variable) { |
213
|
0
|
0
|
|
|
|
|
if ($char =~ /[^A-Z0-9#@*\$\-!\{\}\[\]]/i) { |
214
|
0
|
|
|
|
|
|
$variable = 0; |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
|
218
|
0
|
0
|
0
|
|
|
|
if ($char eq '$') { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
219
|
0
|
|
|
|
|
|
$variable = 1; |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
elsif ($char eq '\'') { |
222
|
0
|
0
|
|
|
|
|
$q = $q?0:1; |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
elsif ($char eq '`') { |
225
|
0
|
0
|
|
|
|
|
$qx = $qx?0:1; |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
elsif ($char eq '"') { |
228
|
0
|
0
|
|
|
|
|
$qq = $qq?0:1; |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
elsif ($char eq '[') { # Take into account nested [] |
231
|
0
|
|
|
|
|
|
$qs++; |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
elsif ($qs && $char eq ']') { |
234
|
0
|
|
|
|
|
|
$qs-- |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
elsif ($char eq '{') { # Take into account nested {} |
237
|
0
|
|
|
|
|
|
$br++; |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
# Tried, but had unexpected side-effects |
240
|
|
|
|
|
|
|
# elsif ($br && $char eq '}' && !$q && !$qq && !$qx && !$qp && !$qs) { |
241
|
|
|
|
|
|
|
# $tokens[$index] .= $char; |
242
|
|
|
|
|
|
|
# $index++; |
243
|
|
|
|
|
|
|
# $br--; |
244
|
|
|
|
|
|
|
# next; |
245
|
|
|
|
|
|
|
# } |
246
|
|
|
|
|
|
|
# Modification of above |
247
|
|
|
|
|
|
|
elsif ($br && $char eq '}') { |
248
|
0
|
|
|
|
|
|
$br--; |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
elsif ($char eq '\\') { |
251
|
0
|
|
|
|
|
|
$tokens[$index] .= $char; |
252
|
0
|
|
|
|
|
|
$esc = 1; |
253
|
0
|
|
|
|
|
|
next; |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
# Take into account nested () |
257
|
0
|
0
|
0
|
|
|
|
if ($char eq '(') { |
|
|
0
|
|
|
|
|
|
258
|
0
|
|
|
|
|
|
$qp++ |
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
elsif ($qp && $char eq ')') { |
261
|
0
|
|
|
|
|
|
$qp-- |
262
|
|
|
|
|
|
|
} |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
# Not inside a delimiter |
265
|
0
|
0
|
0
|
|
|
|
if (!$q && !$qq && !$qx && !$qp && !$qs && !$br) { |
266
|
0
|
0
|
0
|
|
|
|
if ($char eq '#' && !$variable) { |
267
|
0
|
|
|
|
|
|
$comment = 1 |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
|
270
|
0
|
0
|
0
|
|
|
|
if ($char =~ /\s/ && !$comment) { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
271
|
0
|
0
|
|
|
|
|
$index++ if defined $tokens[$index]; |
272
|
|
|
|
|
|
|
} |
273
|
|
|
|
|
|
|
elsif ($char eq ';' && !$comment) { |
274
|
0
|
0
|
|
|
|
|
$index++ if defined $tokens[$index]; |
275
|
0
|
|
|
|
|
|
$tokens[$index] .= $char; |
276
|
0
|
|
|
|
|
|
$index++; |
277
|
|
|
|
|
|
|
} |
278
|
|
|
|
|
|
|
elsif ($char eq '<' && !$comment) { |
279
|
|
|
|
|
|
|
# Here doc? |
280
|
0
|
0
|
|
|
|
|
if (defined $tokens[$index]) { |
281
|
0
|
0
|
|
|
|
|
if ($tokens[$index] ne '<') { |
282
|
0
|
0
|
|
|
|
|
$index++ if defined $tokens[$index]; |
283
|
0
|
|
|
|
|
|
$tokens[$index] .= $char; |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
else { |
286
|
0
|
|
|
|
|
|
$heredoc = 1; |
287
|
0
|
|
|
|
|
|
$tokens[$index] .= $char; |
288
|
0
|
|
|
|
|
|
$index++; |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
else { |
292
|
0
|
|
|
|
|
|
$tokens[$index] .= $char; |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
} |
295
|
|
|
|
|
|
|
elsif ($char eq '>' && !$comment) { |
296
|
0
|
0
|
0
|
|
|
|
if (defined $tokens[$index] && $tokens[$index] ne '>') { # Append? |
297
|
0
|
0
|
|
|
|
|
$index++ if defined $tokens[$index]; |
298
|
0
|
|
|
|
|
|
$tokens[$index] .= $char; |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
else { |
301
|
0
|
|
|
|
|
|
$tokens[$index] .= $char; |
302
|
0
|
|
|
|
|
|
$index++; |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
else { |
306
|
0
|
|
|
|
|
|
$tokens[$index] .= $char; |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
else { |
310
|
0
|
|
|
|
|
|
$tokens[$index] .= $char; |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
|
314
|
0
|
0
|
|
|
|
|
$tokens[$index] .= "\n" if $comment; |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
return @tokens |
317
|
0
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
########################################################### |
320
|
|
|
|
|
|
|
# First argument is used to identify external program calls |
321
|
|
|
|
|
|
|
# nested = 0 - call is not nested, first argument may be an external program |
322
|
|
|
|
|
|
|
# nested = 1 - call is not nested, first argument is not an external program |
323
|
|
|
|
|
|
|
# nested = 2 - as 1, plus call is as a list |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
sub identify { |
326
|
0
|
|
|
0
|
0
|
|
my ($nested, @in) = @_; |
327
|
0
|
|
|
|
|
|
my @out; |
328
|
0
|
|
|
|
|
|
my $first = $in[0]; |
329
|
|
|
|
|
|
|
|
330
|
0
|
0
|
|
|
|
|
if (!@in) { |
331
|
0
|
|
|
|
|
|
print STDERR "+++ Internal error: Empty input array to identify\n"; |
332
|
0
|
|
|
|
|
|
my @caller = caller(); |
333
|
0
|
|
|
|
|
|
die "@caller\n"; |
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
#print STDERR "identify first <$first>\n"; |
337
|
|
|
|
|
|
|
# Special processing for the first token |
338
|
|
|
|
|
|
|
|
339
|
0
|
0
|
0
|
|
|
|
if ($first =~ /^\w+\+?=/) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
340
|
0
|
|
|
|
|
|
$out[0] = [('ASSIGNMENT', |
341
|
|
|
|
|
|
|
\&App::sh2p::Handlers::Handle_assignment)]; |
342
|
|
|
|
|
|
|
shift @in |
343
|
0
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
elsif ($first =~ /^\w+\[.*\]=/) { |
345
|
0
|
|
|
|
|
|
$out[0] = [('ARRAY_ASSIGNMENT', |
346
|
|
|
|
|
|
|
\&App::sh2p::Handlers::Handle_array_assignment)]; |
347
|
|
|
|
|
|
|
shift @in |
348
|
0
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
elsif (is_break($first)) { |
350
|
0
|
|
|
|
|
|
$out[0] = [('BREAK', |
351
|
|
|
|
|
|
|
\&App::sh2p::Handlers::Handle_break)]; |
352
|
|
|
|
|
|
|
shift @in |
353
|
0
|
|
|
|
|
|
} |
354
|
|
|
|
|
|
|
elsif (!$nested && $first =~ /^([\"]?)\$[A-Z0-9#@*{}\[\]]+\1/i) { # Optional " added January 2009 |
355
|
|
|
|
|
|
|
# Not a variable, but a call (variable contains call name) |
356
|
0
|
|
|
|
|
|
$out[0] = [('EXTERNAL', |
357
|
|
|
|
|
|
|
\&App::sh2p::Handlers::Handle_external)]; |
358
|
0
|
|
|
|
|
|
shift @in; |
359
|
|
|
|
|
|
|
} |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
# Now process the rest |
362
|
|
|
|
|
|
|
|
363
|
0
|
|
|
|
|
|
for my $token (@in) { |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
#print STDERR "Identify token: <$token> <$nested>\n"; |
366
|
|
|
|
|
|
|
|
367
|
0
|
|
|
|
|
|
my $type = 'UNKNOWN'; |
368
|
0
|
|
|
|
|
|
my $sub = \&App::sh2p::Handlers::Handle_unknown; |
369
|
|
|
|
|
|
|
|
370
|
0
|
0
|
0
|
|
|
|
if (ref($token) eq 'CODE') { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
371
|
0
|
|
|
|
|
|
$sub = $token; |
372
|
0
|
|
|
|
|
|
$type = 'INTERNAL'; |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
elsif ($token =~ /^\w+=/) { |
375
|
0
|
|
|
|
|
|
$sub = \&App::sh2p::Handlers::Handle_assignment; |
376
|
0
|
|
|
|
|
|
$type = 'ASSIGNMENT'; |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
elsif ($token =~ /^\w+\[.*\]=/) { |
379
|
0
|
|
|
|
|
|
$sub = \&App::sh2p::Handlers::Handle_array_assignment; |
380
|
0
|
|
|
|
|
|
$type = 'ARRAY_ASSIGNMENT'; |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
elsif (exists $icompound{$token}) { |
383
|
0
|
|
|
|
|
|
$sub = $icompound{$token}; |
384
|
0
|
|
|
|
|
|
$type = 'COMPOUND'; |
385
|
|
|
|
|
|
|
} |
386
|
|
|
|
|
|
|
elsif (exists $ioperator{$token} && $nested < 2) { |
387
|
0
|
|
|
|
|
|
$sub = $ioperator{$token}; |
388
|
0
|
|
|
|
|
|
$type = 'OPERATOR'; |
389
|
|
|
|
|
|
|
# Shortcut, next is another command |
390
|
|
|
|
|
|
|
} |
391
|
|
|
|
|
|
|
elsif (exists $ibuiltins{$token} && $nested < 2) { |
392
|
0
|
|
|
|
|
|
$sub = $ibuiltins{$token}; |
393
|
0
|
|
|
|
|
|
$type = 'BUILTIN' |
394
|
|
|
|
|
|
|
} |
395
|
|
|
|
|
|
|
elsif (exists $perl_builtins{$token} && $nested < 2) { |
396
|
0
|
|
|
|
|
|
$sub = $perl_builtins{$token}[0]; |
397
|
0
|
|
|
|
|
|
$type = 'PERL_BUILTIN' |
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
else { |
400
|
0
|
|
|
|
|
|
my $first_char = ''; |
401
|
0
|
|
|
|
|
|
my $two_chars = ''; |
402
|
0
|
|
|
|
|
|
my $three_chars = ''; |
403
|
|
|
|
|
|
|
|
404
|
0
|
|
|
|
|
|
$first_char = substr($token, 0, 1); |
405
|
0
|
0
|
|
|
|
|
$two_chars = substr($token, 0, 2) if length($token) > 1; |
406
|
0
|
0
|
|
|
|
|
$three_chars = substr($token, 0, 3) if length($token) > 2; |
407
|
|
|
|
|
|
|
|
408
|
0
|
0
|
0
|
|
|
|
if (exists $idelimiter{$three_chars}) { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
409
|
0
|
|
|
|
|
|
$type = 'THREE_CHAR_DELIMITER'; |
410
|
0
|
|
|
|
|
|
$sub = $idelimiter{$three_chars}; |
411
|
|
|
|
|
|
|
} |
412
|
|
|
|
|
|
|
elsif (exists $idelimiter{$two_chars}) { |
413
|
|
|
|
|
|
|
# Special hack for variables |
414
|
0
|
0
|
0
|
|
|
|
if ( $two_chars eq '${' && (!@out || ($out[-1]->[0] eq 'BREAK')) && |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
415
|
|
|
|
|
|
|
!$nested && !is_break($first_char)) { # Must be first token |
416
|
0
|
|
|
|
|
|
$type = 'EXTERNAL'; |
417
|
0
|
|
|
|
|
|
$sub = \&App::sh2p::Handlers::Handle_external; |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
else { |
420
|
0
|
|
|
|
|
|
$type = 'TWO_CHAR_DELIMITER'; |
421
|
0
|
|
|
|
|
|
$sub = $idelimiter{$two_chars}; |
422
|
|
|
|
|
|
|
} |
423
|
|
|
|
|
|
|
} |
424
|
|
|
|
|
|
|
elsif (exists $idelimiter{$first_char}) { # January 2009 |
425
|
0
|
0
|
0
|
|
|
|
if ( $first_char eq '"' && (!@out || ($out[-1]->[0] eq 'BREAK')) && |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
426
|
|
|
|
|
|
|
!$nested && !is_break($first_char)) { # Must be first token |
427
|
0
|
|
|
|
|
|
$type = 'EXTERNAL'; |
428
|
0
|
|
|
|
|
|
$sub = \&App::sh2p::Handlers::Handle_external; |
429
|
|
|
|
|
|
|
} |
430
|
|
|
|
|
|
|
else { |
431
|
0
|
|
|
|
|
|
$type = 'SINGLE_DELIMITER'; |
432
|
0
|
|
|
|
|
|
$sub = $idelimiter{$first_char}; |
433
|
|
|
|
|
|
|
} |
434
|
|
|
|
|
|
|
} |
435
|
|
|
|
|
|
|
elsif ($first_char eq '~') { |
436
|
0
|
|
|
|
|
|
$type = 'GLOB'; |
437
|
0
|
|
|
|
|
|
$sub = \&App::sh2p::Handlers::Handle_Glob; |
438
|
|
|
|
|
|
|
} |
439
|
|
|
|
|
|
|
elsif ( (!@out || ($out[-1]->[0] eq 'BREAK')) && |
440
|
|
|
|
|
|
|
!$nested && !is_break($first_char)) { # Must be first token |
441
|
0
|
|
|
|
|
|
$type = 'EXTERNAL'; |
442
|
0
|
|
|
|
|
|
$sub = \&App::sh2p::Handlers::Handle_external; |
443
|
|
|
|
|
|
|
} |
444
|
|
|
|
|
|
|
# January 2009 This test must come after the 'EXTERNAL' test, |
445
|
|
|
|
|
|
|
# otherwise a bare variable is not seen as an external call |
446
|
|
|
|
|
|
|
elsif ($first_char eq '$' && $token =~ /^\$[A-Z0-9\#\@\*\?\{\}\[\]]+$/i) { |
447
|
0
|
|
|
|
|
|
$type = 'VARIABLE'; |
448
|
0
|
|
|
|
|
|
$sub = \&App::sh2p::Handlers::Handle_variable |
449
|
|
|
|
|
|
|
} |
450
|
|
|
|
|
|
|
elsif (is_break($token)) { # 0.06 |
451
|
0
|
|
|
|
|
|
$type = 'BREAK'; |
452
|
0
|
|
|
|
|
|
$sub = \&App::sh2p::Handlers::Handle_break; |
453
|
|
|
|
|
|
|
} |
454
|
|
|
|
|
|
|
elsif (exists $ioperator{$two_chars} && $nested) { |
455
|
0
|
|
|
|
|
|
$sub = $ioperator{$two_chars}; |
456
|
0
|
|
|
|
|
|
$type = 'OPERATOR' |
457
|
|
|
|
|
|
|
} |
458
|
|
|
|
|
|
|
elsif (exists $ioperator{$first_char} && $nested) { |
459
|
0
|
|
|
|
|
|
$sub = $ioperator{$first_char}; |
460
|
0
|
|
|
|
|
|
$type = 'OPERATOR' |
461
|
|
|
|
|
|
|
} |
462
|
|
|
|
|
|
|
elsif ($token =~ /\[|\*|\?/ && !query_in_quotes()) { |
463
|
|
|
|
|
|
|
# No globbing inside quotes |
464
|
0
|
|
|
|
|
|
$sub = \&App::sh2p::Handlers::Handle_Glob; |
465
|
0
|
|
|
|
|
|
$type = 'GLOB'; |
466
|
|
|
|
|
|
|
} |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
} |
469
|
0
|
|
|
|
|
|
push @out, [($type, $sub)]; |
470
|
|
|
|
|
|
|
} |
471
|
|
|
|
|
|
|
|
472
|
0
|
|
|
|
|
|
return @out; |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
} |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
########################################################### |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
sub convert (\@\@) { |
479
|
0
|
|
|
0
|
0
|
|
my ($rtok, $rtype) = @_; |
480
|
|
|
|
|
|
|
|
481
|
0
|
0
|
|
|
|
|
if ( $DEBUG ) { |
482
|
0
|
|
|
|
|
|
my @caller = caller(); |
483
|
0
|
|
|
|
|
|
print STDERR "\nconvert called from @caller\n"; |
484
|
0
|
|
|
|
|
|
local $" = '|'; |
485
|
0
|
|
|
|
|
|
print STDERR "convert:@$rtok\nconvert: "; |
486
|
0
|
|
|
|
|
|
print STDERR (map {"$_->[0] "} @$rtype),"\n"; |
|
0
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
} |
488
|
|
|
|
|
|
|
|
489
|
0
|
0
|
|
|
|
|
if (@$rtok != @$rtype ) { |
490
|
0
|
|
|
|
|
|
print STDERR "+++ Internal Error rtok: <@$rtok>, rtype: <@$rtype>\n"; |
491
|
0
|
|
|
|
|
|
die "Parser::convert: token and type arrays uneven\n" |
492
|
|
|
|
|
|
|
} |
493
|
|
|
|
|
|
|
|
494
|
0
|
0
|
|
|
|
|
pop @$rtok if (is_break($rtok->[-1])); |
495
|
0
|
|
|
|
|
|
my $tokens_processed = 0; |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
#print_types_tokens ($rtype, $rtok); |
498
|
|
|
|
|
|
|
|
499
|
0
|
|
|
|
|
|
while (@$rtok) { |
500
|
|
|
|
|
|
|
|
501
|
0
|
|
|
|
|
|
my $type = $rtype->[0][0]; |
502
|
0
|
|
|
|
|
|
my $sub = $rtype->[0][1]; |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
#print STDERR "tokens: <@$rtok> type: $type, sub: $sub\n"; |
505
|
0
|
0
|
|
|
|
|
if (ref($sub) eq 'CODE' ) { |
506
|
|
|
|
|
|
|
|
507
|
0
|
0
|
|
|
|
|
if ($type eq 'COMPOUND') { |
508
|
0
|
|
|
|
|
|
test_for_redirection($rtok, $rtype); |
509
|
|
|
|
|
|
|
} |
510
|
|
|
|
|
|
|
|
511
|
0
|
|
|
|
|
|
$tokens_processed = &$sub(@$rtok); |
512
|
|
|
|
|
|
|
|
513
|
0
|
0
|
|
|
|
|
if ($tokens_processed > @$rtok) { |
514
|
0
|
|
|
|
|
|
error_out "Internal error: Token count wrong! Was: $tokens_processed, max: ".scalar(@$rtok); |
515
|
0
|
|
|
|
|
|
error_out "Type: $rtype->[0][0], tokens: @$rtok"; |
516
|
|
|
|
|
|
|
} |
517
|
|
|
|
|
|
|
} |
518
|
|
|
|
|
|
|
else { |
519
|
0
|
|
|
|
|
|
error_out ("No conversion routine for $type $rtok->[0]"); |
520
|
0
|
|
|
|
|
|
out "$rtok->[0]\n"; |
521
|
0
|
|
|
|
|
|
$tokens_processed = 1; |
522
|
|
|
|
|
|
|
} |
523
|
|
|
|
|
|
|
|
524
|
0
|
0
|
|
|
|
|
if ($tokens_processed) { |
525
|
|
|
|
|
|
|
# Remove tokens already processed |
526
|
0
|
|
|
|
|
|
splice (@$rtok, 0, $tokens_processed); |
527
|
0
|
|
|
|
|
|
splice (@$rtype, 0, $tokens_processed); |
528
|
|
|
|
|
|
|
} |
529
|
|
|
|
|
|
|
} |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
} |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
######################################################## |
534
|
|
|
|
|
|
|
# Called by convert |
535
|
|
|
|
|
|
|
sub test_for_redirection { |
536
|
|
|
|
|
|
|
|
537
|
0
|
|
|
0
|
0
|
|
my ($rtok, $rtype) = @_; |
538
|
|
|
|
|
|
|
|
539
|
0
|
|
|
|
|
|
my $next_type = $rtype->[1][0]; |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
|
542
|
0
|
0
|
0
|
|
|
|
return 0 if !defined $next_type || $next_type ne 'BUILTIN'; |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
#print_types_tokens($rtype, $rtok); |
545
|
|
|
|
|
|
|
|
546
|
0
|
|
|
|
|
|
for (my $i = 2; $i < @$rtok; $i++) { |
547
|
0
|
0
|
0
|
|
|
|
if ($rtok->[$i] eq '<' || $rtok->[$i] eq '>' || $rtok->[$i] eq '>>') { |
|
|
|
0
|
|
|
|
|
548
|
|
|
|
|
|
|
|
549
|
0
|
0
|
|
|
|
|
if ( !defined $rtok->[$i+1] ) { |
550
|
0
|
|
|
|
|
|
die "*** Malformed redirection (no file)\n"; |
551
|
|
|
|
|
|
|
} |
552
|
|
|
|
|
|
|
|
553
|
0
|
|
|
|
|
|
my $redirection_file = $rtok->[$i+1]; |
554
|
0
|
|
|
|
|
|
$redirection_file =~ s/^\s+//; |
555
|
0
|
|
|
|
|
|
App::sh2p::Handlers::Handle_open_redirection ($rtok->[$i], |
556
|
|
|
|
|
|
|
$redirection_file); |
557
|
|
|
|
|
|
|
# Remove tokens processed |
558
|
0
|
|
|
|
|
|
splice (@$rtok, $i, 2); |
559
|
0
|
|
|
|
|
|
splice (@$rtype, $i, 2); |
560
|
|
|
|
|
|
|
|
561
|
0
|
|
|
|
|
|
return 2; |
562
|
|
|
|
|
|
|
} |
563
|
|
|
|
|
|
|
} |
564
|
|
|
|
|
|
|
} |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
######################################################## |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
sub join_parse_tokens { |
569
|
|
|
|
|
|
|
|
570
|
0
|
|
|
0
|
0
|
|
my ($sep, @args) = @_; |
571
|
0
|
|
|
|
|
|
my $ntok = 0; |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
# C style for loop because I need to check the position |
574
|
0
|
|
|
|
|
|
for (my $i = 0; $i < @args; $i++) { |
575
|
|
|
|
|
|
|
|
576
|
0
|
|
|
|
|
|
my @tokens = ($args[$i]); |
577
|
0
|
|
|
|
|
|
my @types = identify (2, @tokens); |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
#print_types_tokens(\@types, \@tokens); |
580
|
|
|
|
|
|
|
|
581
|
0
|
|
|
|
|
|
convert (@tokens, @types); |
582
|
0
|
|
|
|
|
|
$ntok++; |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
# Look ahead to see if we are at end |
585
|
0
|
0
|
|
|
|
|
if ($i < $#args) { |
586
|
0
|
0
|
|
|
|
|
last if substr($args[$i+1],0,1) eq '#'; |
587
|
0
|
0
|
|
|
|
|
last if is_break($args[$i+1]); |
588
|
0
|
0
|
|
|
|
|
last if $args[$i+1] eq ';'; # January 2009 |
589
|
0
|
|
|
|
|
|
out $sep; |
590
|
|
|
|
|
|
|
} |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
} |
593
|
|
|
|
|
|
|
|
594
|
0
|
|
|
|
|
|
return $ntok; |
595
|
|
|
|
|
|
|
} |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
########################################################### |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
sub analyse_pipeline { |
600
|
0
|
|
|
0
|
0
|
|
my @args = @_; |
601
|
0
|
|
|
|
|
|
my $ntok = @args; |
602
|
0
|
|
|
|
|
|
my $end_value = ''; |
603
|
|
|
|
|
|
|
|
604
|
0
|
|
|
|
|
|
error_out (); |
605
|
0
|
|
|
|
|
|
error_out "Pipeline '@args' detected"; |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
#my @caller = caller(); |
608
|
|
|
|
|
|
|
#print STDERR "analyse_pipeline: <@args><@caller>\n"; |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
# Get commands, sometimes the | is separate, sometimes not |
611
|
0
|
|
|
|
|
|
@args = split /\|/, "@args"; |
612
|
|
|
|
|
|
|
|
613
|
0
|
|
|
|
|
|
App::sh2p::Handlers::no_semi_colon(); |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
# Let's make a guess. echo or print at the front usually means |
616
|
|
|
|
|
|
|
# that the command which follows wants a string |
617
|
0
|
0
|
|
|
|
|
if ($args[0] =~ s/^(echo |print )//) { |
618
|
0
|
|
|
|
|
|
$end_value = shift @args; |
619
|
|
|
|
|
|
|
} |
620
|
|
|
|
|
|
|
|
621
|
0
|
|
|
|
|
|
for (my $i = 0; $i < @args; $i++) { |
622
|
0
|
|
|
|
|
|
$args[$i] =~ s/^\s+//; # Strip leading whitespace |
623
|
0
|
|
|
|
|
|
$args[$i] =~ s/\s+$//; # Strip trailing whitespace |
624
|
|
|
|
|
|
|
|
625
|
0
|
0
|
|
|
|
|
if (! $args[$i] ) { |
626
|
|
|
|
|
|
|
# Blank line - remove it |
627
|
0
|
|
|
|
|
|
splice (@args, $i, 1); |
628
|
0
|
|
|
|
|
|
$i--; # to counteract the ++ |
629
|
0
|
|
|
|
|
|
next; |
630
|
|
|
|
|
|
|
} |
631
|
|
|
|
|
|
|
|
632
|
0
|
|
|
|
|
|
my @tokens = tokenise ($args[$i]); |
633
|
0
|
|
|
|
|
|
my @types = identify (0, @tokens); |
634
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
# We are delimited by |, so get the arguments as well |
636
|
|
|
|
|
|
|
# external call is not the last in the pipe, change to back-ticks |
637
|
0
|
0
|
0
|
|
|
|
if ( $types[0][0] eq 'EXTERNAL' && $i < $#args) { |
638
|
|
|
|
|
|
|
|
639
|
0
|
|
|
|
|
|
@types = (['DELIMITER',\&App::sh2p::Handlers::Handle_2char_qx]); |
640
|
0
|
|
|
|
|
|
@tokens = ("\$(@tokens)"); |
641
|
|
|
|
|
|
|
|
642
|
0
|
0
|
|
|
|
|
if ($args[$i+1] =~ /^\s*grep/) { |
643
|
|
|
|
|
|
|
# Switch next command around with this |
644
|
0
|
|
|
|
|
|
$i++; |
645
|
0
|
|
|
|
|
|
$args[$i] =~ s/^\s+//; |
646
|
0
|
|
|
|
|
|
$args[$i] =~ s/\s+$//; |
647
|
|
|
|
|
|
|
|
648
|
0
|
|
|
|
|
|
my @next_tokens = tokenise ($args[$i]); |
649
|
0
|
|
|
|
|
|
my @next_types = identify (0, @next_tokens); |
650
|
0
|
|
|
|
|
|
convert (@next_tokens, @next_types); |
651
|
|
|
|
|
|
|
} |
652
|
|
|
|
|
|
|
} |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
#print_types_tokens (\@types, \@tokens); |
655
|
|
|
|
|
|
|
|
656
|
0
|
|
|
|
|
|
convert (@tokens, @types); |
657
|
0
|
0
|
|
|
|
|
out '|' if $i < $#args; |
658
|
|
|
|
|
|
|
} |
659
|
0
|
|
|
|
|
|
out "$end_value"; |
660
|
0
|
0
|
|
|
|
|
out "\n" if !App::sh2p::Compound::get_context(); |
661
|
|
|
|
|
|
|
|
662
|
0
|
|
|
|
|
|
App::sh2p::Handlers::reset_semi_colon(); |
663
|
0
|
|
|
|
|
|
error_out (); |
664
|
|
|
|
|
|
|
|
665
|
0
|
|
|
|
|
|
return $ntok; |
666
|
|
|
|
|
|
|
} |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
########################################################### |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
1; |