line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Shell::Base; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
4
|
|
|
|
|
|
|
# Shell::Base - A generic class to build line-oriented command interpreters. |
5
|
|
|
|
|
|
|
# $Id: Base.pm,v 1.5 2004/08/26 20:01:47 dlc Exp $ |
6
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
7
|
|
|
|
|
|
|
# Copyright (C) 2003 darren chamberlain |
8
|
|
|
|
|
|
|
# |
9
|
|
|
|
|
|
|
# This module is free software; you can redistribute it and/or |
10
|
|
|
|
|
|
|
# modify it under the same terms as Perl itself. |
11
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
12
|
|
|
|
|
|
|
|
13
|
21
|
|
|
21
|
|
9204185
|
use strict; |
|
21
|
|
|
|
|
54
|
|
|
21
|
|
|
|
|
1014
|
|
14
|
21
|
|
|
|
|
2433
|
use vars qw( $VERSION $REVISION $PROMPT |
15
|
|
|
|
|
|
|
$RE_QUIT $RE_HELP $RE_SHEBANG |
16
|
21
|
|
|
21
|
|
2169
|
); |
|
21
|
|
|
|
|
51
|
|
17
|
|
|
|
|
|
|
|
18
|
21
|
|
|
21
|
|
117
|
use Carp qw(carp croak); |
|
21
|
|
|
|
|
41
|
|
|
21
|
|
|
|
|
2134
|
|
19
|
21
|
|
|
21
|
|
31170
|
use Env qw($PAGER $SHELL $COLUMNS); |
|
21
|
|
|
|
|
2703179
|
|
|
21
|
|
|
|
|
143
|
|
20
|
21
|
|
|
21
|
|
28650
|
use IO::File; |
|
21
|
|
|
|
|
1269230
|
|
|
21
|
|
|
|
|
4032
|
|
21
|
21
|
|
|
21
|
|
230
|
use File::Basename qw(basename); |
|
21
|
|
|
|
|
47
|
|
|
21
|
|
|
|
|
2649
|
|
22
|
21
|
|
|
21
|
|
23509
|
use Term::Size qw(chars); |
|
21
|
|
|
|
|
437819
|
|
|
21
|
|
|
|
|
1642
|
|
23
|
21
|
|
|
21
|
|
20232
|
use Text::Shellwords qw(shellwords); |
|
21
|
|
|
|
|
61255
|
|
|
21
|
|
|
|
|
4062
|
|
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
$VERSION = 0.05; # $Date: 2004/08/26 20:01:47 $ |
26
|
|
|
|
|
|
|
$REVISION = sprintf "%d.%02d", q$Revision: 1.5 $ =~ /(\d+)\.(\d+)/; |
27
|
|
|
|
|
|
|
$RE_QUIT = '(?i)^\s*(exit|quit|logout)' unless defined $RE_QUIT; |
28
|
|
|
|
|
|
|
$RE_HELP = '(?i)^\s*(help|\?)' unless defined $RE_HELP; |
29
|
|
|
|
|
|
|
$RE_SHEBANG = '^\s*!\s*$' unless defined $RE_SHEBANG; |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
32
|
|
|
|
|
|
|
# import() |
33
|
|
|
|
|
|
|
# |
34
|
|
|
|
|
|
|
# The default import method, called when the class is use'd. This |
35
|
|
|
|
|
|
|
# sets the default prompt, which can be overridden by a subclass as |
36
|
|
|
|
|
|
|
# necessary. |
37
|
|
|
|
|
|
|
# |
38
|
|
|
|
|
|
|
# There is a pseudo-function called "shell" that can be imported by |
39
|
|
|
|
|
|
|
# classes which use a Shell::Base-originated class: |
40
|
|
|
|
|
|
|
# |
41
|
|
|
|
|
|
|
# use My::Shell qw(shell); |
42
|
|
|
|
|
|
|
# |
43
|
|
|
|
|
|
|
# shell(); |
44
|
|
|
|
|
|
|
# |
45
|
|
|
|
|
|
|
# Tests: t/import.t |
46
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
47
|
|
|
|
|
|
|
sub import { |
48
|
48
|
|
|
48
|
|
23234
|
my $class = shift; |
49
|
|
|
|
|
|
|
|
50
|
48
|
100
|
66
|
|
|
331
|
if (@_ && grep /^shell$/, @_) { |
51
|
|
|
|
|
|
|
# Requested as use Shell::Base qw(shell), or |
52
|
|
|
|
|
|
|
# from the command line as -MShell::Base=shell |
53
|
|
|
|
|
|
|
# Install the shell function into the caller's |
54
|
|
|
|
|
|
|
# namespace. However, there is no shell |
55
|
|
|
|
|
|
|
# function; we create one here. shell would |
56
|
|
|
|
|
|
|
# be invoked by the caller as: |
57
|
|
|
|
|
|
|
# |
58
|
|
|
|
|
|
|
# shell(@args); |
59
|
|
|
|
|
|
|
# |
60
|
|
|
|
|
|
|
# i.e., without a package, so we need to pass |
61
|
|
|
|
|
|
|
# a package in. A closure will do nicely. |
62
|
|
|
|
|
|
|
|
63
|
21
|
|
|
21
|
|
163
|
no strict qw(refs); |
|
21
|
|
|
|
|
49
|
|
|
21
|
|
|
|
|
19298
|
|
64
|
10
|
|
|
|
|
20
|
my $caller = caller; |
65
|
10
|
|
|
|
|
41
|
*{"$caller\::shell"} = sub { |
66
|
0
|
|
|
0
|
|
0
|
$class->new(@_)->run(); |
67
|
10
|
|
|
|
|
42
|
}; |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
|
70
|
48
|
100
|
|
|
|
33673
|
$PROMPT = "($class) \$ " unless defined $PROMPT; |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
74
|
|
|
|
|
|
|
# new(\%args) |
75
|
|
|
|
|
|
|
# |
76
|
|
|
|
|
|
|
# Basic constructor. |
77
|
|
|
|
|
|
|
# |
78
|
|
|
|
|
|
|
# new() calls initialization methods: |
79
|
|
|
|
|
|
|
# |
80
|
|
|
|
|
|
|
# - init_rl |
81
|
|
|
|
|
|
|
# |
82
|
|
|
|
|
|
|
# o Initializes the Term::ReadLine instance |
83
|
|
|
|
|
|
|
# |
84
|
|
|
|
|
|
|
# - init_rcfiles |
85
|
|
|
|
|
|
|
# |
86
|
|
|
|
|
|
|
# o Initializes rc files (anything in RCFILES) |
87
|
|
|
|
|
|
|
# |
88
|
|
|
|
|
|
|
# - init_help |
89
|
|
|
|
|
|
|
# |
90
|
|
|
|
|
|
|
# o Initializes the list of help methods |
91
|
|
|
|
|
|
|
# |
92
|
|
|
|
|
|
|
# - init_completions |
93
|
|
|
|
|
|
|
# |
94
|
|
|
|
|
|
|
# o Initializes the list of tab-completable commands |
95
|
|
|
|
|
|
|
# |
96
|
|
|
|
|
|
|
# - init |
97
|
|
|
|
|
|
|
# |
98
|
|
|
|
|
|
|
# o Subclass-specific intializations. |
99
|
|
|
|
|
|
|
# |
100
|
|
|
|
|
|
|
# Tests: t/new.t |
101
|
|
|
|
|
|
|
# All tests instantiate objects, so new is tested indirectly |
102
|
|
|
|
|
|
|
# by all tests. |
103
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
104
|
|
|
|
|
|
|
sub new { |
105
|
16
|
|
|
16
|
1
|
7546
|
my $class = shift; |
106
|
16
|
100
|
|
|
|
151
|
my $args = UNIVERSAL::isa($_[0], 'HASH') ? shift : { @_ }; |
107
|
|
|
|
|
|
|
|
108
|
16
|
|
|
|
|
283
|
my @size = chars(); |
109
|
16
|
|
|
|
|
241
|
my $self = bless { |
110
|
|
|
|
|
|
|
ARGS => $args, |
111
|
|
|
|
|
|
|
COMPLETIONS => undef, # tab completion |
112
|
|
|
|
|
|
|
CONFIG => { }, |
113
|
|
|
|
|
|
|
HELPS => undef, # help methods |
114
|
|
|
|
|
|
|
HISTFILE => undef, # history file |
115
|
|
|
|
|
|
|
PAGER => undef, # pager |
116
|
|
|
|
|
|
|
PROMPT => $PROMPT, # default prompt |
117
|
|
|
|
|
|
|
TERM => undef, # Term::ReadLine instance |
118
|
|
|
|
|
|
|
SIZE => \@size, # Terminal size |
119
|
|
|
|
|
|
|
COLUMNS => $size[0], |
120
|
|
|
|
|
|
|
ROWS => $size[1], |
121
|
|
|
|
|
|
|
} => $class; |
122
|
|
|
|
|
|
|
|
123
|
16
|
|
|
|
|
91
|
$self->init_rl($args); |
124
|
13
|
|
|
|
|
396
|
$self->init_rcfiles($args); |
125
|
13
|
|
|
|
|
249
|
$self->init_completions($args); |
126
|
13
|
|
|
|
|
340
|
$self->init_help($args); |
127
|
13
|
|
|
|
|
556
|
$self->init($args); |
128
|
|
|
|
|
|
|
|
129
|
13
|
|
|
|
|
163
|
return $self; |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
133
|
|
|
|
|
|
|
# init_rl(\%args) |
134
|
|
|
|
|
|
|
# |
135
|
|
|
|
|
|
|
# Initialize Term::ReadLine. Subclasses can override this method if |
136
|
|
|
|
|
|
|
# readline support is not needed or wanted. |
137
|
|
|
|
|
|
|
# |
138
|
|
|
|
|
|
|
# Tests: t/init_rl.t |
139
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
140
|
|
|
|
|
|
|
sub init_rl { |
141
|
16
|
|
|
16
|
1
|
38
|
my ($self, $args) = @_; |
142
|
16
|
|
|
|
|
33
|
my ($term, $attr); |
143
|
|
|
|
|
|
|
|
144
|
16
|
|
|
|
|
17975
|
require Term::ReadLine; |
145
|
16
|
|
|
|
|
67079
|
$self->term($term = Term::ReadLine->new(ref $self)); |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
# Setup default tab-completion function. |
148
|
16
|
|
|
|
|
215
|
$attr = $term->Attribs; |
149
|
16
|
|
|
0
|
|
452
|
$attr->{completion_function} = sub { $self->complete(@_) }; |
|
0
|
|
|
|
|
0
|
|
150
|
|
|
|
|
|
|
|
151
|
16
|
100
|
|
|
|
156
|
if (my $histfile = $args->{ HISTFILE }) { |
152
|
3
|
|
|
|
|
22
|
$self->histfile($histfile); |
153
|
3
|
|
|
|
|
1295
|
$term->ReadHistory($histfile); |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
13
|
|
|
|
|
187
|
return $self; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
160
|
|
|
|
|
|
|
# init_rcfiles(\%args) |
161
|
|
|
|
|
|
|
# |
162
|
|
|
|
|
|
|
# Initialize rc files, which are in name = value format. The RCFILES |
163
|
|
|
|
|
|
|
# member of %args should contain a reference to a rc files. These |
164
|
|
|
|
|
|
|
# will be read in the order defined, and all elements defined within |
165
|
|
|
|
|
|
|
# will be present in $self->{ CONFIG }, and accessible via $self->config. |
166
|
|
|
|
|
|
|
# |
167
|
|
|
|
|
|
|
# test: t/init_rcfiles.t |
168
|
|
|
|
|
|
|
# XXX Refactor this into init_rcfiles and parse_rcfile! |
169
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
170
|
|
|
|
|
|
|
sub init_rcfiles { |
171
|
13
|
|
|
13
|
1
|
889
|
my ($self, $args) = @_; |
172
|
13
|
|
|
|
|
37
|
my (@rcfiles, $rcfile); |
173
|
|
|
|
|
|
|
|
174
|
13
|
100
|
|
|
|
92
|
return unless defined $args->{ RCFILES }; |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
# Ensure we have an array |
177
|
|
|
|
|
|
|
$args->{ RCFILES } = [ $args->{ RCFILES } ] |
178
|
1
|
50
|
|
|
|
5
|
unless ref($args->{ RCFILES }) eq 'ARRAY'; |
179
|
|
|
|
|
|
|
|
180
|
1
|
|
|
|
|
2
|
@rcfiles = @{ $args->{ RCFILES } }; |
|
1
|
|
|
|
|
12
|
|
181
|
|
|
|
|
|
|
|
182
|
1
|
|
|
|
|
5
|
for $rcfile (@rcfiles) { |
183
|
|
|
|
|
|
|
_merge_hash($self->{ CONFIG }, |
184
|
1
|
|
|
|
|
6
|
scalar $self->parse_rcfile($rcfile)); |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
189
|
|
|
|
|
|
|
# parse_rcfile($filename) |
190
|
|
|
|
|
|
|
# |
191
|
|
|
|
|
|
|
# Parses a config file, and returns a hash of config values. |
192
|
|
|
|
|
|
|
# |
193
|
|
|
|
|
|
|
# test: t/parse_rcfile.t |
194
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
195
|
|
|
|
|
|
|
sub parse_rcfile { |
196
|
2
|
|
|
2
|
0
|
785
|
my ($self, $rcfile) = @_; |
197
|
2
|
|
|
|
|
5
|
my %config = (); |
198
|
|
|
|
|
|
|
|
199
|
2
|
|
|
|
|
7
|
my $buffer = ""; |
200
|
2
|
50
|
|
|
|
35
|
my $rc = IO::File->new($rcfile) |
201
|
|
|
|
|
|
|
or next; |
202
|
|
|
|
|
|
|
|
203
|
2
|
|
|
|
|
330
|
while (defined(my $line = <$rc>)) { |
204
|
48
|
|
|
|
|
62
|
chomp $line; |
205
|
48
|
|
|
|
|
108
|
$line =~ s/#.*$//; |
206
|
|
|
|
|
|
|
|
207
|
48
|
100
|
66
|
|
|
123
|
if (length $buffer && length $line) { |
208
|
4
|
|
|
|
|
8
|
$line = $buffer . $line; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
# Line continuation |
212
|
48
|
100
|
|
|
|
100
|
if ($line =~ s/\\$//) { |
213
|
4
|
|
|
|
|
6
|
$buffer = $line; |
214
|
4
|
|
|
|
|
12
|
next; |
215
|
|
|
|
|
|
|
} else { |
216
|
44
|
|
|
|
|
61
|
$buffer = ''; |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
|
219
|
44
|
100
|
|
|
|
140
|
next unless length $line; |
220
|
|
|
|
|
|
|
|
221
|
14
|
|
|
|
|
97
|
my ($name, $value) = $line =~ /^\s*(.*?)\s*(?:=>?\s*(.*))?$/; |
222
|
14
|
|
|
|
|
25
|
$name = lc $name; |
223
|
14
|
100
|
|
|
|
33
|
unless (defined $value) { |
224
|
2
|
100
|
|
|
|
12
|
if ($name =~ s/^no//) { |
225
|
1
|
|
|
|
|
1
|
$value = 0; |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
else { |
228
|
1
|
|
|
|
|
2
|
$value = 1; |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
} |
231
|
14
|
|
|
|
|
73
|
$config{ $name } = $value; |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
|
234
|
2
|
100
|
|
|
|
49
|
return wantarray ? %config : \%config; |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
238
|
|
|
|
|
|
|
# init_help() |
239
|
|
|
|
|
|
|
# |
240
|
|
|
|
|
|
|
# Initializes the internal HELPS list, which is a list of all the |
241
|
|
|
|
|
|
|
# help_foo methods defined within the current class, and all the |
242
|
|
|
|
|
|
|
# classes from which the current class inherits from. |
243
|
|
|
|
|
|
|
# |
244
|
|
|
|
|
|
|
# Tests: t/init_help.t |
245
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
246
|
|
|
|
|
|
|
sub init_help { |
247
|
14
|
|
|
14
|
1
|
1665
|
my $self = shift; |
248
|
14
|
|
33
|
|
|
91
|
my $class = ref $self || $self; |
249
|
14
|
|
|
|
|
38
|
my %uniq = (); |
250
|
|
|
|
|
|
|
|
251
|
21
|
|
|
21
|
|
417
|
no strict qw(refs); |
|
21
|
|
|
|
|
51
|
|
|
21
|
|
|
|
|
3785
|
|
252
|
15
|
|
|
|
|
123
|
$self->helps( |
253
|
15
|
|
|
|
|
91
|
grep { ++$uniq{$_} == 1 } |
254
|
15
|
|
|
|
|
48
|
map { s/^help_//; $_ } |
|
3
|
|
|
|
|
285
|
|
255
|
|
|
|
|
|
|
grep /^help_/, |
256
|
3
|
|
|
|
|
7
|
map({ %{"$_\::"} } @{"$class\::ISA"}), |
|
14
|
|
|
|
|
66
|
|
|
14
|
|
|
|
|
764
|
|
257
|
14
|
|
|
|
|
39
|
keys %{"$class\::"}); |
258
|
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
261
|
|
|
|
|
|
|
# init_completions() |
262
|
|
|
|
|
|
|
# |
263
|
|
|
|
|
|
|
# Initializes the internal COMPLETIONS list, which is used by the |
264
|
|
|
|
|
|
|
# complete method, which is, in turn, used by Term::ReadLine to |
265
|
|
|
|
|
|
|
# do tab-compleion. |
266
|
|
|
|
|
|
|
# |
267
|
|
|
|
|
|
|
# Tests: t/init_completions.t |
268
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
269
|
|
|
|
|
|
|
sub init_completions { |
270
|
13
|
|
|
13
|
1
|
54
|
my $self = shift; |
271
|
13
|
|
33
|
|
|
104
|
my $class = ref $self || $self; |
272
|
13
|
|
|
|
|
53
|
my %uniq = (); |
273
|
|
|
|
|
|
|
|
274
|
21
|
|
|
21
|
|
115
|
no strict qw(refs); |
|
21
|
|
|
|
|
33
|
|
|
21
|
|
|
|
|
59728
|
|
275
|
26
|
|
|
|
|
494
|
$self->completions( |
276
|
|
|
|
|
|
|
sort |
277
|
|
|
|
|
|
|
"help", |
278
|
26
|
|
|
|
|
142
|
grep { ++$uniq{$_} == 1 } |
279
|
26
|
|
|
|
|
104
|
map { s/^do_//; $_ } |
|
3
|
|
|
|
|
1483
|
|
280
|
|
|
|
|
|
|
grep /^do_/, |
281
|
3
|
|
|
|
|
6
|
map({ %{"$_\::"} } @{"$class\::ISA"}), |
|
13
|
|
|
|
|
232
|
|
|
13
|
|
|
|
|
1895
|
|
282
|
13
|
|
|
|
|
39
|
keys %{"$class\::"}); |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
286
|
|
|
|
|
|
|
# init(\%args) |
287
|
|
|
|
|
|
|
# |
288
|
|
|
|
|
|
|
# Basic init method; subclasses can override this as needed. This is |
289
|
|
|
|
|
|
|
# the place to do any subclass-specific initialization. |
290
|
|
|
|
|
|
|
# |
291
|
|
|
|
|
|
|
# Command completion is initialized here, so subclasses should call |
292
|
|
|
|
|
|
|
# $self->SUPER::init(@_) within overridden init methods if they want |
293
|
|
|
|
|
|
|
# this completion to be setup. |
294
|
|
|
|
|
|
|
# |
295
|
|
|
|
|
|
|
# Tests: none (why?) |
296
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
297
|
|
|
|
|
|
|
sub init { |
298
|
13
|
|
|
13
|
1
|
34
|
my ($self, $args) = @_; |
299
|
|
|
|
|
|
|
|
300
|
13
|
|
|
|
|
29
|
return $self; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
304
|
|
|
|
|
|
|
# run() |
305
|
|
|
|
|
|
|
# |
306
|
|
|
|
|
|
|
# run is the main() of the interpreter. Its duties are: |
307
|
|
|
|
|
|
|
# |
308
|
|
|
|
|
|
|
# - Print the results of $self->intro(), if defined, |
309
|
|
|
|
|
|
|
# via $self->print() |
310
|
|
|
|
|
|
|
# |
311
|
|
|
|
|
|
|
# - Get a line of input, via $self->term->readline. |
312
|
|
|
|
|
|
|
# This begins the run loop. |
313
|
|
|
|
|
|
|
# |
314
|
|
|
|
|
|
|
# o Pass this line to $self->precmd for massaging |
315
|
|
|
|
|
|
|
# |
316
|
|
|
|
|
|
|
# o Pass this line to $self->parseline for splitting into |
317
|
|
|
|
|
|
|
# (command_name, variable assignments, arguments) |
318
|
|
|
|
|
|
|
# |
319
|
|
|
|
|
|
|
# o Check contents of command_name; there are a few special |
320
|
|
|
|
|
|
|
# cases: |
321
|
|
|
|
|
|
|
# |
322
|
|
|
|
|
|
|
# + If the line is a help line (matches $RE_HELP), then |
323
|
|
|
|
|
|
|
# call $self->help(@args) |
324
|
|
|
|
|
|
|
# |
325
|
|
|
|
|
|
|
# + If the line is a quit line (matches $RE_QUIT), then |
326
|
|
|
|
|
|
|
# call $self->quit() |
327
|
|
|
|
|
|
|
# |
328
|
|
|
|
|
|
|
# + If the line is a bang (matches $RE_SHEBANG), then |
329
|
|
|
|
|
|
|
# invoke $self->do_shell() |
330
|
|
|
|
|
|
|
# |
331
|
|
|
|
|
|
|
# + Otherwise, attempt to invoke $self->do_$command_name |
332
|
|
|
|
|
|
|
# |
333
|
|
|
|
|
|
|
# o The output from whichever of the above is chosen will be |
334
|
|
|
|
|
|
|
# passed to $self->postcmd for final processing |
335
|
|
|
|
|
|
|
# |
336
|
|
|
|
|
|
|
# o If the output from $self->postcmd is not undefined, it |
337
|
|
|
|
|
|
|
# will be printed via $self->print() |
338
|
|
|
|
|
|
|
# |
339
|
|
|
|
|
|
|
# o The prompt is reset, and control returns to the top of |
340
|
|
|
|
|
|
|
# the run loop. |
341
|
|
|
|
|
|
|
# |
342
|
|
|
|
|
|
|
# Tests: none (Dunno how, without requiring Expect (yuck)) |
343
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
344
|
|
|
|
|
|
|
sub run { |
345
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
346
|
0
|
|
|
|
|
0
|
my ($prompt, $blurb); |
347
|
|
|
|
|
|
|
|
348
|
0
|
|
|
|
|
0
|
$prompt = $self->prompt; |
349
|
0
|
|
|
|
|
0
|
$blurb = $self->intro; |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
|
352
|
0
|
0
|
|
|
|
0
|
if (defined $blurb) { |
353
|
0
|
|
|
|
|
0
|
chomp $blurb; |
354
|
0
|
|
|
|
|
0
|
$self->print("$blurb\n"); |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
|
357
|
0
|
|
|
|
|
0
|
while (defined (my $line = $self->readline($prompt))) { |
358
|
0
|
|
|
|
|
0
|
my (@args, $cmd, $env, $output); |
359
|
|
|
|
|
|
|
|
360
|
0
|
|
|
|
|
0
|
$line = $self->precmd($line); |
361
|
|
|
|
|
|
|
|
362
|
0
|
|
|
|
|
0
|
($cmd, $env, @args) = $self->parseline($line); |
363
|
0
|
|
|
|
|
0
|
local %ENV = (%ENV, %$env); |
364
|
|
|
|
|
|
|
|
365
|
0
|
0
|
|
|
|
0
|
if (! length($cmd)) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
366
|
0
|
|
|
|
|
0
|
$output = $self->emptycommand(); |
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
elsif ($cmd =~ /$RE_HELP/) { |
369
|
0
|
|
|
|
|
0
|
$output = $self->help(@args); |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
elsif ($cmd =~ /$RE_QUIT/) { |
372
|
0
|
|
|
|
|
0
|
$self->quit; |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
else { |
375
|
0
|
0
|
|
|
|
0
|
if ($cmd =~ /$RE_SHEBANG/) { |
376
|
0
|
|
|
|
|
0
|
$cmd = "shell"; |
377
|
|
|
|
|
|
|
} |
378
|
0
|
|
|
|
|
0
|
eval { |
379
|
0
|
|
|
|
|
0
|
my $meth = "do_$cmd"; |
380
|
0
|
|
|
|
|
0
|
$output = $self->$meth(@args); |
381
|
|
|
|
|
|
|
}; |
382
|
0
|
0
|
|
|
|
0
|
if ($@) { |
383
|
0
|
|
|
|
|
0
|
$output = sprintf "%s: Bad command or filename", $self->progname; |
384
|
0
|
|
|
|
|
0
|
my $err = $@; |
385
|
0
|
|
|
|
|
0
|
chomp $err; |
386
|
0
|
|
|
|
|
0
|
warn "$output ($err)\n"; |
387
|
0
|
|
|
|
|
0
|
eval { |
388
|
0
|
|
|
|
|
0
|
$output = $self->default($cmd, @args); |
389
|
|
|
|
|
|
|
}; |
390
|
|
|
|
|
|
|
} |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
|
393
|
0
|
|
|
|
|
0
|
$output = $self->postcmd($output); |
394
|
0
|
|
|
|
|
0
|
$output =~ s/\n*$//; |
395
|
|
|
|
|
|
|
|
396
|
0
|
|
|
|
|
0
|
chomp $output; |
397
|
0
|
0
|
|
|
|
0
|
$self->print("$output\n") if defined $output; |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
# In case precmd or postcmd modified the prompt, |
400
|
|
|
|
|
|
|
# we recollect it before displaying it. |
401
|
0
|
|
|
|
|
0
|
$prompt = $self->prompt(); |
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
|
404
|
0
|
|
|
|
|
0
|
$self->quit(); |
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
408
|
|
|
|
|
|
|
# readline() |
409
|
|
|
|
|
|
|
# |
410
|
|
|
|
|
|
|
# Calls readline on the internal Term::ReadLine instance. Provided |
411
|
|
|
|
|
|
|
# as a separate method within Shell::Base so that subclasses which |
412
|
|
|
|
|
|
|
# do not want to use Term::ReadLine don't have to. |
413
|
|
|
|
|
|
|
# |
414
|
|
|
|
|
|
|
# Tests: none (how?) |
415
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
416
|
|
|
|
|
|
|
sub readline { |
417
|
0
|
|
|
0
|
1
|
0
|
my ($self, $prompt) = @_; |
418
|
0
|
|
|
|
|
0
|
return $self->term->readline($prompt); |
419
|
|
|
|
|
|
|
} |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
422
|
|
|
|
|
|
|
# print(@data) |
423
|
|
|
|
|
|
|
# |
424
|
|
|
|
|
|
|
# This method is here to that subclasses can redirect their output |
425
|
|
|
|
|
|
|
# stream without having to do silly things like tie STDOUT (although |
426
|
|
|
|
|
|
|
# they still can if they want, by overriding this method). |
427
|
|
|
|
|
|
|
# |
428
|
|
|
|
|
|
|
# Tests: none |
429
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
430
|
|
|
|
|
|
|
sub print { |
431
|
0
|
|
|
0
|
1
|
0
|
my ($self, @stuff) = @_; |
432
|
0
|
|
|
|
|
0
|
my $OUT = $self->term->Attribs->{'outstream'}; |
433
|
|
|
|
|
|
|
|
434
|
0
|
|
|
|
|
0
|
CORE::print $OUT @stuff; |
435
|
|
|
|
|
|
|
} |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
438
|
|
|
|
|
|
|
# quit([$status]) |
439
|
|
|
|
|
|
|
# |
440
|
|
|
|
|
|
|
# Exits the interpreter with $status as the exit status (0 by default). |
441
|
|
|
|
|
|
|
# If $self->outro() returns a defined value, it is printed here. |
442
|
|
|
|
|
|
|
# |
443
|
|
|
|
|
|
|
# Tests: none |
444
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
445
|
|
|
|
|
|
|
sub quit { |
446
|
0
|
|
|
0
|
1
|
0
|
my ($self, $status) = @_; |
447
|
0
|
0
|
|
|
|
0
|
$status = 0 unless defined $status; |
448
|
|
|
|
|
|
|
|
449
|
0
|
|
|
|
|
0
|
my $blurb = $self->outro(); |
450
|
0
|
0
|
|
|
|
0
|
$self->print("$blurb\n") if defined $blurb; |
451
|
|
|
|
|
|
|
|
452
|
0
|
0
|
|
|
|
0
|
if (my $h = $self->histfile) { |
453
|
|
|
|
|
|
|
# XXX Can this be better encapsulated? |
454
|
0
|
|
|
|
|
0
|
$self->term->WriteHistory($h); |
455
|
|
|
|
|
|
|
} |
456
|
|
|
|
|
|
|
|
457
|
0
|
|
|
|
|
0
|
exit($status); |
458
|
|
|
|
|
|
|
} |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
462
|
|
|
|
|
|
|
# precmd($line) |
463
|
|
|
|
|
|
|
# |
464
|
|
|
|
|
|
|
# This is called immediately before parseline(), to give the subclass |
465
|
|
|
|
|
|
|
# first crack at manipulating the input line. This might be a good |
466
|
|
|
|
|
|
|
# place to do, for example, tilde-expansion, or some other kind of |
467
|
|
|
|
|
|
|
# variable pre-processing. |
468
|
|
|
|
|
|
|
# |
469
|
|
|
|
|
|
|
# Tests: t/pre,postcmd.t |
470
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
471
|
|
|
|
|
|
|
sub precmd { |
472
|
1
|
|
|
1
|
1
|
445
|
my ($self, $line) = @_; |
473
|
1
|
|
|
|
|
8
|
return $line; |
474
|
|
|
|
|
|
|
} |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
477
|
|
|
|
|
|
|
# postcmd($output) |
478
|
|
|
|
|
|
|
# |
479
|
|
|
|
|
|
|
# This is called immediately before $output is passed to print, to |
480
|
|
|
|
|
|
|
# give the class one last chance to manipulate the text before it is |
481
|
|
|
|
|
|
|
# sent to the output stream. |
482
|
|
|
|
|
|
|
# |
483
|
|
|
|
|
|
|
# Tests: t/pre,postcmd.t |
484
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
485
|
|
|
|
|
|
|
sub postcmd { |
486
|
1
|
|
|
1
|
1
|
2
|
my ($self, $output) = @_; |
487
|
1
|
|
|
|
|
7
|
return $output; |
488
|
|
|
|
|
|
|
} |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
491
|
|
|
|
|
|
|
# default($cmd, @args) |
492
|
|
|
|
|
|
|
# |
493
|
|
|
|
|
|
|
# What to do by default, i.e., when there is no matching do_foo method. |
494
|
|
|
|
|
|
|
# |
495
|
|
|
|
|
|
|
# Tests: t/default.t |
496
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
497
|
|
|
|
|
|
|
sub default { |
498
|
2
|
|
|
2
|
1
|
507
|
my ($self, $cmd, @args) = @_; |
499
|
2
|
|
33
|
|
|
11
|
my $class = ref $self || $self; |
500
|
2
|
|
|
|
|
16
|
return "$class->$cmd(@args) called, but do_$cmd is not defined!"; |
501
|
|
|
|
|
|
|
} |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
504
|
|
|
|
|
|
|
# emptycommand() |
505
|
|
|
|
|
|
|
# |
506
|
|
|
|
|
|
|
# What to do when an empty command is issued |
507
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
508
|
|
|
|
|
|
|
sub emptycommand { |
509
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
510
|
0
|
|
|
|
|
0
|
return; |
511
|
|
|
|
|
|
|
} |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
514
|
|
|
|
|
|
|
# prompt_no() |
515
|
|
|
|
|
|
|
# |
516
|
|
|
|
|
|
|
# Returns the command number in the history. |
517
|
|
|
|
|
|
|
# |
518
|
|
|
|
|
|
|
# Tests: t/prompt_no.t |
519
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
520
|
|
|
|
|
|
|
sub prompt_no { |
521
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
522
|
0
|
|
|
|
|
0
|
return $self->term->where_history(); |
523
|
|
|
|
|
|
|
} |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
526
|
|
|
|
|
|
|
# Some general purpose methods. Subclasses may wish to override some |
527
|
|
|
|
|
|
|
# of these, but many of them (version, progname) are probably ok as is. |
528
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
531
|
|
|
|
|
|
|
# version() |
532
|
|
|
|
|
|
|
# |
533
|
|
|
|
|
|
|
# Returns the version number. |
534
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
535
|
|
|
|
|
|
|
sub version { |
536
|
2
|
|
|
2
|
0
|
642
|
return $VERSION; |
537
|
|
|
|
|
|
|
} |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
540
|
|
|
|
|
|
|
# do_version() |
541
|
|
|
|
|
|
|
# |
542
|
|
|
|
|
|
|
# Example command method. |
543
|
|
|
|
|
|
|
# |
544
|
|
|
|
|
|
|
# Tests: t/version.t |
545
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
546
|
|
|
|
|
|
|
sub do_version { |
547
|
1
|
|
|
1
|
0
|
358
|
my $self = shift; |
548
|
1
|
|
|
|
|
6
|
return sprintf "%s v%s", $self->progname, $self->version; |
549
|
|
|
|
|
|
|
} |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
sub help_version { |
552
|
1
|
|
|
1
|
0
|
8
|
return "Display the version." |
553
|
|
|
|
|
|
|
} |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
556
|
|
|
|
|
|
|
# progname() |
557
|
|
|
|
|
|
|
# |
558
|
|
|
|
|
|
|
# Returns the name of the program in question. Defaults to |
559
|
|
|
|
|
|
|
# basename($0) or the classname of the caller. |
560
|
|
|
|
|
|
|
# |
561
|
|
|
|
|
|
|
# Tests: t/progname.t |
562
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
563
|
|
|
|
|
|
|
sub progname { |
564
|
6
|
|
|
6
|
0
|
1937
|
my $self = shift; |
565
|
6
|
|
33
|
|
|
316
|
return basename($0) || ref $self || $self; |
566
|
|
|
|
|
|
|
} |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
569
|
|
|
|
|
|
|
# intro() |
570
|
|
|
|
|
|
|
# |
571
|
|
|
|
|
|
|
# Introduction text, printed when the interpreter starts up. The |
572
|
|
|
|
|
|
|
# default is to print the GPL-recommended introduction. I would |
573
|
|
|
|
|
|
|
# hope that modules that utilize Shell::Base would create intro() |
574
|
|
|
|
|
|
|
# methods that incorporate this, if possible: |
575
|
|
|
|
|
|
|
# |
576
|
|
|
|
|
|
|
# sub intro { |
577
|
|
|
|
|
|
|
# my $self = shift; |
578
|
|
|
|
|
|
|
# my $default_intro = $self->SUPER::intro(); |
579
|
|
|
|
|
|
|
# |
580
|
|
|
|
|
|
|
# return "My Intro\n$default_intro"; |
581
|
|
|
|
|
|
|
# } |
582
|
|
|
|
|
|
|
# |
583
|
|
|
|
|
|
|
# Tests: t/intro.t |
584
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
585
|
|
|
|
|
|
|
sub intro { |
586
|
|
|
|
|
|
|
# No default intro |
587
|
0
|
|
|
0
|
1
|
0
|
return "" |
588
|
|
|
|
|
|
|
} |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
591
|
|
|
|
|
|
|
# outro() |
592
|
|
|
|
|
|
|
# |
593
|
|
|
|
|
|
|
# Similar to intro(), but called from within quit(), immediately |
594
|
|
|
|
|
|
|
# before exit is called. |
595
|
|
|
|
|
|
|
# |
596
|
|
|
|
|
|
|
# Tests: t/outro.t |
597
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
598
|
|
|
|
|
|
|
sub outro { |
599
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
600
|
0
|
|
|
|
|
0
|
return sprintf "Thanks for using %s!", $self->progname; |
601
|
|
|
|
|
|
|
} |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
604
|
|
|
|
|
|
|
# parseline($line) |
605
|
|
|
|
|
|
|
# |
606
|
|
|
|
|
|
|
# parseline splits a line into three components: |
607
|
|
|
|
|
|
|
# |
608
|
|
|
|
|
|
|
# 1. Command |
609
|
|
|
|
|
|
|
# |
610
|
|
|
|
|
|
|
# 2. Environment variable additions |
611
|
|
|
|
|
|
|
# |
612
|
|
|
|
|
|
|
# 3. Arguments |
613
|
|
|
|
|
|
|
# |
614
|
|
|
|
|
|
|
# returns an array that looks like: |
615
|
|
|
|
|
|
|
# |
616
|
|
|
|
|
|
|
# ($cmd, \%env, @args) |
617
|
|
|
|
|
|
|
# |
618
|
|
|
|
|
|
|
# %env comes from environment variable assignments that occur at |
619
|
|
|
|
|
|
|
# the beginning of the line: |
620
|
|
|
|
|
|
|
# |
621
|
|
|
|
|
|
|
# FOO=bar cmd opt1 opt2 |
622
|
|
|
|
|
|
|
# |
623
|
|
|
|
|
|
|
# In this case $env{FOO} = "bar". |
624
|
|
|
|
|
|
|
# |
625
|
|
|
|
|
|
|
# This parseline method doesn't handle pipelines gracefully; pipes |
626
|
|
|
|
|
|
|
# ill treated like any other token. |
627
|
|
|
|
|
|
|
# |
628
|
|
|
|
|
|
|
# Tests: t/parseline.t |
629
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
630
|
|
|
|
|
|
|
sub parseline { |
631
|
5
|
|
|
5
|
1
|
4038
|
my ($self, $line) = @_; |
632
|
5
|
|
|
|
|
5
|
my ($cmd, %env, @args); |
633
|
|
|
|
|
|
|
|
634
|
5
|
|
|
|
|
13
|
@args = shellwords($line); |
635
|
5
|
|
|
|
|
540
|
%env = (); |
636
|
|
|
|
|
|
|
|
637
|
5
|
|
|
|
|
11
|
while (@args) { |
638
|
7
|
100
|
|
|
|
16
|
if ($args[0] =~ /=/) { |
639
|
2
|
|
|
|
|
8
|
my ($n, $v) = split /=/, shift(@args), 2; |
640
|
2
|
|
50
|
|
|
9
|
$env{$n} = $v || ""; |
641
|
|
|
|
|
|
|
} |
642
|
|
|
|
|
|
|
else { |
643
|
5
|
|
|
|
|
5
|
$cmd = shift @args; |
644
|
5
|
|
|
|
|
7
|
last; |
645
|
|
|
|
|
|
|
} |
646
|
|
|
|
|
|
|
} |
647
|
|
|
|
|
|
|
|
648
|
5
|
|
50
|
|
|
27
|
return (($cmd or ""), \%env, @args); |
649
|
|
|
|
|
|
|
} |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
652
|
|
|
|
|
|
|
# Generic accessors |
653
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
656
|
|
|
|
|
|
|
# args([$arg]) |
657
|
|
|
|
|
|
|
# |
658
|
|
|
|
|
|
|
# Returns the hash ref of configuration arguments. If passed a single |
659
|
|
|
|
|
|
|
# value, then that configuration value will be returned. |
660
|
|
|
|
|
|
|
# |
661
|
|
|
|
|
|
|
# Tests: t/args.t |
662
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
663
|
|
|
|
|
|
|
sub args { |
664
|
23
|
|
|
23
|
1
|
6591
|
my $self = shift; |
665
|
23
|
100
|
|
|
|
69
|
if (@_) { |
666
|
|
|
|
|
|
|
return $self->{ ARGS }->{ $_[0] } |
667
|
21
|
|
66
|
|
|
198
|
|| $self->{ ARGS }->{ uc $_[0] }; |
668
|
|
|
|
|
|
|
} |
669
|
2
|
|
|
|
|
32
|
return $self->{ ARGS }; |
670
|
|
|
|
|
|
|
} |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
673
|
|
|
|
|
|
|
# config([$arg]) |
674
|
|
|
|
|
|
|
# |
675
|
|
|
|
|
|
|
# Returns the hash reference of configuration parameters read from |
676
|
|
|
|
|
|
|
# the rc file(s). |
677
|
|
|
|
|
|
|
# |
678
|
|
|
|
|
|
|
# Tests: t/init_rcfiles.t |
679
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
680
|
|
|
|
|
|
|
sub config { |
681
|
10
|
|
|
10
|
1
|
1550
|
my $self = shift; |
682
|
10
|
50
|
|
|
|
25
|
if (@_) { |
683
|
10
|
|
|
|
|
81
|
return $self->{ CONFIG }->{ $_[0] }; |
684
|
|
|
|
|
|
|
} |
685
|
0
|
|
|
|
|
0
|
return $self->{ CONFIG }; |
686
|
|
|
|
|
|
|
} |
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
690
|
|
|
|
|
|
|
# term() |
691
|
|
|
|
|
|
|
# |
692
|
|
|
|
|
|
|
# Returns the Term::ReadLine instance. Useful if the subclass needs |
693
|
|
|
|
|
|
|
# do something like modify attributes on the instance. |
694
|
|
|
|
|
|
|
# |
695
|
|
|
|
|
|
|
# Tests: t/term.t |
696
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
697
|
|
|
|
|
|
|
sub term { |
698
|
17
|
|
|
17
|
1
|
404072
|
my $self = shift; |
699
|
17
|
100
|
|
|
|
605
|
$self->{ TERM } = shift if (@_); |
700
|
17
|
|
|
|
|
348
|
return $self->{ TERM }; |
701
|
|
|
|
|
|
|
} |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
704
|
|
|
|
|
|
|
# histfile([$histfile]) |
705
|
|
|
|
|
|
|
# |
706
|
|
|
|
|
|
|
# Gets/set the history file. |
707
|
|
|
|
|
|
|
# |
708
|
|
|
|
|
|
|
# Tests: t/histfile.t |
709
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
710
|
|
|
|
|
|
|
sub histfile { |
711
|
3
|
|
|
3
|
0
|
14
|
my $self = shift; |
712
|
3
|
50
|
|
|
|
909
|
$self->{ HISTFILE } = shift if (@_); |
713
|
3
|
|
|
|
|
13
|
return $self->{ HISTFILE }; |
714
|
|
|
|
|
|
|
} |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
718
|
|
|
|
|
|
|
# prompt([$prompt[, @args]]) |
719
|
|
|
|
|
|
|
# |
720
|
|
|
|
|
|
|
# The prompt can be modified using this method. For example, multiline |
721
|
|
|
|
|
|
|
# commands (which much be handled by the subclass) might modify the |
722
|
|
|
|
|
|
|
# prompt, e.g., PS1 and PS2 in bash. If $prompt is a coderef, it is |
723
|
|
|
|
|
|
|
# executed with $self and @args: |
724
|
|
|
|
|
|
|
# |
725
|
|
|
|
|
|
|
# $self->{ PROMPT } = &$prompt($self, @args); |
726
|
|
|
|
|
|
|
# |
727
|
|
|
|
|
|
|
# Tests: t/prompt.t |
728
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
729
|
|
|
|
|
|
|
sub prompt { |
730
|
6
|
|
|
6
|
1
|
21
|
my $self = shift; |
731
|
6
|
100
|
|
|
|
25
|
if (@_) { |
732
|
2
|
|
|
|
|
6
|
my $p = shift; |
733
|
2
|
100
|
|
|
|
12
|
if (ref($p) eq 'CODE') { |
734
|
1
|
|
|
|
|
7
|
$self->{ PROMPT } = &$p($self, @_); |
735
|
|
|
|
|
|
|
} |
736
|
|
|
|
|
|
|
else { |
737
|
1
|
|
|
|
|
5
|
$self->{ PROMPT } = $p; |
738
|
|
|
|
|
|
|
} |
739
|
|
|
|
|
|
|
} |
740
|
6
|
|
|
|
|
70
|
return $self->{ PROMPT }; |
741
|
|
|
|
|
|
|
} |
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
744
|
|
|
|
|
|
|
# pager([$pager]) |
745
|
|
|
|
|
|
|
# |
746
|
|
|
|
|
|
|
# It is possible that each time through the loop in run() might need |
747
|
|
|
|
|
|
|
# to be passed through a pager; this method exists to figure out what |
748
|
|
|
|
|
|
|
# that pager should be. |
749
|
|
|
|
|
|
|
# |
750
|
|
|
|
|
|
|
# Tests: t/pager.t |
751
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
752
|
|
|
|
|
|
|
sub pager { |
753
|
4
|
|
|
4
|
1
|
16
|
my $self = shift; |
754
|
|
|
|
|
|
|
|
755
|
4
|
100
|
|
|
|
14
|
if (@_) { |
756
|
1
|
|
|
|
|
2
|
$self->{ PAGER } = shift; |
757
|
|
|
|
|
|
|
} |
758
|
|
|
|
|
|
|
|
759
|
4
|
100
|
|
|
|
92
|
unless (defined $self->{ PAGER }) { |
760
|
3
|
|
100
|
|
|
60
|
$self->{ PAGER } = $PAGER || "less"; |
761
|
3
|
50
|
|
|
|
157
|
$self->{ PAGER } = "more" unless -x $self->{ PAGER }; |
762
|
|
|
|
|
|
|
} |
763
|
|
|
|
|
|
|
|
764
|
4
|
|
|
|
|
45
|
return $self->{ PAGER }; |
765
|
|
|
|
|
|
|
} |
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
769
|
|
|
|
|
|
|
# help([$topic[, @args]]) |
770
|
|
|
|
|
|
|
# |
771
|
|
|
|
|
|
|
# Displays help. With $topic, it attempts to call $self->help_$topic, |
772
|
|
|
|
|
|
|
# which is expected to return a string. Without $topic, it lists the |
773
|
|
|
|
|
|
|
# available help topics, which is a list of methods that begin with |
774
|
|
|
|
|
|
|
# help_; these names are massaged with s/^help_// before being displayed. |
775
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
776
|
|
|
|
|
|
|
sub help { |
777
|
0
|
|
|
0
|
1
|
0
|
my ($self, $topic, @args) = @_; |
778
|
0
|
|
|
|
|
0
|
my @ret; |
779
|
|
|
|
|
|
|
|
780
|
0
|
0
|
|
|
|
0
|
if ($topic) { |
781
|
0
|
0
|
|
|
|
0
|
if (my $sub = $self->can("help_$topic")) { |
782
|
0
|
|
|
|
|
0
|
push @ret, $self->$sub(@_); |
783
|
|
|
|
|
|
|
} |
784
|
|
|
|
|
|
|
else { |
785
|
0
|
|
|
|
|
0
|
push @ret, |
786
|
|
|
|
|
|
|
"Sorry, no help available for `$topic'."; |
787
|
|
|
|
|
|
|
} |
788
|
|
|
|
|
|
|
} |
789
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
else { |
791
|
0
|
|
|
|
|
0
|
my @helps = $self->helps; |
792
|
0
|
0
|
|
|
|
0
|
if (@helps) { |
793
|
0
|
|
|
|
|
0
|
push @ret, |
794
|
|
|
|
|
|
|
"Help is available for the following topics:", |
795
|
|
|
|
|
|
|
"===========================================", |
796
|
0
|
|
|
|
|
0
|
map({ " * $_" } @helps), |
797
|
|
|
|
|
|
|
"==========================================="; |
798
|
|
|
|
|
|
|
} |
799
|
|
|
|
|
|
|
else { |
800
|
0
|
|
|
|
|
0
|
my $me = $self->progname; |
801
|
0
|
|
|
|
|
0
|
push @ret, "No help available for $me.", |
802
|
|
|
|
|
|
|
"Please complain to the author!"; |
803
|
|
|
|
|
|
|
} |
804
|
|
|
|
|
|
|
} |
805
|
|
|
|
|
|
|
|
806
|
0
|
|
|
|
|
0
|
return join "\n", @ret; |
807
|
|
|
|
|
|
|
} |
808
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
811
|
|
|
|
|
|
|
# helps([@helps]) |
812
|
|
|
|
|
|
|
# |
813
|
|
|
|
|
|
|
# Returns or sets a list of possible help functions. |
814
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
815
|
|
|
|
|
|
|
sub helps { |
816
|
16
|
|
|
16
|
1
|
48
|
my $self = shift; |
817
|
|
|
|
|
|
|
|
818
|
16
|
100
|
|
|
|
340
|
if (@_) { |
819
|
14
|
|
|
|
|
76
|
$self->{ HELPS } = \@_; |
820
|
|
|
|
|
|
|
} |
821
|
|
|
|
|
|
|
|
822
|
16
|
|
|
|
|
31
|
return @{ $self->{ HELPS } }; |
|
16
|
|
|
|
|
88
|
|
823
|
|
|
|
|
|
|
} |
824
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
826
|
|
|
|
|
|
|
# complete(@_) |
827
|
|
|
|
|
|
|
# |
828
|
|
|
|
|
|
|
# Command completion -- this method is designed to be assigned as: |
829
|
|
|
|
|
|
|
# |
830
|
|
|
|
|
|
|
# $term->Attribs->{completion_function} = sub { $self->complete(@_) }; |
831
|
|
|
|
|
|
|
# |
832
|
|
|
|
|
|
|
# Note the silly setup -- it will be called as a function, without |
833
|
|
|
|
|
|
|
# any references to $self, so we need to force $self into the equation |
834
|
|
|
|
|
|
|
# using a closure. |
835
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
836
|
|
|
|
|
|
|
sub complete { |
837
|
0
|
|
|
0
|
0
|
0
|
my ($self, $word, $line, $pos) = @_; |
838
|
|
|
|
|
|
|
#warn "Completing '$word' in '$line' (pos $pos)"; |
839
|
|
|
|
|
|
|
|
840
|
|
|
|
|
|
|
# This is grossly suboptimal, and only completes on |
841
|
|
|
|
|
|
|
# defined keywords. A better idea is to: |
842
|
|
|
|
|
|
|
# 1. If subtr($line, ' ') is less than $pos, |
843
|
|
|
|
|
|
|
# then we are completing a command |
844
|
|
|
|
|
|
|
# (the current method does this correctly) |
845
|
|
|
|
|
|
|
# 2. Otherwise, we are completing something else. |
846
|
|
|
|
|
|
|
# By default, this should defer to regular filename |
847
|
|
|
|
|
|
|
# completion. |
848
|
0
|
|
|
|
|
0
|
return grep { /$word/ } $self->completions; |
|
0
|
|
|
|
|
0
|
|
849
|
|
|
|
|
|
|
} |
850
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
sub completions { |
852
|
14
|
|
|
14
|
1
|
50
|
my $self = shift; |
853
|
|
|
|
|
|
|
|
854
|
14
|
100
|
|
|
|
96
|
if (@_) { |
855
|
13
|
|
|
|
|
48
|
$self->{ COMPLETIONS } = \@_; |
856
|
|
|
|
|
|
|
} |
857
|
|
|
|
|
|
|
|
858
|
14
|
|
|
|
|
30
|
return @{ $self->{ COMPLETIONS } }; |
|
14
|
|
|
|
|
289
|
|
859
|
|
|
|
|
|
|
} |
860
|
|
|
|
|
|
|
|
861
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
862
|
|
|
|
|
|
|
# _do_shell |
863
|
|
|
|
|
|
|
# |
864
|
|
|
|
|
|
|
# An example do_shell method. This can be used in subclasses like: |
865
|
|
|
|
|
|
|
# sub do_shell { shift->_do_shell(@_) } |
866
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
867
|
|
|
|
|
|
|
sub _do_shell { |
868
|
0
|
|
|
0
|
|
0
|
my ($self, @args) = @_; |
869
|
0
|
|
0
|
|
|
0
|
my $sh = $SHELL || '/bin/sh'; |
870
|
|
|
|
|
|
|
|
871
|
0
|
0
|
|
|
|
0
|
unless (system($sh, @args) == 0) { |
872
|
0
|
|
|
|
|
0
|
carp "Problem executing $sh: $!"; |
873
|
|
|
|
|
|
|
} |
874
|
|
|
|
|
|
|
|
875
|
|
|
|
|
|
|
# No return value! |
876
|
0
|
|
|
|
|
0
|
return; |
877
|
|
|
|
|
|
|
} |
878
|
|
|
|
|
|
|
|
879
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
880
|
|
|
|
|
|
|
# An example predefined command: warranty. This also, |
881
|
|
|
|
|
|
|
# incidentally, fulfills the GPL recommended requirements. |
882
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
883
|
|
|
|
|
|
|
sub do_warranty { |
884
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
885
|
|
|
|
|
|
|
|
886
|
0
|
|
|
|
|
0
|
require Text::Wrap; |
887
|
|
|
|
|
|
|
# To prevent "used only once" warnings. |
888
|
0
|
|
0
|
|
|
0
|
local $Text::Wrap::columns = |
889
|
|
|
|
|
|
|
$Text::Wrap::columns = $COLUMNS || '72'; |
890
|
|
|
|
|
|
|
|
891
|
0
|
|
|
|
|
0
|
return Text::Wrap::wrap('', '', sprintf |
892
|
|
|
|
|
|
|
'Because %s is licensed free of charge, there is no warranty for the ' . |
893
|
|
|
|
|
|
|
'program, to the extent permitted by applicable law. Except when ' . |
894
|
|
|
|
|
|
|
'otherwise stated in writing the copyright holders and/or other parties ' . |
895
|
|
|
|
|
|
|
'provide the program "as is" without warranty of any kind, either ' . |
896
|
|
|
|
|
|
|
'expressed or implied, including, but not limited to, the implied ' . |
897
|
|
|
|
|
|
|
'warranties of merchantability and fitness for a particular purpose. ' . |
898
|
|
|
|
|
|
|
'The entire risk as to the quality and performance of the program is ' . |
899
|
|
|
|
|
|
|
'with you. Should the program prove defective, you assume the cost of ' . |
900
|
|
|
|
|
|
|
'all necessary servicing, repair or correction.', $self->progname); |
901
|
|
|
|
|
|
|
} |
902
|
|
|
|
|
|
|
|
903
|
|
|
|
|
|
|
# Helper function |
904
|
|
|
|
|
|
|
sub _merge_hash { |
905
|
1
|
|
|
1
|
|
3
|
my ($merge_to, $merge_from) = @_; |
906
|
|
|
|
|
|
|
$merge_to->{$_} = $merge_from->{$_} |
907
|
1
|
|
|
|
|
21
|
for keys %$merge_from; |
908
|
|
|
|
|
|
|
} |
909
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
__END__ |