diff options
author | Tanaka Akira <akr@users.sourceforge.net> | 1999-08-12 22:59:04 +0000 |
---|---|---|
committer | Tanaka Akira <akr@users.sourceforge.net> | 1999-08-12 22:59:04 +0000 |
commit | 8d1b4b1358db02d6c9426e4bb3553583e11bf112 (patch) | |
tree | a3095364536d55f8356ac99559e440cc91f33eb1 /Misc | |
parent | 5714953c514a5fea35dcd819caf1afef4d92a13b (diff) | |
download | zsh-8d1b4b1358db02d6c9426e4bb3553583e11bf112.tar.gz zsh-8d1b4b1358db02d6c9426e4bb3553583e11bf112.tar.xz zsh-8d1b4b1358db02d6c9426e4bb3553583e11bf112.zip |
Sync up with zsh-3_1_6-pws-1.
Diffstat (limited to 'Misc')
-rw-r--r-- | Misc/.lastloc | 2 | ||||
-rw-r--r-- | Misc/new-completion-examples | 453 | ||||
-rw-r--r-- | Misc/zftp-functions | 1281 |
3 files changed, 0 insertions, 1736 deletions
diff --git a/Misc/.lastloc b/Misc/.lastloc deleted file mode 100644 index 8ba7dd946..000000000 --- a/Misc/.lastloc +++ /dev/null @@ -1,2 +0,0 @@ -(("/home/user2/pws/src/zsh-3.1.5/Misc/globtests.ksh" . 2763) - ("/home/user2/pws/src/zsh-3.1.5/Misc/globtests" . 3123)) diff --git a/Misc/new-completion-examples b/Misc/new-completion-examples deleted file mode 100644 index 659679891..000000000 --- a/Misc/new-completion-examples +++ /dev/null @@ -1,453 +0,0 @@ -# Define a new widget behaving like `expand-or-complete' but calling the -# function `main-complete' to generate matches. - -zle -c my-comp expand-or-complete main-complete - -bindkey '\C-i' my-comp - - -# Below is a proposed main loop and the things it needs. - -# One associative array for normal completions and one for patterns. - -typeset -A comps - - -# These may be used to define completion handlers. First argument is the -# name of the function/variable containing the definition, the other -# arguments are the command names for which this definition should be used. -# With only one argument the function/variable-name __$1 is used. - -defcomp() { - local v - - if [[ $# -eq 1 ]] then - comps[$1]="__$1" - else - v="$1" - shift - for i; do - comps[$i]="$v" - done - fi -} - -defpatcomp() { - if [[ ${+patcomps} == 1 ]] then - patcomps=("$patcomps[@]" "$2 $1" ) - else - patcomps=( "$2 $1" ) - fi -} - - -# These can be used to easily save and restore the state of the special -# variables used by the completion code. - -alias compsave='local _opre _oipre _oargs _ocur;_opre="$PREFIX";_oipre="$IPREFIX";_oargs=( "$@" );_ocur="$CURRENT"' -alias compreset='PREFIX="$_opre";IPREFIX="$_oipre";argv=( "$_oargs[@]" );CURRENT="$_ocur"' - -# This is an easy way to get completion for sub-commands. - -alias compsub='do-complete "$@" || return 1' - -# This searches $1 in the array for normal completions and calls the result. - -compalso() { - 1="$comps[$1]" - [[ -z "$1" ]] || call-complete "$@" -} - -# This generates matches. The first argument is something we got from one -# of the associative arrays above. This is expected to be either the name -# of a variable in which case we use its value as arguments to complist, -# or it is the name of a function in which case we call this function with -# the arguments from the command line as its arguments. - -call-complete() { - local var - - eval var\=\$\{\+$1\} - if [[ "$var" == 0 ]] then - "$@" - else - eval complist \$\{${1}\[\@\]\} - fi -} - -# The main loop of the competion code. This is what is called when TAB is -# pressed. The completion code gives us the special variables and the -# arguments from the command line are gives as positional parameters. - -main-complete() { - emulate -R zsh - local comp - setopt localoptions nullglob rcexpandparam globdots - unsetopt markdirs globsubst shwordsplit nounset - - # An entry for `--first--' is the replacement for `compctl -T' - # The `|| return 1' is used throughout: if a function producing matches - # returns non-zero this is interpreted as `do not try to produce more matches' - # (this is the replacement for `compctl -t'). - - comp="$comps[--first--]" - [[ -z "$comp" ]] || call-complete "$comp" "$@" || return 1 - - # For arguments we use the `do-complete' function below called via the - # convenience alias `compsub'. - - if [[ $CONTEXT == argument || $CONTEXT == command ]] then - compsub - else - # Let's see if we have a special completion definition for the other - # possible contexts. - - comp='' - - case $CONTEXT in - redirect) comp="$comps[--redir--]";; - math) comp="$comps[--math--]";; - subscript) comp="$comps[--subscr--]";; - value) comp="$comps[--value--]";; - condition) comp="$comps[--cond--]";; - esac - - # If not, we use default completion, if any. - - [[ -z "$comp" ]] && comp="$comps[--default--]" - [[ -z "$comp" ]] || call-complete "$comp" "$@" || return 1 - fi -} - -# This does completion for a command (in command position and for the -# arguments). - -do-complete() { - local comp cmd1 cmd2 pat val - - # Completing in command position? If not we set up `cmd1' and `cmd2' as - # two strings we have search in the completion definition arrays (e.g. - # a path and the last path name component). - - if [[ $CONTEXT == command ]] then - comp="$comps[--command--]" - [[ -z "$comp" ]] || call-complete "$comp" "$@" || return 1 - return 0 - elif [[ "$COMMAND[1]" == '=' ]] then - eval cmd1\=$COMMAND - cmd2="$COMMAND[2,-1]" - elif [[ "$COMMAND" == */* ]] then - cmd1="$COMMAND" - cmd2="${COMMAND:t}" - else - cmd1="$COMMAND" - eval cmd2=$(whence -p $COMMAND) - fi - - # See if there are any matching pattern completions. - - for i in "$patcomps[@]"; do - pat="${i% *}" - val="${i#* }" - if [[ "$cmd1" == $~pat || "$cmd2" == $~pat ]] then - call-complete "$val" "$@" || return 1 - fi - done - - # Now look up the two names in the normal completion array. - - comp="${comps[$cmd1]:-$comps[$cmd2]}" - - # And generate the matches, probably using default completion. - - [[ -z "$comp" ]] && comp="$comps[--default--]" - [[ -z "$comp" ]] || call-complete "$comp" "$@" || return 1 -} - -# Do sub-completion for pre-command modifiers. - -defcomp __precmd - noglob nocorrect exec command builtin -__precmd() { - COMMAND="$1" - shift - (( CURRENT-- )) - if [[ CURRENT -eq 0 ]] then - CONTEXT=command - else - CONTEXT=argument - fi - compsub -} - -# Utility function for in-path completion. -# First argument should be an complist-option (e.g. -f, -/, -g). The other -# arguments should be glob patterns, one per argument. -# E.g.: files -g '*.tex' '*.texi' -# This is intended as a replacement for `complist -f', `complist -/', and -# `complist -g ...' (but don't use it with other options). -# This function behaves as if you have a matcher definition like: -# compctl -M 'r:|[-.,_/]=* r:|=* m:{a-z}={A-Z} m:-=_ m:.=,' -# so you may want to modify this. - -pfiles() { - local nm str pa pre epre a b c s rest - - setopt localoptions nullglob rcexpandparam globdots extendedglob - unsetopt markdirs globsubst shwordsplit nounset - - nm=$NMATCHES - if [[ $# -eq 0 ]] then - complist -f - elif [[ "$1" = -g ]] then - complist -g "$argv[2,-1]" - shift - else - complist $1 - shift - fi - [[ -nmatches nm ]] || return - - str="$PREFIX*$SUFFIX" - - [[ -z "$1" ]] && 1='*' - if [[ $str[1] = \~ ]] then - pre="${str%%/*}/" - eval epre\=$pre - str="${str#*/}" - pa='' - else - pre='' - epre='' - if [[ $str[1] = / ]] then - str="$str[2,-1]" - pa='/' - else - pa='' - fi - fi - str="$str:gs/,/*,/:gs/_/*_/:gs./.*/.:gs/-/*[-_]/:gs/./*[.,]/:gs-*[.,]*[.,]*/-../-:gs.**.*." - while [[ "$str" = */* ]] do - rest="${str#*/}" - a="${epre}${pa}(#l)${str%%/*}(-/)" - a=( $~a ) - if [[ $#a -eq 0 ]] then - return - elif [[ $#a -gt 1 ]] then - c=() - s=( $rest$@ ) - s=( "${(@)s:gs.**.*.}" ) - for i in $a; do - b=( $~i/(#l)$~s ) - eval b\=\( \$\{b:/\*\(${(j:|:)fignore}\)\} \) - [[ $#b -ne 0 ]] && c=( $c $i ) - done - if [[ $#c -eq 0 ]] then - return - elif [[ $#c -ne 1 ]] then - a="$epre$pa" - c=( $~c/(#l)$~s ) - eval c\=\( \$\{c:/\*\(${(j:|:)fignore}\)\} \) - c=( ${c#$a} ) - for i in $c; do - compadd -p "$pre$pa" -W "$a" -s "/${i#*/}" -f "${i%%/*}" - done - return - fi - a=( "$c[1]" ) - fi - a="$a[1]" - pa="$pa${a##*/}/" - str="$rest" - done - a="$epre$pa" - s=( $str$@ ) - s=( "${(@)s:gs.**.*.}" ) - b=( $~a(#l)$~s ) - eval b\=\( \$\{b:/\*\(${(j:|:)fignore}\)\} \) - compadd -p "$pre$pa" -W "$epre$pa" -f ${b#$a} -} - -# Utility function for completing files of a given type or any file. -# In many cases you will want to call this one instead of pfiles(). - -files() { - local nm - - nm=$NMATCHES - pfiles "$@" - - [[ $# -ne 0 && -nmatches nm ]] && pfiles -} - -# Simple default, command, and math completion defined with variables. - -defcomp __default --default-- -__default() { - files -} - -defcomp __command --command-- -__command=( -c ) - -defcomp __math --math-- -__math=( -v ) - -defcomp __subscr --subscr-- -__subscr() { - compalso --math-- "$@" - # ...probably other stuff -} - -# A simple pattern completion, just as an example. - -defpatcomp __x_options '*/X11/*' -__x_options() { - complist -J options -k '(-display -name -xrm)' -} - -# A better example: completion for `find'. - -defcomp find -__find() { - compsave - - if [[ -mbetween -(ok|exec) \\\; ]] then - compsub - elif [[ -iprefix - ]] then - complist -s 'daystart {max,min,}depth follow noleaf version xdev \ - {a,c,}newer {a,c,m}{min,time} empty false {fs,x,}type gid inum links \ - {i,}{l,}name {no,}{user,group} path perm regex size true uid used \ - exec {f,}print{f,0,} ok prune ls' - compreset - elif [[ -position 1 ]] then - complist -g '. ..' - files -g '(-/)' - elif [[ -mcurrent -1 -((a|c|)newer|fprint(|0|f)) ]] then - files - elif [[ -current -1 -fstype ]] then - complist -k '(ufs 4.2 4.3 nfs tmp mfs S51K S52K)' - elif [[ -current -1 -group ]] then - complist -k groups - elif [[ -current -1 -user ]] then - complist -u - fi -} - -# Various completions... - -defcomp __gunzip gunzip zcat -__gunzip() { - files -g '*.[gG][z]' -} - -defcomp gzip -__gzip() { - files -g '*~*.[gG][zZ]' -} - -defcomp xfig -__xfig() { - files -g '*.fig' -} - -defcomp __make make gmake -__make() { - complist -s "\$(awk '/^[a-zA-Z0-9][^/ ]+:/ {print \$1}' FS=: [mM]akefile)" -} - -defcomp __ps gs ghostview gview psnup psselect pswrap pstops pstruct lpr -__ps() { - files -g '*([pP][sS]|eps)' -} - -defcomp __which which whence -__which=( -caF ) - -defcomp __rlogin rlogin rsh ssh -__rlogin() { - if [[ -position 1 ]] then - complist -k hosts - elif [[ -position 2 ]] then - complist -k '(-l)' - elif [[ -position 3 && -word 1 artus ]] then - complist -k '(puck root)' - fi -} - -defcomp __dvi xdvi dvips dvibook dviconcat dvicopy dvidvi dviselect dvitodvi dvitype -__dvi() { - files -g '*.(dvi|DVI)' -} - -defcomp __dirs rmdir df du dircmp cd -__dirs() { - files -/ '*(-/)' -} - -defcomp __jobs fg bg jobs -__jobs=(-j -P '%?') - -defcomp kill -__kill() { - if [[ -iprefix '-' ]] then - complist -k signals - else - complist -P '%?' -j - fi -} - -defcomp __uncompress uncompress zmore -__uncompress() { - files -g '*.Z' -} - -defcomp compress -__compress() { - files -g '*~*.Z' -} - -defcomp __tex tex latex glatex slitex gslitex -__tex() { - files -g '*.(tex|TEX|texinfo|texi)' -} - -defcomp __options setopt unsetopt -__options=(-M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o) - -defcomp __funcs unfunction -__funcs=(-F) - -defcomp __aliases unalias -__aliases=(-a) - -defcomp __vars unset -__vars=(-v) - -defcomp __enabled disable -__enabled=(-FBwa) - -defcomp __disabled enable -__disabled=(-dFBwa) - -defcomp __pdf acroread -__pdf() { - files -g '*.(pdf|PDF)' -} - -defcomp tar -__tar() { - local nm tf - compsave - - tf="$2" - nm=$NMATCHES - if [[ ( -mword 1 *t*f* || -mword 1 *x*f* ) && -position 3 100000 ]] then - complist -k "( $(tar tf $tf) )" - compreset - elif [[ -mword 1 *c*f* && -position 3 100000 ]] then - files - compreset - elif [[ -mcurrent -1 *f* && -position 2 ]] then - files -g '*.(tar|TAR)' - fi -} diff --git a/Misc/zftp-functions b/Misc/zftp-functions deleted file mode 100644 index a07e46d72..000000000 --- a/Misc/zftp-functions +++ /dev/null @@ -1,1281 +0,0 @@ -# zftp is a loadable module implementing an FTP client as a builtin -# command so that you can use the shell command language and line -# editing to make life easier. If your system has dynamically -# load libraries and zsh was compiled to use them, it is probably -# somewhere where it can be loaded at run time. Otherwise, it depends -# whether the shell was compiled with zftp already built into it. -# -# Here is a suite of functions, plus assorted other code, to make -# zftp work smoothly. -# -# Completion is implemented in a fairly natural way, except that -# very little support has been provided for non-UNIX remote hosts. -# On such machines, the safest thing to do is only try to complete -# files in the current directory; this should be OK. -# -# Remote globbing for commands which retrieve files is also -# implemented. This can be done in two different ways. The default -# is for zsh to do the globbing locally. The advantage is that full -# zsh pattern matching (respecting the setting of extendedglob) is -# possible, and no assumption (apart from the restrictions on -# directory handling noted above) is made about the behaviour of the -# server. The disadvantage is that the entire filename list for the -# current directory must be retrieved, and then zsh must laboriously -# do pattern matching against every file, so it is potentially slow -# for large directories. Only the non-directory part of file names is -# globbed. -# -# The alternative will be used if $zfrglob has non-zero length. -# Zsh then sends the pattern to the server for globbing. Best of -# luck. -# -# To support remote globbing, some functions have been aliased -# with 'noglob' in front. Currently, this has a dire effect on -# completion unless the completeinaliases option is set, so -# it is set below. This can conceivably cause you problems -# if you expect completion for aliases automatically to give you -# completion for the base command. I suspect that most people -# don't even know that happens. -# -# The following functions are provided. -# -# General status changing and displaying functions: -# zfparams -# Simple front end to `zftp params', except it will automatically -# query host, user and password. These are then stored to be -# used with a `zfopen' with no arguments. -# zfopen [ host [ user ... ] ] -# Open a connection and login. Unless the option -1 (once) -# is given, will store the parameters for the open (including -# a password which is prompted for and not echoed) so that -# if you call zfopen subsequently without arguments it will -# reopen the same connection. -# zfanon anonftphost -# Open a connection for anonymous FTP. Tries to guess an -# email address to use as the password, unless $EMAIL_ADDR is -# already set. The first time, will tell you what it has guessed. -# It's rude to set EMAIL_ADDR=mozilla. -# zfcd [ dir | old new ] -# Change directory on the server. This tries to mimic the behaviour -# of the shell's cd. In particular, -# zfcd change to '~' on server, if it interprets it -# zfcd - change to previous directory of current connection -# zfcd OLD NEW change directory from fooOLDbar to fooNEWbar -# One piece of magic is builtin: an initial part of the directory -# matching $HOME is translated back to `~'. Most UNIX servers -# recognise the usual shell convention. So things like `zfcd $PWD' -# is useful provide you are under your home directory and the -# structure on the remote machine mirrors that on the local. -# zfhere -# Synonym for `zfcd $PWD', see above. -# zfdir [args] -# Show a long diretory list of the remote connection. Any -# arguments are passed on to the server, apart from options. -# Currently this always uses a pager to show the directory -# list. Caching is implemented: zfdir on its own always shows -# the current diretory, which is cached; zfdir with some other -# directory arguments shows that, which is cached separately -# and can be reviewed with `zfdir -r'. Other options: -# -f force reget, overriding the cache, in case something's changed -# -d delete the cache, but don't show anything. -# To pass options to the server, use e.g. `zfdir -- -C'. -# This also has the zfcd ~ hack. -# zfls [args] -# Short list of the long directory, depending on what [args] -# do to the server. No options, no caching, no pager. -# zftype [ a[scii] | i[mage] | b[inary] ] -# Set or display the transfer type; currently only ASCII -# and image (same as binary) types are supported. -# zfclose -# Close the connection. -# zfstat -# Print the zftp status from local variables; doesn't do any network -# operations unless -v is supplied, in which case the server is -# asked for its views on the status, too. -# -# Functions for retrieving data: -# All accept the following options: -# -G Don't do remote globbing (see above); the default is to do it. -# -t Try to set local files to the same time as the remote ones. -# Unfortunately we only know the remote time in GMT, so it's -# a little tricky and you need perl 5 (installed as `perl') -# for this to work. Suggestions welcome. -# zfget file1 file2 ... -# Retrieve each file from the server. The remote file is the -# full name given, the local file is the non-directory part of that -# (assuming UNIX file paths). -# zfuget file1 file2 .. -# Get with update. Check remote and local sizes and times and -# retrieve files which are newer on the server. Will query -# hard cases, which are where the remote file is newer but a -# different size, or is older but the same size. With option -s -# (silent) assumes it's best to retrieve the files in both those -# cases. With -v (may be combined with -s), print the information -# about the files being considered. -# zfcget file1 ... -# Assuming file1 was incompletely retrieved, try to get the rest of -# it. This relies on a normal UNIX server behaviour which is not -# as specified in the FTP standard and hence is not universal. -# zfgcp file1 file2 -# zfgcp file1 file2 ... dir -# Get with the behaviour of cp, i.e. copy remote file1 to local -# file2, or get remote fileN into local diretory dir. -# -# Function for sending data: -# zfput file1 file2 ... -# Put the local files onto the server under the same name. The -# local files are exactly as given; the remote files are the -# non-diretory parts of that. -# zfuput file1 file2 .. -# Put the local files onto the server, with update. Works -# similarly to zfuget. -# -# Utility functions: -# zftp_chpwd -# Show the new directory when it changes; try to put it into -# an xterm on shelltool header. Works best alongside chpwd. -# zftp_progress -# Show the percentage of a file retrieved as it is coming; if the -# size is not available show the size transferred so far. The -# percentage may be wrong if sending data from a local pipe. -# If you transfer files in the background, you should undefine -# this before the transfer. It is smart enough not to print -# anything when stderr is not a terminal. -# zfcd_match -# Function for remote directory completion. -# zfget_match -# Function for remote filename completion. -# zfrglob varname -# This is used for the remote globbing. The pattern resides -# in $varname (note extra level of indirection), and on return -# $varname will contain the list of matching files. -# zfrtime locfile remfile [ time ] -# This sad thing does the setting of local file times to those -# of the remote, see horror story above. - -zmodload -ia zftp - -alias zfcd='noglob zfcd' -alias zfget='noglob zfget' -alias zfls='noglob zfls' -alias zfdir='noglob zfdir' -alias zfuget='noglob zfuget' -# only way of getting that noglob out of the way at the moment -setopt completealiases - -# -# zftp completions -# -compctl -f -x 'p[1]' \ - -k '(open params user login type ascii binary mode put putat - get getat append appendat ls dir local remote mkdir rmdir delete - close quit)' - \ - 'w[1,cd][1,ls][1,dir][1,rmdir]' -K zfcd_match -S/ -q - \ - 'W[1,get*]' -K zfget_match - 'w[1,delete][1,remote]' -K zfget_match - \ - 'w[1,open][1,params]' -k hosts -- zftp -compctl -K zfcd_match -S/ -q zfcd zfdir zfls -compctl -K zfget_match zfget zfgcp zfuget zfcget -compctl -k hosts zfopen zfparams - -function zfanon { - local opt optlist once - - while [[ $1 = -* ]]; do - if [[ $1 = - || $1 = -- ]]; then - shift; - break; - fi - optlist=${1#-} - for (( i = 1; i <= $#optlist; i++)); do - opt=$optlist[$i] - case $optlist[$i] in - 1) once=1 - ;; - *) print option $opt not recognised >&2 - ;; - esac - done - shift - done - - if [[ -z $EMAIL_ADDR ]]; then - # Exercise in futility. There's a poem by Wallace Stevens - # called something like `N ways of looking at a blackbird', - # where N is somewhere around 0x14 to 0x18. Now zftp is - # ashamed to prsent `N ways of looking at a hostname'. - local domain host - # First, maybe we've already got it. Zen-like. - if [[ $HOST = *.* ]]; then - # assume this is the full host name - host=$HOST - elif [[ -f /etc/resolv.conf ]]; then - # Next, maybe we've got resolv.conf. - domain=$(awk '/domain/ { print $2 }' /etc/resolv.conf) - [[ -n $domain ]] && host=$HOST.$domain - fi - # Next, maybe we've got nlsookup. May not work on LINUX. - [[ -z $host ]] && host=$(nslookup $HOST | awk '/Name:/ { print $2 }') - if [[ -z $host ]]; then - # we're running out of ideas, but this should work. - # after all, i wrote it... - # don't want user to know about this, too embarrassed. - local oldvb=$ZFTP_VERBOSE oldtm=$ZFTP_TMOUT - ZFTP_VERBOSE= - ZFTP_TMOUT=5 - if zftp open $host >& /dev/null; then - host=$ZFTP_HOST - zftp close $host - fi - ZFTP_VERBOSE=$oldvb - ZFTP_TMOUT=$oldtm - fi - if [[ -z $host ]]; then - print "Can't get your hostname. Define \$EMAIL_ADDR by hand." - return 1; - fi - EMAIL_ADDR="$USER@$host" - print "Using $EMAIL_ADDR as anonymous FTP password." - fi - - if [[ $once = 1 ]]; then - zftp open $1 anonymous $EMAIL_ADDR - else - zftp params $1 anonymous $EMAIL_ADDR - zftp open - fi -} - -function zfcd { - # zfcd: change directory on the remote server. - # - # Currently has the following features: - # --- an initial string matching $HOME in the directory is turned back into ~ - # to be re-interpreted by the remote server. - # --- zfcd with no arguments changes directory to '~' - # --- `zfcd old new' and `zfcd -' work analagously to cd - # --- if the connection is not currently open, it will try to - # re-open it with the stored parameters as set by zfopen. - # If the connection timed out, however, it won't know until - # too late. In that case, just try the same zfcd command again - # (but now `zfcd -' and `zfcd old new' won't work). - - # hack: if directory begins with $HOME, turn it back into ~ - # there are two reasons for this: - # first, a ~ on the command line gets expanded even with noglob. - # (I suppose this is correct, but I wouldn't like to swear to it.) - # second, we can no do 'zfcd $PWD' and the like, and that will - # work just as long as the directory structures under the home match. - - # Autoopen: if not already open, hope there are parameters set up to - # do so. If not, we get the right error message, so no harm done. - [[ -z $ZFTP_HOST ]] && { zfopen || return 1; } - - if [[ $1 = $HOME || $1 = $HOME/* ]]; then - 1="~${1#$HOME}" - fi - - if (( $# == 0 )); then - # Emulate `cd' behaviour - set -- '~' - elif [[ $# -eq 1 && $1 = - ]]; then - # Emulate `cd -' behaviour. - set -- $zflastdir - elif [[ $# -eq 2 ]]; then - # Emulate `cd old new' behaviour. - # We have to find a character not in $1 or $2; ! is a good bet. - eval set -- "\${ZFTP_PWD:s!$1!$2!}" - fi - - # We have to remember the current directory before changing it - # if we want to keep it. - local lastdir=$ZFTP_PWD - - zftp cd "$@" && zflastdir=$lastdir -} - -function zfcd_match { - # see zfcd for details of this hack - if [[ $1 = $HOME || $1 = $HOME/* ]]; then - 1="~${1#$HOME}" - fi - - # error messages only - local ZFTP_VERBOSE=45 - # should we redirect 2>/dev/null or let the user see it? - - if [[ $ZFTP_SYSTEM = UNIX* ]]; then - # hoo, aren't we lucky: this makes things so much easier - setopt localoptions rcexpandparam - local dir - if [[ $1 = ?*/* ]]; then - dir=${1%/*} - elif [[ $1 = /* ]]; then - dir=/ - fi - # If we're using -F, we get away with using a directory - # to list, but not a glob. Don't ask me why. - # I hate having to rely on awk here. - reply=($(zftp ls -F $dir | - awk '/\/$/ { print substr($1, 0, length($1)-1) }')) - if [[ $dir = / ]]; then - reply=(${dir}$reply) - elif [[ -n $dir ]]; then - reply=($dir/$reply) - fi - else - # I simply don't know what to do here. - # Just use the list of files for the current directory. - zfget_match $* - fi - -} - -function zfcget { - # Continuation get of files from remote server. - # For each file, if it's shorter here, try to get the remainder from - # over there. This requires the server to support the REST command - # in the way many do but RFC959 doesn't specify. - # Options: - # -G don't to remote globbing, else do - # -t update the local file times to the same time as the remote. - # Currently this only works if you have the `perl' command, - # and that perl is version 5 with the standard library. - # See the function zfrtime for more gory details. - - setopt localoptions - unsetopt ksharrays shwordsplit - - local loc rem stat=0 optlist opt nglob remlist locst remst - local tmpfile=${TMPPREFIX}zfcget$$ rstat tsize time - - while [[ $1 = -* ]]; do - if [[ $1 = - || $1 = -- ]]; then - shift; - break; - fi - optlist=${1#-} - for (( i = 1; i <= $#optlist; i++)); do - opt=$optlist[$i] - case $optlist[$i] in - G) nglob=1 - ;; - t) time=1 - ;; - *) print option $opt not recognised >&2 - ;; - esac - done - shift - done - - for remlist in $*; do - # zfcd directory hack to put the front back to ~ - if [[ $remlist = $HOME || $remlist = $HOME/* ]]; then - remlist="~${remlist#$HOME}" - fi - if [[ $nglob != 1 ]]; then - zfrglob remlist - fi - if (( $#remlist )); then - for rem in $remlist; do - loc=${rem:t} - if [[ ! -f $loc ]]; then - # File does not yet exist - zftp get $rem >$loc || stat=$? - else - # Compare the sizes. - locst=($(zftp local $loc)) - zftp remote $rem >$tmpfile - rstat=$? - remst=($(<$tmpfile)) - rm -f $tmpfile - if [[ $rstat = 2 ]]; then - print "Server does not support SIZE command.\n" \ - "Assuming you know what you're doing..." 2>&1 - zftp getat $rem $locst[1] >>$loc || stat=$? - continue - elif [[ $rstat = 1 ]]; then - print "Remote file not found: $rem" 2>&1 - continue - fi - if [[ $locst[1] -gt $remst[1] ]]; then - print "Local file is larger!" 2>&1 - continue; - elif [[ $locst[1] == $remst[1] ]]; then - print "Files are already the same size." 2>&1 - continue - else - if zftp getat $rem $locst[1] >>$loc; then - [[ $time = 1 ]] && zfrtime $loc $rem $remst[2] - else - stat=1 - fi - fi - fi - done - fi - done - - return $stat -} - -function zfclose { - zftp close -} - -function zfdir { - # Long directory of remote server. - # The remote directory is cached. In fact, two caches are kept: - # one of the standard listing of the current directory, i.e. zfdir - # with no arguments, and another for everything else. - # To access the appropriate cache, just use zfdir with the same - # arguments as previously. zfdir -r will also re-use the `everything - # else' cache; you can always reuse the current directory cache just - # with zfdir on its own. - # - # The current directory cache is emptied when the directory changes; - # the other is kept until a new zfdir with a non-empty argument list. - # Both are removed when the connection is closed. - # - # zfdir -f will force the existing cache to be ignored, e.g. if you know - # or suspect the directory has changed. - # zfdir -d will remove both caches without listing anything. - # If you need to pass -r, -f or -d to the dir itself, use zfdir -- -d etc. - - setopt localoptions unset - unsetopt shwordsplit ksharrays - - local file opt optlist redir i newargs force - - while [[ $1 = -* ]]; do - if [[ $1 = - || $1 = -- ]]; then - shift; - break; - fi - optlist=${1#-} - for (( i = 1; i <= $#optlist; i++)); do - opt=$optlist[$i] - case $optlist[$i] in - r) redir=1 - ;; - f) force=1 - ;; - d) [[ -n $zfcurdir && -f $zfcurdir ]] && rm -f $zfcurdir - [[ -n $zfotherdir && -f $zfotherdir ]] && rm -f $zfotherdir - zftp_fcache=() - return 0 - ;; - *) print option $opt not recognised >&2 - ;; - esac - done - shift - done - - # directory hack, see zfcd - for (( i = 1; i <= $#argv; i++ )); do - if [[ $argv[$i] = $HOME || $argv[$i] = $HOME/* ]]; then - argv[$i]="~${argv[$i]#$HOME}" - fi - done - - if [[ $# -eq 0 ]]; then - # Cache it in the current directory file. This means that repeated - # calls to zfdir with no arguments always use a cached file. - [[ -z $zfcurdir ]] && zfcurdir=${TMPPREFIX}zfcurdir$$ - file=$zfcurdir - else - # Last directly looked at was not the current one, or at least - # had non-standard arguments. - [[ -z $zfotherdir ]] && zfotherdir=${TMPPREFIX}zfotherdir$$ - file=$zfotherdir - newargs="$*" - if [[ -f $file && $redir != 1 && $force -ne 1 ]]; then - # Don't use the cached file if the arguments changed. - [[ $newargs = $zfotherargs ]] || rm -f $file - fi - zfotherargs=$newargs - fi - - if [[ $force -eq 1 ]]; then - rm -f $file - # if it looks like current directory has changed, better invalidate - # the filename cache, too. - (( $# == 0 )) && zftp_fcache=() - fi - - if [[ -n $file && -f $file ]]; then - eval ${PAGER:-more} \$file - else - zftp dir $* | tee $file | eval ${PAGER-:more} - fi -} - -function zfgcp { - # ZFTP get as copy: i.e. first arguments are remote, last is local. - # Supposed to work exactly like a normal copy otherwise, i.e. - # zfcp rfile lfile - # or - # zfcp rfile1 rfile2 rfile3 ... ldir - # Options: - # -G don't to remote globbing, else do - # -t update the local file times to the same time as the remote. - # Currently this only works if you have the `perl' command, - # and that perl is version 5 with the standard library. - # See the function zfrtime for more gory details. - - setopt localoptions - unsetopt shwordsplit - - local opt optlist nglob remlist rem loc stat=0 time - - while [[ $1 == -* ]]; do - if [[ $1 == - || $1 == -- ]]; then - shift; - break; - fi - optlist=${1#-} - for (( i = 1; i <= $#optlist; i++)); do - opt=$optlist[$i] - case $opt in - G) nglob=1 - ;; - t) time=1 - ;; - *) print option $opt not recognised >&2 - ;; - esac - done - shift - done - - # hmm, we should really check this after expanding the glob, - # but we shouldn't expand the last argument remotely anyway. - if [[ $# -gt 2 && ! -d $argv[-1] ]]; then - print "zfgcp: last argument must be a directory." 2>&1 - return 1 - elif [[ $# == 1 ]]; then - print "zfgcp: not enough arguments." 2>&1 - return 1 - fi - - if [[ -d $argv[-1] ]]; then - local dir=$argv[-1] - argv[-1]= - for remlist in $*; do - # zfcd directory hack to put the front back to ~ - if [[ $remlist = $HOME || $remlist = $HOME/* ]]; then - remlist="~${remlist#$HOME}" - fi - if [[ $nglob != 1 ]]; then - zfrglob remlist - fi - if (( $#remlist )); then - for rem in $remlist; do - loc=$dir/${rem:t} - if zftp get $rem >$loc; then - [[ $time = 1 ]] && zfrtime $rem $loc - else - stat=1 - fi - done - fi - done - else - zftp get $1 >$2 || stat=$? - fi - return $stat -} - -function zfget { - # Get files from remote server. Options: - # -G don't to remote globbing, else do - # -t update the local file times to the same time as the remote. - # Currently this only works if you have the `perl' command, - # and that perl is version 5 with the standard library. - # See the function zfrtime for more gory details. - - local loc rem stat=0 optlist opt nglob remlist time - - while [[ $1 == -* ]]; do - if [[ $1 == - || $1 == -- ]]; then - shift; - break; - fi - optlist=${1#-} - for (( i = 1; i <= $#optlist; i++)); do - opt=$optlist[$i] - case $opt in - G) nglob=1 - ;; - t) time=1 - ;; - *) print option $opt not recognised >&2 - ;; - esac - done - shift - done - - for remlist in $*; do - # zfcd directory hack to put the front back to ~ - if [[ $remlist == $HOME || $remlist == $HOME/* ]]; then - remlist="~${remlist#$HOME}" - fi - if [[ $nglob != 1 ]]; then - zfrglob remlist - fi - if (( $#remlist )); then - for rem in $remlist; do - loc=${rem:t} - if zftp get $rem >$loc; then - [[ $time = 1 ]] && zfrtime $rem $loc - else - stat=1 - fi - done - fi - done - - return $stat -} - -function zfget_match { - # the zfcd hack: this may not be necessary here - if [[ $1 == $HOME || $1 == $HOME/* ]]; then - 1="~${1#$HOME}" - fi - - - if [[ $ZFTP_SYSTEM == UNIX* && $1 == */* ]]; then - # On the first argument to ls, we usually get away with a glob. - reply=($(zftp ls "$1*$2")) - else - if (( $#zftp_fcache == 0 )); then - # Always cache the current directory and use it - # even if the system is UNIX. - zftp_fcache=($(zftp ls)) - fi - reply=($zftp_fcache); - fi -} - -function zfhere { - # Change to the directory corresponding to $PWD on the server. - # See zfcd for how this works. - zfcd $PWD -} - -function zfls { - # directory hack, see zfcd - if [[ $1 = $HOME || $1 = $HOME/* ]]; then - 1="~${1#$HOME}" - fi - zftp ls $* -} - -function zfopen { - # Use zftp params to set parameters for open, rather than sending - # them straight to open. That way they are stored for a future open - # command. - # - # With option -1 (just this 1ce), don't do that. - - local optlist opt once - - while [[ $1 = -* ]]; do - if [[ $1 = - || $1 = -- ]]; then - shift; - break; - fi - optlist=${1#-} - for (( i = 1; i <= $#optlist; i++)); do - opt=$optlist[$i] - case $optlist[$i] in - 1) once=1 - ;; - *) print option $opt not recognised >&2 - ;; - esac - done - shift - done - - # This is where we should try and do same name-lookupage in - # both .netrc and .ncftp/bookmarks . We could even try saving - # the info in their for new hosts, like ncftp does. - - if [[ $once = 1 ]]; then - zftp open $* - else - # set parameters, but only if there was at least a host - (( $# > 0 )) && zfparams $* - # now call with no parameters - zftp open - fi -} - -function zfparams { - # Set to prompt for any user or password if not given. - # Don't worry about accounts here. - if (( $# > 0 )); then - (( $# < 2 )) && 2='?' - (( $# < 3 )) && 3='?' - fi - zftp params $* -} - -function zfput { - # Simple put: dump every file under the same name, but stripping - # off any directory parts. - local loc rem stat=0 - for loc in $*; do - rem=${loc:t} - zftp put $rem <$loc - [[ $? == 0 ]] || stat=$? - done - return $stat -} - -function zfrglob { - # Do the remote globbing for zfput, etc. - # We have two choices: - # (1) Get the entire file list and match it one by one - # locally against the pattern. - # Causes problems if we are globbing directories (rare, presumably). - # But: we can cache the current directory, which - # we need for completion anyway. Works on any OS if you - # stick with a single directory. This is the default. - # (2) Use remote globbing, i.e. pass it to ls at the site. - # Faster, but only works with UNIX, and only basic globbing. - # We do this if $zfrglob is non-null. - - # There is only one argument, the variable containing the - # pattern to be globbed. We set this back to an array containing - # all the matches. - setopt localoptions unset - unsetopt ksharrays - - local pat dir nondir files i - - eval pat=\$$1 - - # Check if we really need to do anything. Look for standard - # globbing characters, and if extendedglob is set and we are - # using zsh for the actual pattern matching also look for - # extendedglob characters. - if [[ $remlist != *[][*?]* && - ( -n $zfrglob || ! -o extendedglob || $remlist != *[(|)~#^]* ) ]]; then - return 0 - fi - - if [[ $zfrglob != '' ]]; then - eval "$1=(\$(zftp ls \"$pat\" 2>/dev/null))" - else - if [[ $ZFTP_SYSTEM = UNIX* && $pat = */* ]]; then - # not the current directory and we know how to handle paths - if [[ $pat = ?*/* ]]; then - # careful not to remove too many slashes - dir=${pat%/*} - else - dir=/ - fi - nondir=${pat##*/} - files=($(zftp ls "$dir" 2>/dev/null)) - else - # we just have to do an ls and hope that's right - nondir=$pat - if (( $#zftp_fcache == 0 )); then - zftp_fcache=($(zftp ls)) - fi - files=($zftp_fcache) - fi - # now we want to see which of the $files match $nondir - for (( i = 1; i <= $#files; i++)); do - # empty words are elided in array assignment - [[ $files[$i] = ${~nondir} ]] || files[$i]='' - done - eval "$1=(\$files)" - fi -} - -function zfrtime { - # Set the modification time of file LOCAL to that of REMOTE. - # If the optional TIME is passed, it should be in the FTP format - # CCYYMMDDhhmmSS, i.e. no dot before the seconds, and in GMT. - # This is what both `zftp remote' and `zftp local' return. - # - # Unfortunately, since the time returned from FTP is GMT and - # your file needs to be set in local time, we need to do some - # hacking around with time. At the moment this requires perl 5 - # with the standard library. - - setopt localoptions unset - unsetopt ksharrays - - local time gmtime loctime - - if [[ -n $3 ]]; then - time=$3 - else - time=($(zftp remote $2 2>/dev/null)) - [[ -n $time ]] && time=$time[2] - fi - [[ -z $time ]] && return 1 - - # Now's the real *!@**!?!. We have the date in GMT and want to turn - # it into local time for touch to handle. It's just too nasty - # to handle in zsh; do it in perl. - if perl -mTime::Local -e '($file, $t) = @ARGV; - $yr = substr($t, 0, 4) - 1900; - $mon = substr($t, 4, 2) - 1; - $mday = substr($t, 6, 2) + 0; - $hr = substr($t, 8, 2) + 0; - $min = substr($t, 10, 2) + 0; - $sec = substr($t, 12, 2) + 0; - $time = Time::Local::timegm($sec, $min, $hr, $mday, $mon, $yr); - utime $time, $time, $file and return 0;' $1 $time 2>/dev/null; then - print "Setting time for $1 failed. Need perl 5." 2>1 - fi - - # If it wasn't for the GMT/local time thing, it would be this simple. - # - # time="${time[1,12]}.${time[13,14]}" - # - # touch -t $time $1 - -} - -function zfstat { - # Give a zftp status report using local variables. - # With option -v, connect the remote host and ask it what it - # thinks the status is. - - setopt localoptions unset - unsetopt ksharrays - - local i stat=0 opt optlist verbose - - while [[ $1 = -* ]]; do - if [[ $1 = - || $1 = -- ]]; then - shift; - break; - fi - optlist=${1#-} - for (( i = 1; i <= $#optlist; i++)); do - opt=$optlist[$i] - case $opt in - v) verbose=1 - ;; - *) print option $opt not recognised >&2 - ;; - esac - done - shift - done - - # hack: in case the status from a subshell process hasn't been - # fixed yet - zftp type >&/dev/null - - if [[ -n $ZFTP_HOST ]]; then - print "Host:\t\t$ZFTP_HOST" - print "IP:\t\t$ZFTP_IP" - [[ -n $ZFTP_SYSTEM ]] && print "System type:\t$ZFTP_SYSTEM" - if [[ -n $ZFTP_USER ]]; then - print "User:\t\t$ZFTP_USER " - [[ -n $ZFTP_ACCOUNT ]] && print "Account:\t$AFTP_ACCOUNT" - print "Directory:\t$ZFTP_PWD" - print -n "Transfer type:\t" - if [[ $ZFTP_TYPE = "I" ]]; then - print Image - elif [[ $ZFTP_TYPE = "A" ]]; then - print Ascii - else - print Unknown - fi - print -n "Transfer mode:\t" - if [[ $ZFTP_MODE = "S" ]]; then - print Stream - elif [[ $ZFTP_MODE = "B" ]]; then - print Block - else - print Unknown - fi - else - print "No user logged in." - fi - else - print "Not connected." - stat=1 - fi - - # things which may be set even if not connected: - [[ -n $ZFTP_REPLY ]] && print "Last reply:\t$ZFTP_REPLY" - print "Verbosity:\t$ZFTP_VERBOSE" - print -n "Preferences:\t" - for (( i = 1; i <= ${#ZFTP_PREFS}; i++ )); do - case $ZFTP_PREFS[$i] in - [pP]) print -n "Passive " - ;; - [sS]) print -n "Sendport " - ;; - [dD]) print -n "Dumb " - ;; - *) print -n "$ZFTP_PREFS[$i]???" - esac - done - print - - if [[ -n $ZFTP_HOST && $verbose = 1 ]]; then - print "Status of remote server:" - # make sure we print the reply - local ZFTP_VERBOSE=045 - zftp quote STAT - fi - - return $stat -} - -function zftp_chpwd { - # You may want to alter chpwd to call this when $ZFTP_USER is set. - # If so, call it with a non-zero first argument so it doesn't - # print the new FTP directory. - - # Cancel the filename cache for the current directory. - zftp_fcache=() - # ...and also empty the stored directory listing cache. - # As this function is called when we close the connection, this - # is the only place we need to do these two things. - [[ -n $zfcurdir && -f $zfcurdir ]] && rm -f $zfcurdir - - if [[ -z $ZFTP_USER ]]; then - # last call, after an FTP logout - - # delete the non-current cached directory - [[ -n $zfotherdir && -f $zfotherdir ]] && rm -f $zfotherdir - zfotherargs= - - # don't keep zflastdir between opens - zflastdir= - - # return the display to standard - # uncomment the following line if you have a chpwd which shows directories - # chpwd - else - [[ -z $zflastdir ]] && zflastdir=$ZFTP_PWD - local args - if [[ -t 1 && -t 2 ]]; then - local str="$ZFTP_HOST:$ZFTP_PWD" - [[ -z $1 ]] && print $str - [[ ${#str} -lt 70 ]] && str="%m: %~ $str" - case $TERM in - sun-cmd) print -n -P "\033]l$str\033\\" - ;; - xterm) print -n -P "\033]2;$str\a" - ;; - esac - fi - fi -} - -function zftp_progress { - # Basic progress metre, showing the percent of the file transferred. - # You want growing bars? You gotta write growing bars. - - # Don't show progress unless stderr is a terminal - [[ ! -t 2 ]] && return 0 - - if [[ $ZFTP_TRANSFER = *F ]]; then - print 1>&2 - elif [[ -n $ZFTP_TRANSFER ]]; then - if [[ -n $ZFTP_SIZE ]]; then - local frac="$(( ZFTP_COUNT * 100 / ZFTP_SIZE ))%" - print -n "\r$ZFTP_FILE ($ZFTP_SIZE bytes): $ZFTP_TRANSFER $frac" 1>&2 - else - print -n "\r$ZFTP_FILE: $ZFTP_TRANSFER $ZFTP_COUNT" 1>&2 - fi - fi -} - -function zftype { - local type - - if (( $# == 0 )); then - type=$(zftp type) - if [[ $type = I ]]; then - print "Current type is image (binary)" - return 0 - elif [[ $type = A ]]; then - print "Current type is ASCII" - return 0 - else - return 1 - fi - else - if [[ $1 == [aA]([sS][cC]([iI][iI]|)|) ]]; then - type=A - elif [[ $1 == [iI]([mM]([aA][gG][eE]|)|) || - $1 == [bB]([iI][nN]([aA][rR][yY]|)|) ]]; then - type=I - else - print "Type not recognised: $1" 2>&1 - return 1 - fi - zftp type $type - fi -} - -function zfuget { - # Get a list of files from the server with update. - # In other words, only retrieve files which are newer than local - # ones. This depends on the clocks being adjusted correctly - # (i.e. if one is fifteen minutes out, for the next fifteen minutes - # updates may not be correctly calculated). However, difficult - # cases --- where the files are the same size, but the remote is newer, - # or have different sizes, but the local is newer -- are prompted for. - # - # Files are globbed on the remote host --- assuming, of course, they - # haven't already been globbed local, so use 'noglob' e.g. as - # `alias zfuget="noglob zfuget"'. - # - # Options: - # -G Glob: turn off globbing - # -v verbose: print more about the files listed. - # -s silent: don't ask, just guess. The guesses are: - # - if the files have different sizes but remote is older ) grab - # - if they have the same size but remote is newer ) - # which is safe if the remote files are always the right ones. - # -t time: update the local file times to the same time as the remote. - # Currently this only works if you have the `perl' command, - # and that perl is version 5 with the standard library. - # See the function zfrtime for more gory details. - - setopt localoptions - unsetopt ksharrays shwordsplit - - local loc rem stat=0 locstats remstats doit tmpfile=${TMPPREFIX}zfuget$$ - local rstat remlist verbose optlist opt bad i silent nglob time - - zfuget_print_time() { - local tim=$1 - print -n "$tim[1,4]/$tim[5,6]/$tim[7,8] $tim[9,10]:$tim[11,12].$tim[13,14]" - print -n GMT - } - - zfuget_print () { - print -n "\nremote $rem (" - zfuget_print_time $remstats[2] - print -n ", $remstats[1] bytes)\nlocal $loc (" - zfuget_print_time $locstats[2] - print ", $locstats[1] bytes)" - } - - while [[ $1 = -* ]]; do - if [[ $1 = - || $1 = -- ]]; then - shift; - break; - fi - optlist=${1#-} - for (( i = 1; i <= $#optlist; i++)); do - opt=$optlist[$i] - case $optlist[$i] in - v) verbose=1 - ;; - s) silent=1 - ;; - G) nglob=1 - ;; - t) time=1 - ;; - *) print option $opt not recognised >&2 - ;; - esac - done - shift - done - - [[ -n $bad ]] && return 1 - - for remlist in $*; do - # zfcd directory hack to put the front back to ~ - if [[ $remlist == $HOME || $remlist == $HOME/* ]]; then - remlist="~${remlist#$HOME}" - fi - if [[ $nglob != 1 ]]; then - zfrglob remlist - fi - if (( $#remlist )); then - for rem in $remlist; do - loc=${rem:t} - doit=y - remstats=() - if [[ -f $loc ]]; then - zftp local $loc >$tmpfile - locstats=($(<$tmpfile)) - zftp remote $rem >$tmpfile - rstat=$? - remstats=($(<$tmpfile)) - rm -f $tmpfile - if [[ $rstat = 2 ]]; then - print "Server does not implement full command set required." 1>&2 - return 1 - elif [[ $rstat = 1 ]]; then - print "File not found on server: $rem" 1>&2 - stat=1 - continue - fi - [[ $verbose = 1 ]] && zfuget_print - if (( $locstats[1] != $remstats[1] )); then - # Files have different sizes - if [[ $locstats[2] > $remstats[2] && $silent != 1 ]]; then - [[ $verbose != 1 ]] && zfuget_print - print "Local file $loc more recent than remote," 1>&2 - print -n "but sizes are different. Transfer anyway [y/n]? " 1>&2 - read -q doit - fi - else - # Files have same size - if [[ $locstats[2] < $remstats[2] ]]; then - if [[ $silent != 1 ]]; then - [[ $verbose != 1 ]] && zfuget_print - print "Local file $loc has same size as remote," 1>&2 - print -n "but local file is older. Transfer anyway [y/n]? " 1>&2 - read -q doit - fi - else - # presumably same file, so don't get it. - [[ $verbose = 1 ]] && print Not transferring - doit=n - fi - fi - else - [[ $verbose = 1 ]] && print New file $loc - fi - if [[ $doit = y ]]; then - if zftp get $rem >$loc; then - if [[ $time = 1 ]]; then - # if $remstats is set, it's second element is the remote time - zfrtime $loc $rem $remstats[2] - fi - else - stat=$? - fi - - fi - done - fi - done - return $stat -} - -function zfuput { - # Put a list of files from the server with update. - # See zfuget for details. - # - # Options: - # -v verbose: print more about the files listed. - # -s silent: don't ask, just guess. The guesses are: - # - if the files have different sizes but remote is older ) grab - # - if they have the same size but remote is newer ) - # which is safe if the remote files are always the right ones. - - setopt localoptions - unsetopt ksharrays shwordsplit - - local loc rem stat=0 locstats remstats doit tmpfile=${TMPPREFIX}zfuput$$ - local rstat verbose optlist opt bad i silent - - zfuput_print_time() { - local tim=$1 - print -n "$tim[1,4]/$tim[5,6]/$tim[7,8] $tim[9,10]:$tim[11,12].$tim[13,14]" - print -n GMT - } - - zfuput_print () { - print -n "\nremote $rem (" - zfuput_print_time $remstats[2] - print -n ", $remstats[1] bytes)\nlocal $loc (" - zfuput_print_time $locstats[2] - print ", $locstats[1] bytes)" - } - - while [[ $1 = -* ]]; do - if [[ $1 = - || $1 = -- ]]; then - shift; - break; - fi - optlist=${1#-} - for (( i = 1; i <= $#optlist; i++)); do - opt=$optlist[$i] - case $optlist[$i] in - v) verbose=1 - ;; - s) silent=1 - ;; - *) print option $opt not recognised >&2 - ;; - esac - done - shift - done - - [[ -n $bad ]] && return 1 - - if [[ $ZFTP_VERBOSE = *5* ]]; then - # should we turn it off locally? - print "Messages with code 550 are harmless." >&2 - fi - - for loc in $*; do - rem=${loc:t} - doit=y - remstats=() - if [[ ! -f $loc ]]; then - print "$loc: file not found" >&2 - stat=1 - continue - fi - zftp local $loc >$tmpfile - locstats=($(<$tmpfile)) - zftp remote $rem >$tmpfile - rstat=$? - remstats=($(<$tmpfile)) - rm -f $tmpfile - if [[ $rstat = 2 ]]; then - print "Server does not implement full command set required." 1>&2 - return 1 - elif [[ $rstat = 1 ]]; then - [[ $verbose = 1 ]] && print New file $loc - else - [[ $verbose = 1 ]] && zfuput_print - if (( $locstats[1] != $remstats[1] )); then - # Files have different sizes - if [[ $locstats[2] < $remstats[2] && $silent != 1 ]]; then - [[ $verbose != 1 ]] && zfuput_print - print "Remote file $rem more recent than local," 1>&2 - print -n "but sizes are different. Transfer anyway [y/n]? " 1>&2 - read -q doit - fi - else - # Files have same size - if [[ $locstats[2] > $remstats[2] ]]; then - if [[ $silent != 1 ]]; then - [[ $verbose != 1 ]] && zfuput_print - print "Remote file $rem has same size as local," 1>&2 - print -n "but remote file is older. Transfer anyway [y/n]? " 1>&2 - read -q doit - fi - else - # presumably same file, so don't get it. - [[ $verbose = 1 ]] && print Not transferring - doit=n - fi - fi - fi - if [[ $doit = y ]]; then - zftp put $rem <$loc || stat=$? - fi - done - return $stat -} |