[LDAPsh-cvs] ldapsh ldapsh,1.36,1.37
Status: Beta
Brought to you by:
rcorvalan
|
From: <j-d...@us...> - 2003-12-14 08:50:22
|
Update of /cvsroot/ldapsh/ldapsh
In directory sc8-pr-cvs1:/tmp/cvs-serv25614
Modified Files:
ldapsh
Log Message:
* Added warnings/errors when 'redir' command fails.
* Added a primitive 'history' command to view Term::ReadLine::Gnu command history.
* Added Psh support:
- Documented Psh command-line syntax (dual documentation of ldapsh and Psh syntaxes).
- Added dynamic check for availability of Psh module.
- Replaced Perl -w option with $^W=1 to suppress warnings when Psh is in use.
- Change some 'my' to 'our' so that $ENTRIES is available to Psh Perl evaluation.
- Added variables $PSH_SUPPORT and $LDAPSH_PARSER to indicate whether Psh is in use.
- Provided Psh::Strategy::Ldapsh::Perlfunc and Psh::Strategy hooks.
- Modified main loop to use Psh, when it is available.
Index: ldapsh
===================================================================
RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v
retrieving revision 1.36
retrieving revision 1.37
diff -C2 -d -r1.36 -r1.37
*** ldapsh 14 Dec 2003 02:51:59 -0000 1.36
--- ldapsh 14 Dec 2003 04:15:36 -0000 1.37
***************
*** 1,3 ****
! #!/usr/bin/perl -w
# vim:ts=4:sw=4:noet:ai:
--- 1,3 ----
! #!/usr/bin/perl
# vim:ts=4:sw=4:noet:ai:
***************
*** 88,92 ****
of Perl functions and all you do is to call functions from a prompt.
! In fact, whatever you type at the prompt will either be:
=over 8
--- 88,107 ----
of Perl functions and all you do is to call functions from a prompt.
! You can request help typing L<help [E<lt>commandE<gt>]|help> or, if you use
! B<Term::ReadLine::Gnu>, you can type C<E<lt>CTRL-tE<gt>> after a command
! to get help on it.
!
! B<ldapsh> includes a simple command-line interpreter. It can also make use of
! the optional B<Psh> module for an enhanced user experience. This manual
! describes both interpreters as indicated by [ldapsh] and [Psh], respectively. Both
! interpreters facilitate evaluation of Perl expressions and you may use the
! L<$G|"$G"> variable to store your own data.
!
! In this manual, command options are shown as C<'-l',> to be compatible with the
! Perl C<eval()> function. However, you do not usually need to type the
! apostrophes because B<ldapsh> will insert them automatically. If you have
! B<Psh> installed, you do not need to use commas, either.
!
! [ldapsh] Whatever you type at the prompt will either be:
=over 8
***************
*** 96,111 ****
=item * Evaluated as a Perl expression (using C<eval()>).
For convenience, a few commands (such as L<cd|cd>, L<lcd|lcd> and L<help|help>)
automatically quote their arguments. Thus, you can type C<cd ou=Users>
instead of C<cd "ou=Users">.
- You may use the L<$G|"$G"> variable to store values such as your results.
! =back
! You can request help typing L<help [E<lt>commandE<gt>]|help> or, if you use
! B<Term::ReadLine::Gnu>, you can type C<E<lt>CTRL-tE<gt>> after a command
! to get help on it.
! =head2 Expansion
Almost every function that uses LDAP entries (L<ls|ls>, L<cat|cat>,
--- 111,153 ----
=item * Evaluated as a Perl expression (using C<eval()>).
+ =back
+
For convenience, a few commands (such as L<cd|cd>, L<lcd|lcd> and L<help|help>)
automatically quote their arguments. Thus, you can type C<cd ou=Users>
instead of C<cd "ou=Users">.
! [Psh] What you type at the prompt will be passed through a number of handlers
! that facilitate a rich shell-like syntax. The order of precedence is:
! exclamation mark, brace, B<ldapsh> commands, Perl functions, shell executables,
! Perl evaluation. Please note the following examples for correct quoting of
! strings, arrays, and hashes:
! =over 8
! =item * Correct (expands L<$CWD|"$CWD">): echo $CWD
!
! =item * Correct (expands L<$CWD|"$CWD">): echo "$CWD"
!
! =item * Prints C<$CWD> literally: echo '$CWD'
!
! =item * Correct (expands L<$ENTRIES|"$ENTRIES">): ls $ENTRIES
!
! =item * Correct (expands L<$ENTRIES|"$ENTRIES">): nbentries $ENTRIES
!
! =item * Incorrect (converts array reference to a string): nbentries "$ENTRIES"
!
! =item * Incorrect (does not expand the variable): nbentries '$ENTRIES'
!
! =item * Expands $ENV{PATH}: echo "$ENV{PATH}"
!
! =item * Expands $ENV{PATH}: echo $ENV\{PATH\}
!
! =item * $ENV expanded on its own: echo $ENV{PATH}
!
! =item * Prints C<$ENV{PATH}> literally: echo '$ENV{PATH}'
!
! =back
!
! =head2 Expansion of LDAP DNs and Filters
Almost every function that uses LDAP entries (L<ls|ls>, L<cat|cat>,
***************
*** 113,119 ****
identified in the documentation with a usage like: C<ls E<lt>expansionE<gt>>
- I tried -- even if it's by far incomplete -- to simulate the mechanism of the
- shell parser and its variable substitution, wildcard expansion, etc.
-
The three syntaxes are:
--- 155,158 ----
***************
*** 126,130 ****
is the I<current working directory>.
! The results of the search are put in the L<$ENTRIES|"$ENTRIES"> array ref
(composed of B<Net::LDAP::Entry> entries).
--- 165,169 ----
is the I<current working directory>.
! The results of the search are put in the L<$ENTRIES|"$ENTRIES"> array reference
(composed of B<Net::LDAP::Entry> entries).
***************
*** 151,157 ****
You may redirect search results using the L<redir|redir> command. This will
! stay in effect until L<noredir> is called.
! Alternatively, you can use a special shell syntax which will have only a
temporary effect. The special syntax is appending "; | ..." to your command,
where "..." is a parameter to the C<open> function.
--- 190,199 ----
You may redirect search results using the L<redir|redir> command. This will
! stay in effect until L<noredir|noredir> is called.
! [Psh] Psh allows you to use standard shell symbols such as "|" (for piping)
! and ">" (for output redirection).
!
! [ldapsh] Alternatively, you can use a special shell syntax which will have only a
temporary effect. The special syntax is appending "; | ..." to your command,
where "..." is a parameter to the C<open> function.
***************
*** 206,213 ****
--- 248,259 ----
=item * B<POSIX::Termios>
+ =item * B<Psh>
+
=item * B<Term::ReadKey>
=item * B<Term::ReadLine::Gnu>
+ =item * B<Term::Size>
+
=back
***************
*** 222,225 ****
--- 268,273 ----
use subs qw(bind connect delete dump exit mkdir rename reset);
+ my $PSH_SUPPORT;
+
BEGIN {
require Net::LDAP;
***************
*** 230,236 ****
Getopt::Long::Configure ('bundling_override');
}
! my $RELEASE = '0.9.3-2';
my $Opts = {
--- 278,297 ----
Getopt::Long::Configure ('bundling_override');
+
+ if ($ENV{LDAPSH_PARSER}) {
+ $PSH_SUPPORT = $ENV{LDAPSH_PARSER} eq "Psh" && eval "require Psh";
+ }
+ else {
+ $PSH_SUPPORT = eval "require Psh";
+ }
+
+ if (!$PSH_SUPPORT) {
+ #use warnings;
+ $^W = 1;
+ # leave warnings off when psh is in use
+ }
}
! our $RELEASE = '0.9.3-2';
my $Opts = {
***************
*** 264,267 ****
--- 325,329 ----
EDITOR => {VALUE => $ENV{VISUAL} ? $ENV{VISUAL} : ($ENV{EDITOR} ? $ENV{EDITOR} : 'vi'), RIGHTS => 'RWL'},
G => {VALUE => undef, RIGHTS => 'RWL'},
+ LDAPSH_PARSER => {VALUE => $PSH_SUPPORT ? "Psh" : "ldapsh", RIGHTS => 'RL'},
_APPENDRESULTS => {VALUE => 0, RIGHTS => ''},
_DIRSSTACK => {VALUE => [], RIGHTS => ''},
***************
*** 283,288 ****
};
! my ($CWD, $OLDWD, $PROMPT, $CONNPARAMS, $LDAPCONN, $ENTRIES, $EDITOR, $COLUMNS, $DNSEP, $G);
! my ($PERL_RL); # read-only values
my ($Term, $TermAttribs);
--- 345,350 ----
};
! our ($COLUMNS, $CONNPARAMS, $CWD, $DNSEP, $EDITOR, $ENTRIES, $G, $LDAPCONN, $OLDWD, $PROMPT);
! our ($LDAPSH_PARSER, $PERL_RL); # read-only values
my ($Term, $TermAttribs);
***************
*** 303,306 ****
--- 365,372 ----
$SIG{INT} = 'IGNORE';
$SIG{__DIE__} = \&_resetTermReadline;
+
+ if ($PSH_SUPPORT) {
+ eval('Psh::minimal_initialize(); Psh::finish_initialize(); $Psh::eval_preamble = "package ldapsh;"; $Psh::PerlEval::current_package = "ldapsh";');
+ }
}
***************
*** 680,683 ****
--- 746,763 ----
}
+ sub _escape {
+ #return Psh::OS::_escape(shift);
+ my $text = shift;
+ $text =~ s/(?<!\\)([ ])/\\$1/g;
+ return $text;
+ }
+
+ sub _unescape {
+ #return Psh::Parser::remove_backslash(shift);
+ my $text = shift;
+ $text =~ s/\\([ ])/$1/g;
+ return $text;
+ }
+
sub _attributeNamesDNCompletion($$$) {
my ($prefix, $partToComplete, $BaseDN) = @_;
***************
*** 747,750 ****
--- 827,833 ----
$common = "${prefix},${common}";
}
+ if ($PSH_SUPPORT && scalar(@possible_entries) == 1) {
+ $possible_entries[0] = _escape($possible_entries[0]);
+ }
return $common, @possible_entries;
}
***************
*** 778,781 ****
--- 861,867 ----
return undef unless scalar(@possible_entries);
# TODO find longest common prefix
+ if ($PSH_SUPPORT && scalar(@possible_entries) == 1) {
+ $possible_entries[0] = _escape($possible_entries[0]);
+ }
return $text, @possible_entries;
} else {
***************
*** 807,811 ****
_bindneeded() or return undef;
! $TermAttribs->{completion_append_character} = '\0';
# match the 'filtertype' portion of an LDAP filter (RFC 2254 and RFC 2251)
--- 893,897 ----
_bindneeded() or return undef;
! $TermAttribs->{completion_append_character} = "\0";
# match the 'filtertype' portion of an LDAP filter (RFC 2254 and RFC 2251)
***************
*** 834,837 ****
--- 920,926 ----
my @possible_entries = map {$prefix.$attr.$extra.scalar($_->get_value($attr))} @entries; # Bug: only uses first attribute value.
my $common = _maxCommon(@possible_entries);
+ if ($PSH_SUPPORT && scalar(@possible_entries) == 1) {
+ $possible_entries[0] = _escape($possible_entries[0]);
+ }
return $common, @possible_entries;
}
***************
*** 1232,1235 ****
--- 1321,1338 ----
+ =head3 history
+
+ B<Synopsis>: C<history>
+
+ Print out each line of the command-line history, if B<Term::ReadLine::Gnu> is available.
+
+ =cut
+ sub history {
+ if (_isGnuReadLine) {
+ print {$Output->{FILEHANDLE}} join("\n", $Term->GetHistory()) . "\n";
+ }
+ }
+
+
=head3 reset
***************
*** 1547,1551 ****
B<Synopsis>: C<search E<lt>expansionE<gt>>
! Search for the entries matched by the expansion (see L<Expansion|expansion>).
Does not dump the entries themselves, only a summary of the search results.
--- 1650,1654 ----
B<Synopsis>: C<search E<lt>expansionE<gt>>
! Search for the entries matched by the expansion (see L<Expansion|"Expansion of LDAP DNs and Filters">).
Does not dump the entries themselves, only a summary of the search results.
***************
*** 1574,1578 ****
B<Synopsis>: C<ldif E<lt>expansionE<gt>>
! Display the entries matched by the expansion (see L<Expansion|expansion>) using the LDIF format.
See also L<cat|cat>.
--- 1677,1681 ----
B<Synopsis>: C<ldif E<lt>expansionE<gt>>
! Display the entries matched by the expansion (see L<Expansion|"Expansion of LDAP DNs and Filters">) using the LDIF format.
See also L<cat|cat>.
***************
*** 1608,1612 ****
B<Synopsis>: C<dump E<lt>expansionE<gt>>
! Dump the entries matched by the expansion (see L<Expansion|expansion>) in a relatively human-readable format.
=cut
--- 1711,1715 ----
B<Synopsis>: C<dump E<lt>expansionE<gt>>
! Dump the entries matched by the expansion (see L<Expansion|"Expansion of LDAP DNs and Filters">) in a relatively human-readable format.
=cut
***************
*** 1625,1629 ****
B<Synopsis>: C<list ['-a',] ['-dn',] E<lt>expansionE<gt>>
! Display the attribute values of the entries matched by the expansion (see L<Expansion|expansion>) in a list format (easy to parse).
Arguments:
--- 1728,1732 ----
B<Synopsis>: C<list ['-a',] ['-dn',] E<lt>expansionE<gt>>
! Display the attribute values of the entries matched by the expansion (see L<Expansion|"Expansion of LDAP DNs and Filters">) in a list format (easy to parse).
Arguments:
***************
*** 1665,1669 ****
B<Synopsis>: C<csv [E<lt>optionsE<gt>,] E<lt>expansionE<gt>>
! Display the entries matched by the expansion (see L<Expansion|expansion>) in a CSV format.
The first argument can be a list of options to tell how to format the file. If it's given, it's a hash reference.
--- 1768,1772 ----
B<Synopsis>: C<csv [E<lt>optionsE<gt>,] E<lt>expansionE<gt>>
! Display the entries matched by the expansion (see L<Expansion|"Expansion of LDAP DNs and Filters">) in a CSV format.
The first argument can be a list of options to tell how to format the file. If it's given, it's a hash reference.
***************
*** 1723,1727 ****
B<Synopsis>: C<ls ['-C',|'-m',] ['-l',] E<lt>expansionE<gt>>
! List the DNs of the entries matched by the expansion (see L<Expansion|expansion>).
Entries are displayed in the order received (no sorting is performed),
with one entry per line.
--- 1826,1830 ----
B<Synopsis>: C<ls ['-C',|'-m',] ['-l',] E<lt>expansionE<gt>>
! List the DNs of the entries matched by the expansion (see L<Expansion|"Expansion of LDAP DNs and Filters">).
Entries are displayed in the order received (no sorting is performed),
with one entry per line.
***************
*** 1826,1830 ****
};
! open $new->{FILEHANDLE}, $out || return $previous;
$Output = $new;
--- 1929,1939 ----
};
! if (open($new->{FILEHANDLE}, $out)) {
! print STDERR "Warning: redirection destination did not start with | or >\n" unless $out =~ /^[|>]/;
! }
! else {
! print STDERR "Error: could not change redirection.\n";
! return $previous;
! }
$Output = $new;
***************
*** 2092,2096 ****
command will prompt you prior to starting and will stop if an error is
encountered. You may specify C<-r>, too, as a normal part of expansion (see
! L<Expansion|expansion>). If C<-a> is specified, an attempt will be made to
delete leaf entries before their parent entries. Thus, to delete an entire
subtree, you might try this:
--- 2201,2205 ----
command will prompt you prior to starting and will stop if an error is
encountered. You may specify C<-r>, too, as a normal part of expansion (see
! L<Expansion|"Expansion of LDAP DNs and Filters">). If C<-a> is specified, an attempt will be made to
delete leaf entries before their parent entries. Thus, to delete an entire
subtree, you might try this:
***************
*** 2156,2160 ****
C<from-expansion> will be expanded in the usual way
! (see L<Expansion|expansion>), with the addition that C<*> corresponds to
the filter C<(objectclass=*)>.
--- 2265,2269 ----
C<from-expansion> will be expanded in the usual way
! (see L<Expansion|"Expansion of LDAP DNs and Filters">), with the addition that C<*> corresponds to
the filter C<(objectclass=*)>.
***************
*** 2222,2226 ****
C<from-expansion> will be expanded in the usual way
! (see L<Expansion|expansion>), with the addition that C<*> corresponds to
the filter C<(objectclass=*)>.
--- 2331,2335 ----
C<from-expansion> will be expanded in the usual way
! (see L<Expansion|"Expansion of LDAP DNs and Filters">), with the addition that C<*> corresponds to
the filter C<(objectclass=*)>.
***************
*** 2290,2294 ****
B<Synopsis>: C<vi E<lt>expansionE<gt>>
! Show the entries matched by the expansion (see L<Expansion|expansion>) in a text editor.
Entries are saved to a temporary file for editing in the LDIF format.
If the temporary file is modified, it will be re-read as an LDIF file and used to modify
--- 2399,2403 ----
B<Synopsis>: C<vi E<lt>expansionE<gt>>
! Show the entries matched by the expansion (see L<Expansion|"Expansion of LDAP DNs and Filters">) in a text editor.
Entries are saved to a temporary file for editing in the LDIF format.
If the temporary file is modified, it will be re-read as an LDIF file and used to modify
***************
*** 2521,2525 ****
B<Synopsis>: C<changes [$entries]>
! Show the changes done to the entries given in the C<$entries> array ref (or L<$ENTRIES|"$ENTRIES">, if omitted). You can apply some changes to a set of entries using the L<apply|apply> command, and see the changes using the L<changes|changes> command.
=cut
--- 2630,2634 ----
B<Synopsis>: C<changes [$entries]>
! Show the changes done to the entries given in the C<$entries> array reference (or L<$ENTRIES|"$ENTRIES">, if omitted). You can apply some changes to a set of entries using the L<apply|apply> command, and see the changes using the L<changes|changes> command.
=cut
***************
*** 2779,2783 ****
=head2 $ENTRIES
! The buffer of entries (B<Net::LDAP::Entry>). It's an array ref. Contains the last entries got with the
commands L<ls|ls>, L<cat|cat>, L<search|search>...
--- 2888,2892 ----
=head2 $ENTRIES
! The buffer of entries (B<Net::LDAP::Entry>). It's an array reference. Contains the last entries got with the
commands L<ls|ls>, L<cat|cat>, L<search|search>...
***************
*** 2894,2903 ****
! package ldapsh;
! _Init();
$_ = "@ARGV";
--- 3003,3094 ----
+ package ldapsh;
+ _Init();
+ if ($PSH_SUPPORT) {
+ package Psh::Strategy::Ldapsh::Perlfunc;
! use strict;
! use vars qw(@ISA);
! require Psh::Strategy::Perlfunc;
! @ISA=('Psh::Strategy::Perlfunc');
!
! sub applies {
! my @words= @{$_[2]};
! if ((Psh::PerlEval::protected_eval("defined(&{'ldapsh::$words[0]'})"))[0]) {
! @{$_[2]}[0] = "ldapsh::@{$_[2]}[0]";
! }
! else {
! return Psh::Strategy::Perlfunc::applies($_);
! }
!
! }
!
! sub variable_expansion {
! # Adapted from Gregor N. Purdy's Psh::PerlEval.pm
! my ($arref) = @_;
! my @retval = ();
! my $word;
!
! for $word (@{$arref}) {
! if ($word =~ /^\'(.*)\'/) {
! push @retval, $1;
! }
! else {
! no strict qw(vars);
! local $SIG{__WARN__} = sub {};
!
! my $expr = $word;
! $expr = "\"$expr\"" unless $expr =~ /^[\$"\']/;
! $expr =~ s/\\/\\\\/g;
!
! my $val = eval(eval('$Psh::eval_preamble')." $expr");
! if ($@) {
! if ($word =~ /^\"(.*)\"/) {
! push @retval, $1;
! }
! else {
! push @retval, $word;
! }
! }
! else {
! push @retval, $val;
! }
! }
! }
! return @retval;
! }
!
! sub execute {
! my @words= @{$_[2]};
! if ($words[0] =~ "^ldapsh::") {
! # Adapted from Gregor N. Purdy's Psh::Strategy::Built_in.pm
! no strict 'refs';
! my $coderef = *{$words[0]};
! shift @words;
! # Should we be using protected_eval?
! @words = variable_expansion(\@words);
! return (1,sub { &{$coderef}(@words); }, [], 0, undef );
! }
! else {
! return Psh::Strategy::Perlfunc::execute($_);
! }
! }
!
! package Psh::Strategy;
!
! remove("built_in");
! #remove("executable");
! #remove("eval");
! remove("perl");
! remove("perlfunc");
!
! my $obj = Psh::Strategy::Ldapsh::Perlfunc->new();
! add $obj;
! }
!
! package ldapsh;
$_ = "@ARGV";
***************
*** 2908,2911 ****
--- 3099,3108 ----
while (1) {
last unless defined($_);
+
+ if ($PSH_SUPPORT) {
+ Psh::_evl(eval {Psh::Parser::parse_line($_) }) if $_;
+ }
+ else {
+
s/^\s+//;
s/\s+$//;
***************
*** 2938,2942 ****
# temporary filehandle
$Output = $previous if ($previous);
!
my $APP = $Globals->{_APPENDRESULTS}{VALUE} ? '** ' : '';
--- 3135,3139 ----
# temporary filehandle
$Output = $previous if ($previous);
! }
my $APP = $Globals->{_APPENDRESULTS}{VALUE} ? '** ' : '';
|