| 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; |