diff options
-rw-r--r-- | etc/bash_completion.d/vyatta-op | 4 | ||||
-rwxr-xr-x | scripts/ping | 110 | ||||
-rw-r--r-- | templates/ping/node.tag/node.tag/node.def | 2 |
3 files changed, 104 insertions, 12 deletions
diff --git a/etc/bash_completion.d/vyatta-op b/etc/bash_completion.d/vyatta-op index 65dd701..22eea12 100644 --- a/etc/bash_completion.d/vyatta-op +++ b/etc/bash_completion.d/vyatta-op @@ -150,6 +150,10 @@ _vyatta_op_help () [ -f $ndef ] && \ node_run=$( _vyatta_op_get_node_def_field $ndef run ) + if [[ "$1" == "<nocomps>" ]]; then + eval "$restore_shopts" + return + fi echo -en "\nPossible completions:" if [ -z "$cur" -a -n "$node_run" ]; then _vyatta_op_print_help '<Enter>' "Execute the current command" diff --git a/scripts/ping b/scripts/ping index 0f9b241..0f85e8f 100755 --- a/scripts/ping +++ b/scripts/ping @@ -43,19 +43,44 @@ use feature ":5.10"; sub get_options { my ($opt, $args) = @_; + my $orig_arg = $$args[-1]; + + # expand the variables + if (scalar(@$args) > 2){ + $args = expand_args($opt, $args); + } + my $prev = $$args[-2]; my $arg = $$args[-1]; - # print type text for arguments - if ( exists($opt->{$arg}) && $opt->{$arg}->{type} ne "noarg" ){ - get_args($opt, $arg); + + # do something similar to compgen + my $options = ''; + if ($arg ne ''){ + my @matches = grep { /^$arg/ } keys(%{$opt}); + if (scalar(@matches) == 0){ + if ( (exists($opt->{$prev}) && $opt->{$prev}->{type} ne "noarg") ) { + get_args($opt, $prev); + } + } + $options = join " ", @matches; + print $options; + exit 0; } + + if ( (exists($opt->{$prev}) && $opt->{$prev}->{type} ne "noarg") ) { + get_args($opt, $prev); + } + # only show options that we haven't used yet - my $options = ''; foreach my $key (keys(%{$opt})){ - next if (grep $_ eq $key, @{$args}); + next if (grep $_ eq $key, @{$args}) ; $options .= "$key "; } - print $options; + if ($options eq '' ){ + print '<Enter>'; + } else { + print $options; + } exit 0; } @@ -65,6 +90,66 @@ sub get_args { exit 0; } +sub expand_args { + my ($opt, $args) = @_; + my @expand_args = (); + my $index = 0; + my $prev = undef; + foreach my $arg (@$args){ + $index++; + if ($index == 1 || $index == 2) { + push @expand_args, $arg; + next; + } + if ( $arg eq '' ){ + push @expand_args, $arg; + next; + } + if ( (exists($opt->{$arg}) && $opt->{$arg}->{type} ne "noarg") ) { + push @expand_args, $arg; + $prev = $arg; + next; + } + my ($err, @vals) = expand_arg($opt, $arg, $prev); + if (defined($err)) { + my $val = pop @$args; + pop @$args if ($val eq ''); + if ( $err eq "ambiguous" ){ + print STDERR "\n\n Ambiguous command: @{$args} [$arg]\n\n"; + print STDERR " Possible completions:\n"; + print STDERR " $_\n" foreach @vals; + print '<nocomps>'; + } else { + print STDERR "\n\n Invalid command: @{$args} [$arg]\n"; + print '<nocomps>'; + } + exit 1; + } + # print type text for arguments + $arg = $vals[0]; + push @expand_args, $arg; + $prev = $arg; + } + return \@expand_args; +} + +sub expand_arg { + my ($opt, $arg, $prev) = @_; + my @opts = grep { /^$arg/ } keys(%{$opt}); + my @prevs = grep { /^$prev/} keys(%{$opt}) if defined($prev); + if (scalar(@opts) == 1 ){ + return (undef, $opts[0]); + } elsif ($arg eq '') { + return (undef, $arg); + } elsif (defined($prev) && defined($opt->{$prev}) && $opt->{$prev}->{type} ne 'noarg'){ + return (undef, $arg); + } elsif (scalar(@opts) == 0 ) { + return ('invalid', undef); + } else { + return ('ambiguous', @opts); + } +} + # Table for translating options to arguments my %options = ( 'audible' => { 'p_arg'=>'a', @@ -136,8 +221,8 @@ my $host = shift @ARGV; die "ping: Missing host\n" unless defined($host); if ($host eq "--get-options"){ - my @args = @ARGV; - get_options(\%options, \@args); + my @comp_args = @ARGV; + get_options(\%options, \@comp_args); } my $ip = new NetAddr::IP $host; die "ping: Unknown host: $host\n" @@ -153,8 +238,10 @@ given ($ip->version) { } my @cmdargs = ( 'ping' ); - -while (my $arg = shift @ARGV) { +my $args = [ 'ping', $host, @ARGV ]; +$args = expand_args(\%options, $args); +shift @$args; shift @$args; +while (my $arg = shift @$args) { my $pingarg = $options{$arg}->{p_arg}; die "ping: unknown option $arg\n" unless $pingarg; @@ -163,11 +250,12 @@ while (my $arg = shift @ARGV) { push @cmdargs, $flag; if (rindex($pingarg, ':') != -1) { - my $optarg = shift @ARGV; + my $optarg = shift @$args; die "ping: missing argument for $arg option\n" unless defined($optarg); push @cmdargs, $optarg; } } +print "@cmdargs\n"; exec { $cmd } @cmdargs, $host; diff --git a/templates/ping/node.tag/node.tag/node.def b/templates/ping/node.tag/node.tag/node.def index 9452558..cca366b 100644 --- a/templates/ping/node.tag/node.tag/node.def +++ b/templates/ping/node.tag/node.tag/node.def @@ -1,3 +1,3 @@ help: Ping options -allowed: /opt/vyatta/bin/ping --get-options ${COMP_WORDS[@]} +allowed: /opt/vyatta/bin/ping --get-options "${COMP_WORDS[@]}" run: /opt/vyatta/bin/ping ${@:2} |