[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} ? '** ' : ''; |