#! /usr/local/bin/perl
use
vars
qw($PS1 $PS2 $HISTFILE $HISTSIZE $INPUTRC $STRICT
$HOSTNAME $LOGNAME $CWP)
;
$PS1
=
'\w[\!]$ '
;
$PS2
=
'> '
;
$HISTFILE
= (
$ENV
{HOME} || ((
getpwuid
($<))[7])) .
"/.perlsh_history"
;
$HISTSIZE
= 256;
$INPUTRC
= (
$ENV
{HOME} || ((
getpwuid
($<))[7])) .
"/.perlshrc"
;
$STRICT
= 0;
$HOSTNAME
=
$ENV
{HOSTNAME};
$LOGNAME
=
$ENV
{LOGNAME};
$CWP
=
'main'
;
if
(-f
$PerlSh::INPUTRC
) {
do
$PerlSh::INPUTRC
;
}
use
vars
qw($term $attribs)
;
$term
= new Term::ReadLine
'PerlSh'
;
$attribs
=
$term
->Attribs;
$term
->bind_key(
ord
"^"
,
'history-expand-line'
,
'emacs-meta'
);
$term
->bind_key(
ord
"\cv"
,
'display-readline-version'
,
'emacs-ctlx'
);
$term
->bind_key(
ord
"\cc"
,
'abort'
);
if
(
defined
&main::afterinit
) {
&afterinit
;
}
&toplevel
;
sub
toplevel {
$term
->MinLine(
undef
);
$term
->stifle_history(
$HISTSIZE
);
if
(-f
$HISTFILE
) {
$term
->ReadHistory(
$HISTFILE
)
or
warn
"perlsh: cannot read history file: $!\n"
;
}
$attribs
->{attempted_completion_function} = \
&attempt_perl_completion
;
$attribs
->{special_prefixes} =
'$@%&'
;
$attribs
->{completion_display_matches_hook}
= \
&perl_symbol_display_match_list
;
sigaction SIGINT, new POSIX::SigAction
sub
{
$term
->modifying;
$term
->delete_text;
$attribs
->{point} =
$attribs
->{end} = 0;
$term
->redisplay;
} or
die
"Error setting SIGINT handler: $!\n"
;
my
(
$strict
,
$command
,
@result
);
$strict
=
$STRICT
?
''
:
'no strict;'
;
while
(
defined
(
$command
=
&reader
)) {
@result
=
eval
(
"$strict package $CWP; $command"
);
if
($@) {
print
"Error: $@\n"
;
next
; }
printer (
@result
);
$CWP
= $1
if
(
$command
=~ /^\s
*package
\s+([\w:]+)/);
}
&quit
;
}
sub
sigint {
$term
->modifying;
$term
->delete_text;
$attribs
->{point} =
$attribs
->{end} = 0;
$term
->redisplay;
}
sub
quit {
$term
->WriteHistory(
$HISTFILE
)
or
warn
"perlsh: cannot write history file: $!\n"
;
exit
(0);
}
sub
reader {
my
(
$line
,
$command
);
$command
=
''
;
while
(1) {
$line
=
$term
->
readline
(
$command
?
$PS2
: prompt(
$PS1
));
return
undef
unless
(
defined
$line
);
if
(
$line
=~ /\\$/) {
chop
$line
;
$command
=
$command
?
$command
.
" $line"
:
$line
;
}
else
{
$command
=
$command
?
$command
.
" $line"
:
$line
;
$term
->addhistory(
$command
)
if
(
length
(
$command
) > 0);
return
$command
;
}
}
}
sub
printer {
my
(
@res
) =
@_
;
my
(
$i
);
foreach
$i
(
@res
) {
print
"$i\n"
; }
}
sub
prompt {
local
(
$_
) =
@_
;
return
&$_
if
(
ref
(
$_
) eq
'CODE'
);
s/\\h/
$HOSTNAME
/g;
s/\\u/
$LOGNAME
/g;
s/\\w/
$CWP
/g;
s/\\!/
$attribs
->{history_base} +
$attribs
->{history_length}/eg;
$_
;
}
sub
perl_symbol_display_match_list ($$$) {
my
(
$matches
,
$num_matches
,
$max_length
) =
@_
;
map
{
$_
=~ s/^((\$
$term
->display_match_list(
$matches
);
$term
->forced_update_display;
}
sub
attempt_perl_completion ($$$$) {
my
(
$text
,
$line
,
$start
,
$end
) =
@_
;
no
strict
qw(refs)
;
if
(
substr
(
$line
, 0,
$start
) =~ m/\$([\w:]+)\s*(->)?\s*{\s*['"]?$/) {
$attribs
->{completion_append_character} =
'}'
;
return
$term
->completion_matches(
$text
,
\
&perl_hash_key_completion_function
);
}
elsif
(
substr
(
$line
, 0,
$start
) =~ m/\$([\w:]+)\s*->\s*['"]?$/) {
$attribs
->{completion_append_character} =
' '
;
return
$term
->completion_matches(
$text
,
\
&perl_method_completion_function
);
}
else
{
$attribs
->{completion_append_character} =
''
;
return
$term
->completion_matches(
$text
,
\
&perl_symbol_completion_function
);
}
}
use
vars
qw($i @matches)
;
sub
perl_hash_key_completion_function ($$) {
my
(
$text
,
$state
) =
@_
;
if
(
$state
) {
$i
++;
}
else
{
$i
= 0;
my
(
$var
,
$arrow
) = (
substr
(
$attribs
->{line_buffer},
0,
$attribs
->{point} -
length
(
$text
))
=~ m/\$([\w:]+)\s*(->)?\s*{\s*['"]?$/);
no
strict
qw(refs)
;
$var
=
"${CWP}::$var"
unless
(
$var
=~ m/::/);
if
(
$arrow
) {
my
$hashref
=
eval
"\$$var"
;
@matches
=
keys
%$hashref
;
}
else
{
@matches
=
keys
%$var
;
}
}
for
(;
$i
<=
$#matches
;
$i
++) {
return
$matches
[
$i
]
if
(
$matches
[
$i
] =~ /^\Q
$text
/);
}
return
undef
;
}
sub
_search_ISA ($) {
my
(
$mypkg
) =
@_
;
no
strict
'refs'
;
no
warnings
'prototype'
;
my
$isa
=
"${mypkg}::ISA"
;
return
$mypkg
,
map
_search_ISA(
$_
),
@$isa
;
}
sub
perl_method_completion_function ($$) {
my
(
$text
,
$state
) =
@_
;
if
(
$state
) {
$i
++;
}
else
{
my
(
$var
,
$pkg
,
$sym
,
$pk
);
$i
= 0;
$var
= (
substr
(
$attribs
->{line_buffer},
0,
$attribs
->{point} -
length
(
$text
))
=~ m/\$([\w:]+)\s*->\s*$/)[0];
$pkg
=
ref
eval
((
$var
=~ m/::/) ?
"\$$var"
:
"\$${CWP}::$var"
);
no
strict
qw(refs)
;
@matches
=
map
{
$pk
=
$_
.
'::'
;
grep
(/^\w+$/
&& (
$sym
=
"${pk}$_"
,
defined
*$sym
{CODE}),
keys
%$pk
);
} _search_ISA(
$pkg
);
}
for
(;
$i
<=
$#matches
;
$i
++) {
return
$matches
[
$i
]
if
(
$matches
[
$i
] =~ /^\Q
$text
/);
}
return
undef
;
}
{
my
(
$prefix
,
%type
,
@keyword
);
sub
perl_symbol_completion_function ($$) {
my
(
$text
,
$state
) =
@_
;
if
(
$state
) {
$i
++;
}
else
{
my
(
$pre
,
$pkg
,
$sym
);
$i
= 0;
no
strict
qw(refs)
;
(
$prefix
,
$pre
,
$pkg
) = (
$text
=~ m/^((\$
@matches
=
grep
/::$/,
$pkg
?
keys
%$pkg
:
keys
%::;
$pkg
= (
$CWP
eq
'main'
?
'::'
:
$CWP
.
'::'
)
unless
$pkg
;
if
(
$pre
) {
@matches
= (
@matches
,
grep
(/^\w+$/
&& (
$sym
=
$pkg
.
$_
,
defined
*$sym
{
$type
{
$pre
}}),
keys
%$pkg
));
}
else
{
@matches
= (
@matches
,
!
$prefix
&&
@keyword
,
grep
(/^\w+$/
&& (
$sym
=
$pkg
.
$_
,
defined
*$sym
{CODE} ||
defined
*$sym
{IO}
),
keys
%$pkg
));
}
}
my
$entry
;
for
(;
$i
<=
$#matches
;
$i
++) {
$entry
=
$prefix
.
$matches
[
$i
];
return
$entry
if
(
$entry
=~ /^\Q
$text
/);
}
return
undef
;
}
BEGIN {
%type
= (
'$'
=>
'SCALAR'
,
'*'
=>
'SCALAR'
,
'@'
=>
'ARRAY'
,
'$#'
=>
'ARRAY'
,
'%'
=>
'HASH'
,
'&'
=>
'CODE'
);
@keyword
=
qw(
chomp chop chr crypt hex index lc lcfirst
length oct ord pack q qq
reverse rindex sprintf substr tr uc ucfirst
y
m pos quotemeta s split study qr
abs atan2 cos exp hex int log oct rand sin
sqrt srand
pop push shift splice unshift
grep join map qw reverse sort unpack
delete each exists keys values
binmode close closedir dbmclose dbmopen die
eof fileno flock format getc print printf
read readdir rewinddir seek seekdir select
syscall sysread sysseek syswrite tell telldir
truncate warn write
pack read syscall sysread syswrite unpack vec
chdir chmod chown chroot fcntl glob ioctl
link lstat mkdir open opendir readlink rename
rmdir stat symlink umask unlink utime
caller continue die do dump eval exit goto
last next redo return sub wantarray
caller import local my package use
defined dump eval formline local my reset
scalar undef wantarray
alarm exec fork getpgrp getppid getpriority
kill pipe qx setpgrp setpriority sleep
system times wait waitpid
do import no package require use
bless dbmclose dbmopen package ref tie tied
untie use
accept bind connect getpeername getsockname
getsockopt listen recv send setsockopt shutdown
socket socketpair
msgctl msgget msgrcv msgsnd semctl semget
semop shmctl shmget shmread shmwrite
endgrent endhostent endnetent endpwent getgrent
getgrgid getgrnam getlogin getpwent getpwnam
getpwuid setgrent setpwent
endprotoent endservent gethostbyaddr
gethostbyname gethostent getnetbyaddr
getnetbyname getnetent getprotobyname
getprotobynumber getprotoent getservbyname
getservbyport getservent sethostent setnetent
setprotoent setservent
gmtime localtime time times
abs bless chomp chr exists formline glob
import lc lcfirst map my no prototype qx qw
readline readpipe ref sub sysopen tie tied
uc ucfirst untie use
dbmclose dbmopen
)
;
}
}