Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

PATCH: arp and route completion



This adds better cross-system handling for arp and route completion.

Linux's route is actually quite different to real Unix but you're
supposed to use ip on Linux these days anyway. route add has been the
priority here. Might be useful to complete routes for route del but
parsing netstat -rn may not be trivial.

Oliver

diff --git a/Completion/Unix/Command/_arp b/Completion/Unix/Command/_arp
index f340e979e..80e829022 100644
--- a/Completion/Unix/Command/_arp
+++ b/Completion/Unix/Command/_arp
@@ -1,23 +1,103 @@
 #compdef arp
 
 local state line expl curcontext="$curcontext" ret=1
-local -a cmds
+typeset -A opt_args
+local -a cmds args
 
-cmds=(-a --display -d --delete -s --set -f --file)
+flags=( temp pub )
+cmds=(
+  '(2 3)-a[show entries for all hosts]'
+  '(2 -d)-d[delete entry from table]'
+  '(-n -v)-s[create an arp entry]'
+  '(2 3 -n -v)-f[read multiple entries from file]'
+)
+args=( '-n[show numeric addresses]' )
+vopt='-v[be verbose]'
 
-_arguments -C \
-  "($cmds 1 -D --use-device)"{-a,--display}'[show entries for all or specified hosts]:host:->hostintable' \
-  "($cmds 1 -n --numeric -D --use-device -H --hw-type)"{-d,--delete}'[delete entry from table]:host:->hostintable' \
-  "($cmds 1 -n --numeric)"{-s,--set}'[create an ARP entry]:host:_hosts:ethernet address::*:option:(temp trail pub)' \
-  "($cmds 1 -n --numeric)"{-f,--file}'[read multiple entries from file]:file:_files' \
-  '(-i --device)'{-i,--device}'[select an interface]:::_net_interfaces:' \
-  '(-D --use-device -a --display -d --delete)'{-D,--use-device}"[use the interface ifa's hardware address]" \
-  '(-H --hw-type -d --delete)'{-H,--hw-type}'[class of entries to check for]:class:(ether arcnet pronet ax25 netrom)' \
-  '(-n --numeric -d --delete -s --set -f --file)'{-n,--numeric}'[shows numerical addresses]' \
-  '(-v --verbose)'{-v,--verbose}'[be verbose]' \
-  '(-a)1:host:->hostintable' && ret=0
+if (( ${+words[(r)-d]} )) && [[ $OSTYPE = (*bsd|dragonfly|darwin)* ]]; then
+  args+=( '(1 *)-a[delete all entries]' )
+fi
 
-[[ "$state" = hostintable ]] &&
-  _wanted hosts expl 'host' compadd ${${${(f)"$(${words[1]} -an)"}##[ ?(]#}%%[ )]*} && ret=0
+case $OSTYPE in
+  linux*)
+    cmds=(
+      '(2 * -D --use-device)-a[show entries in BSD style output format]'
+      '!(2 * -D --use-device)-e'
+      '(2 -n --numeric -D --use-device -H --hw-type)'{-d,--delete}'[delete entry from table]'
+      '(-n --numeric)'{-s,--set}'[create an ARP entry]'
+      '(2 * -D --use-device)'{-f,--file}'[read multiple entries from file]'
+    )
+    args=(
+      '(-i --device)'{-i+,--device=}'[select an interface]:interface:_net_interfaces'
+      '(-D --use-device -a --display -d --delete)'{-D,--use-device}"[use specified interface's hardware address]"
+      '(-H --hw-type -d --delete)'{-H+,--hw-type=}'[specify class of entries to check for]:class:(ash ether arcnet pronet ax25 netrom rose dlci fddi hippi irda x25 infiniband eui64)'
+      '(* -n --numeric -d --delete -s --set -f --file)'{-n,--numeric}'[show numeric addresses]'
+      '(-v --verbose)'{-v,--verbose}'[be verbose]'
+    )
+    flags+=( netmask )
+  ;;
+  darwin*|freebsd*|dragonfly*)
+    cmds+=( '(-n -v -i)-S[create an arp entry, replacing any existing entry]' )
+  ;|
+  darwin*|freebsd*)
+    args+=( '(-s -Q -f)-i+[select an interface]:interface:_net_interfaces' )
+  ;|
+  darwin*)
+    args+=(
+      '(-d -s -S -f)-l[show link-layer reachability information]'
+      '(-d -s -S -f)-x[show extended link-layer reachability information]'
+    )
+    flags+=( reject blackhole only ifscope )
+  ;;
+  dragonfly*)
+    flags+=( only )
+    args+=( '-c:cpu' )
+  ;;
+  netbsd*)
+    flags+=( proxy )
+    args+=( $vopt )
+  ;;
+  freebsd*)
+    args+=( $vopt )
+    flags+=( blackhole reject )
+  ;;
+  openbsd*)
+    args+=(
+      '(-a -d -W)-F[overwrite existing entries]'
+      '(-W)-V+[select the routing domain]:routing domain'
+    )
+    cmds+=(
+      '(- 1)-W[send the wake on LAN frame]'
+    )
+    flags+=( permanent )
+  ;;
+  solaris*) flags+=( trail permanent) ;;
+esac
+
+_arguments -C -s -S $args \
+  '1: :->hostintable' \
+  '2:ethernet address' \
+  "*: :->flags" \
+  + '(cmds)' $cmds && ret=0
+
+if [[ "$state" = hostintable ]]; then
+  if [[ -n $opt_args[(i)-(D|-use-device)] ]]; then
+    _wanted interfaces expl interface _net_interfaces && ret=0
+  elif [[ -n $opt_args[(i)-(f|-file)] ]]; then
+    _files && ret=0
+  elif [[ -n $opt_args[(i)-(s|S|-set)] ]]; then
+    _hosts && ret=0
+  else
+    _wanted hosts expl 'host' compadd ${${${(f)"$(${words[1]} -an)"}##[ ?(]#}%%[ )]*} && ret=0
+  fi
+elif [[ "$state" = flags ]]; then
+  if [[ $words[CURRENT-1] = netmask ]]; then
+    _message -e netmasks netmask
+  elif (( $+opt_args[-W] )) || [[ $words[CURRENT-1] = ifscope ]]; then
+    _wanted interfaces expl interface _net_interfaces && ret=0
+  else
+    _wanted flags expl flag compadd -F line $flags && ret=0
+  fi
+fi
 
 return ret
diff --git a/Completion/Unix/Command/_route b/Completion/Unix/Command/_route
new file mode 100644
index 000000000..f8426874c
--- /dev/null
+++ b/Completion/Unix/Command/_route
@@ -0,0 +1,254 @@
+#compdef route
+
+local curcontext="$curcontext" expect ret=1
+local -a state state_descr line args families modifiers ignore sub sequential tags
+local -A opt_args subcmds once params
+
+subcmds=(
+  add     'add a route'
+  flush   'remove all routes'
+  delete  'delete a specific route'
+  change  'change aspects of a route (such as its gateway)'
+  get     'lookup route for a destination'
+  monitor 'continuously report any changes to the routing information'
+)
+args=(
+  '-n[output addresses numerically]'
+  '(-q)-v[verbose output]'
+)
+modifiers=(
+  '-net:interpret destination as a network'
+  '-host:interpret destination as a host'
+)
+params=(
+  '-dst'          target  # does this definitely follow
+  '(-|)netmask'   netmask
+  '(gw|-gateway)' gateway
+  metric          metric
+  '(mss|window|-(send|recv)pipe)' size:bytes
+  '[i-]rtt'       time:ms
+  -rttvar         rttvar
+  -mtu            mtu
+  '(dev|-ifscope|-ifp)'  interface
+  -ifa            address
+  -expire         time:epoch
+  -hopcount       hopcount
+  -tag            tag
+  -prefixlen      bits
+  '-(label|push|pop|swap)' label
+  -priority       number  # is it a number
+  -secattr        secattr
+  '(-iw|-iwmax|-msl)' value
+  '-fib'          table
+)
+
+case $OSTYPE in
+  ^linux*)
+    args+=( '(-v)-q[suppress all output]' )
+    families=( -inet -inet6 )
+    modifiers+=(
+      '-dst:distinguish a destination'
+      '-gateway:distinguish a gateway address'
+      -netmask
+      -rtt -rttvar
+      -sendpipe -recvpipe
+      -mtu -hopcount
+      -expire
+      '-lock' '-lockrest'
+      -i{,nter}face:'indicate destination is directly reachable'
+      '-static:manually added route'
+      '-nostatic:pretend route added by kernel or daemon'
+      '-reject:emit an ICMP unreachable when matched'
+      '-blackhole:silently discard packets (during updates)'
+      '-proto1:set protocol specific routing flag #1'
+      '-proto2:set protocol specific routing flag #2'
+    )
+    sequential=( target gateway netmask )
+  ;|
+  *bsd*|darwin*|dragonfly*)
+    modifiers+=(
+      -link '-ifp' '-ifa' # do these need an argument: interface or address
+      '-prefixlen:indicate mask bits'
+    )
+  ;|
+  (net|free)bsd*|darwin*|dragonfly*)
+    families+=( -xns )
+    modifiers+=( '-xresolve:emit mesg on use (for external lookup)' )
+  ;|
+  (net|open)bsd*|darwin*|dragonfly*)
+    modifiers+=(
+      '-cloning:generate a new route on use'
+      '-llinfo:validly translate proto addr to link addr'
+    )
+  ;|
+  (open|free)bsd*|darwin*|dragonfly*)
+    args+=(
+      "-d[debug-only mode: don't update routing table]"
+      '-t[test-only mode: /dev/null used instead of a socket]'
+    )
+  ;|
+  netbsd*|solaris*)
+    args+=( '-f[remove all routes first]' )
+  ;;
+  (netbsd|darwin|dragonfly)*)
+    modifiers+=( '-proxy:make entry a link level proxy' )
+  ;|
+  (netbsd|openbsd|dragonfly)*)
+    subcmds+=( show 'print out the routing table' )
+    families+=( -mpls )
+  ;|
+  (netbsd|darwin)*)
+    families+=( -atalk )
+  ;|
+  (freebsd|darwin)*)
+    families+=( -osi )
+  ;|
+  (openbsd|dragonfly)*)
+    modifiers+=( -push -pop -swap )
+  ;|
+  freebsd*)
+    subcmds+=(
+      del $subcmds[delete]
+      show $subcmds[get]
+    )
+    args+=(
+      '(-6)-4[specify IPv4 address family]'
+      '(-4)-6[specify IPv6 address family]'
+    )
+    families+=( -4 -6 )
+    modifiers+=( '-fib:specify a routing table' )
+  ;;
+  netbsd*)
+    subcmds+=( flushall 'remove all routes including the default gateway' )
+    args+=(
+      '-S[print a space when a flag is missing to align flags]'
+      '-s[suppress all output from get except for the gateway]'
+    )
+    modifiers+=(
+      '-tag'
+      '-noreject:clear reject flag'
+      '-noblackhole:clear blackhole flag'
+    )
+  ;;
+  openbsd*)
+    subcmds+=( exec 'execute a command with alternate routing table' )
+    args+=(
+      '-T+[select specified alternate routing table]:table id'
+    )
+    modifiers+=(
+      -sa
+      '-label'
+      '-priority'
+      '-mpath:multiple gateways for a destination exist'
+      -mplslabel -in -out
+    )
+  ;;
+  solaris*)
+    subcmds+=( show 'display list of routes applied at system startup' )
+    args+=(
+      '-p[make changes to the route tables persistent across system restarts]'
+      '-R+[specify alternate root directory where changes are applied]:directory:_directories'
+    )
+    modifiers+=(
+      "-private:don't advertise this route"
+      '-multirt:create the specified redundant route'
+      '-setsrc:assign the default source address'
+      '-secattr:security attributes'
+    )
+  ;;
+  darwin*)
+    modifiers+=( -ifscope )
+  ;|
+  dragonfly*)
+    modifiers+=( -iw -iwmax -msl )
+  ;|
+  linux*)
+    args+=(
+      '(H -n)--numeric[output addresses numerically]'
+      '(H)*'{-e,--extend}'[display other/more information]'
+      '!(H -C --cache)'{-F,--fib}
+      '(H -C --cache)'{-C,--cache}'[display routing cache instead of FIB]'
+      + '(family)'
+      '-A+[use specified address family]:address family:(inet inet6 ax25 netrom ipx ddp x25)'
+      -4 -6 --inet --inet6 --ax25 --netrom --ipx --ddp --x25
+      + '(H)'
+      '(1 *)'{-h,--help}'[display help information]'
+      '(1 *)'{-V,--version}'[display version information]'
+    )
+    subcmds[del]=$subcmds[delete]
+    unset 'subcmds[monitor]' 'subcmds[get]' 'subcmds[change]'
+    modifiers+=(
+      netmask gw metric mss window irtt reject mod dyn reinstate
+      'dev:force route to be associated with the specified device'
+    )
+    sequential=( target interface )
+  ;;
+esac
+
+print -v sub -f '%s\\:%s' ${(kvq)subcmds}
+_arguments -C -s -S "1:command:(($sub))" '*::args:->args' $args && ret=0
+
+[[ -n $opt_args[(i)-[46]] ]] && families=()
+
+if [[ -n $state ]]; then
+  if [[ $line[1] = exec ]]; then
+    shift words
+    (( CURRENT-- ))
+    _normal
+  elif [[ $line[1] = (flush|monitor) ]]; then
+    sequential=()
+  fi
+
+  for ((i=2;i<CURRENT;i++)); do
+    if [[ -n $expect ]]; then
+      sequential=( ${sequential:#$expect} )
+      expect=''
+      continue
+    fi
+
+    expect=${params[(K)$words[i]]}
+    if [[ -n $expect ]]; then
+      ignore+=( ${(Q)words[i]} )
+    else
+      if [[ -n ${(M)${families%%:*}:#${(q)words[i]}} ]]; then
+        families=()
+      elif [[ -n ${(M)${modifiers%%:*}:#${(q)words[i]}} ]]; then
+	ignore+=( ${(q)words[i]} )
+      elif [[ $words[1] != -lock ]]; then
+	shift sequential
+      fi
+    fi
+  done
+
+  [[ -z $expect ]] && tags=( modifiers families )
+  _tags values $tags
+  while _tags; do
+    if _requested values; then
+      case ${expect:-$sequential[1]} in
+	target)
+	  if [[ -z $expect ]]; then
+	    _wanted -x targets expl target compadd default && ret=0
+	  else
+	    _message -e targets target
+	  fi
+	;;
+	interface) _net_interfaces && ret=0 ;;
+	size:bytes) _guard "[0-9]#" 'size (bytes)' ;; # _guard usage pointless
+	time:ms) _guard "[0-9]#" 'time (ms)' ;;
+	time:microseconds) _guard "[0-9]#" 'time (microseconds)' ;;
+	time:epoch) _guard "[0-9]#" 'expiration time (seconds since epoch)' ;;
+	rttvar) _guard "[0-9]#" 'time variance (microseconds)' ;;
+	mtu) _guard "[0-9]#" 'max MTU (bytes)' ;;
+	hopcount) _guard "[0-9]#" 'hop count' ;;
+	ssthresh) _message -e threshold 'ss threshold' ;;
+	bits) _guard "[0-9]#" 'bits' ;;
+	*) _guard "[^-]#" "${expect:-$sequential[1]}" ;;
+      esac
+    fi
+    _requested modifiers && _describe -t modifiers modifier modifiers -F ignore && ret=0
+    _requested families expl 'address family' compadd -a families && ret=0
+    (( ret )) || break
+  done
+fi
+
+return ret



Messages sorted by: Reverse Date, Date, Thread, Author