about summary refs log tree commit diff
path: root/Functions
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-06-08 09:26:01 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-06-08 09:26:01 +0000
commitfcd7cd1cfa2ba286f4bf73da7a60116cd3912629 (patch)
treed2aa5a9369bf3af8841d3abde69f52bd483f5526 /Functions
parentb39cafaa22ad7efc2ac4b64a5eeac8f49bc80e00 (diff)
downloadzsh-fcd7cd1cfa2ba286f4bf73da7a60116cd3912629.tar.gz
zsh-fcd7cd1cfa2ba286f4bf73da7a60116cd3912629.tar.xz
zsh-fcd7cd1cfa2ba286f4bf73da7a60116cd3912629.zip
Initial revision
Diffstat (limited to 'Functions')
-rw-r--r--Functions/Makefile.in86
-rw-r--r--Functions/Misc/.distfiles6
-rwxr-xr-xFunctions/Misc/acx6
-rw-r--r--Functions/Misc/allopt29
-rw-r--r--Functions/Misc/cat16
-rwxr-xr-xFunctions/Misc/cdmatch23
-rw-r--r--Functions/Misc/cdmatch215
-rw-r--r--Functions/Misc/checkmail26
-rwxr-xr-xFunctions/Misc/cx6
-rw-r--r--Functions/Misc/harden6
-rw-r--r--Functions/Misc/mere3
-rwxr-xr-xFunctions/Misc/multicomp72
-rwxr-xr-xFunctions/Misc/proto8
-rw-r--r--Functions/Misc/pushd13
-rwxr-xr-xFunctions/Misc/randline3
-rw-r--r--Functions/Misc/run-help72
-rwxr-xr-xFunctions/Misc/yp2
-rwxr-xr-xFunctions/Misc/yu2
-rw-r--r--Functions/Misc/zed65
-rw-r--r--Functions/Misc/zless37
-rw-r--r--Functions/Misc/zls72
-rw-r--r--Functions/README.zftp4
-rw-r--r--Functions/Zftp/.distfiles7
23 files changed, 579 insertions, 0 deletions
diff --git a/Functions/Makefile.in b/Functions/Makefile.in
new file mode 100644
index 000000000..d6344dd62
--- /dev/null
+++ b/Functions/Makefile.in
@@ -0,0 +1,86 @@
+#
+# Makefile for Functions subdirectory
+#
+# Copyright (c) 1999 Peter Stephensons
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and to distribute modified versions of this software for any
+# purpose, provided that the above copyright notice and the following
+# two paragraphs appear in all copies of this software.
+#
+# In no event shall Peter Stephenson or the Zsh Development Group be liable
+# to any party for direct, indirect, special, incidental, or consequential
+# damages arising out of the use of this software and its documentation,
+# even if Peter Stephenson and the Zsh Development Group have been advised of
+# the possibility of such damage.
+#
+# Peter Stephenson and the Zsh Development Group specifically disclaim any
+# warranties, including, but not limited to, the implied warranties of
+# merchantability and fitness for a particular purpose.  The software
+# provided hereunder is on an "as is" basis, and Peter Stephenson and the
+# Zsh Development Group have no obligation to provide maintenance,
+# support, updates, enhancements, or modifications.
+#
+
+subdir = Functions
+dir_top = ..
+SUBDIRS =
+
+@VERSION_MK@
+
+# source/build directories
+VPATH           = @srcdir@
+sdir            = @srcdir@
+sdir_top        = @top_srcdir@
+INSTALL         = @INSTALL@
+
+@DEFS_MK@
+
+# ========== DEPENDENCIES FOR BUILDING ==========
+
+all:
+
+# ========== DEPENDENCIES FOR INSTALLING ==========
+
+install: install.fns
+
+uninstall: uninstall.fns
+
+# install functions, including those in subdirectories, creating
+# install directory if necessary
+install.fns:
+	if test x$(fndir) != x && test x$(fndir) != xno; then \
+	  $(sdir_top)/mkinstalldirs $(fndir) || exit 1; \
+	  for file in $(FUNCTIONS_INSTALL); do \
+	    if test -f $$file; then \
+	      $(INSTALL_DATA) $$file $(fndir) || exit 1; \
+	    fi; \
+	  done; \
+	fi; \
+	exit 0
+
+uninstall.fns:
+	if test x$(fndir) != x && test x$(fndir) != xno; then \
+	  for file in $(FUNCTIONS_INSTALL); do \
+	    if test -f $$file; then \
+	      rm -f "$(fndir)/`echo $$file | sed -e 's%^.*/%%'`"; \
+	    fi; \
+	  done; \
+	fi; \
+	exit 0
+
+# ========== DEPENDENCIES FOR CLEANUP ==========
+
+@CLEAN_MK@
+
+mostlyclean-here:
+
+distclean-here:
+
+realclean-here:
+
+# ========== DEPENDENCIES FOR MAINTENANCE ==========
+
+@CONFIG_MK@
diff --git a/Functions/Misc/.distfiles b/Functions/Misc/.distfiles
new file mode 100644
index 000000000..eab3626b6
--- /dev/null
+++ b/Functions/Misc/.distfiles
@@ -0,0 +1,6 @@
+DISTFILES_SRC='
+    .distfiles
+    acx allopt cat cdmatch cdmatch2 checkmail cx harden mere multicomp
+    proto pushd randline run-help yp yu zed zless zls
+'
+
diff --git a/Functions/Misc/acx b/Functions/Misc/acx
new file mode 100755
index 000000000..f7c680bb0
--- /dev/null
+++ b/Functions/Misc/acx
@@ -0,0 +1,6 @@
+#! /bin/sh
+#
+# zsh shell function to make its arguments 755
+# also works as an sh script
+#
+chmod 755 $*
diff --git a/Functions/Misc/allopt b/Functions/Misc/allopt
new file mode 100644
index 000000000..604e76198
--- /dev/null
+++ b/Functions/Misc/allopt
@@ -0,0 +1,29 @@
+# This function lists options with the no's in front removed for
+# improved comprehension, i.e. `norcs off' becomes `rcs on'.
+# The format is otherwise like that with `kshoptionprint' set,
+# i.e. you can see all options whether on or off.
+# It can take a list of option names or parts thereof to search for
+# via egrep.
+#
+# Written by Sweth Chandramouli with hacks by Bart Schaefer.
+
+listalloptions () {
+   emulate -R zsh
+   builtin setopt localoptions kshoptionprint
+   local OPT_NAME OPT_PAIR OPT_VALUE
+   for OPT_PAIR in "${(f)$(builtin setopt)}" ; do
+      OPT_VALUE=${OPT_PAIR##* }
+      OPT_NAME=${OPT_PAIR%% *}
+      if [[ ${OPT_NAME#no} != ${OPT_NAME} ]] ; then
+         OPT_VALUE=${(L)${${OPT_VALUE:s/on/OFF}:s/off/on}} &&
+            OPT_NAME=${OPT_NAME#no};
+      fi;
+      echo ${(r:21:)OPT_NAME} ${OPT_VALUE}
+   done
+}
+
+if [[ -n $@ ]]; then
+    listalloptions | egrep "${(j.|.)@}"
+else
+    listalloptions
+fi
diff --git a/Functions/Misc/cat b/Functions/Misc/cat
new file mode 100644
index 000000000..612deac03
--- /dev/null
+++ b/Functions/Misc/cat
@@ -0,0 +1,16 @@
+#! /usr/local/bin/zsh -f
+
+local file
+
+if ((! ARGC)) then
+	set -- -
+fi
+
+for file
+do
+	if [[ "$file" == - ]] then
+		while read -u0ek 4096; do ; done
+	else
+		while read -u0ek 4096; do ; done < "$file"
+	fi
+done
diff --git a/Functions/Misc/cdmatch b/Functions/Misc/cdmatch
new file mode 100755
index 000000000..7c4bb9ae7
--- /dev/null
+++ b/Functions/Misc/cdmatch
@@ -0,0 +1,23 @@
+# Start of cdmatch.
+# Save in your functions directory and autoload, then do
+# compctl -x 'S[/][~][./][../]' -g '*(-/)' - \
+#         'n[-1,/], s[]' -K cdmatch -S '/' -- cd pushd
+#
+# Completes directories for cd, pushd, ... anything which knows about cdpath.
+# You do not have to include `.' in your cdpath.
+#
+# It works properly only if $ZSH_VERSION > 3.0-pre4.  Remove `emulate -R zsh'
+# for all other values of $ZSH_VERSION > 2.6-beta2. For earlier versions
+# it still works if RC_EXPAND_PARAM is not set or when cdpath is empty.
+emulate -R zsh
+setopt localoptions
+local narg pref cdp
+
+read -nc narg
+read -Ac pref
+
+cdp=(. $cdpath)
+reply=( ${^cdp}/${pref[$narg]%$2}*$2(-/DN^M:t) )
+
+return
+# End of cdmatch.
diff --git a/Functions/Misc/cdmatch2 b/Functions/Misc/cdmatch2
new file mode 100644
index 000000000..8a3e9591f
--- /dev/null
+++ b/Functions/Misc/cdmatch2
@@ -0,0 +1,15 @@
+# This function should be called from compctl to complete the
+# second argument of cd and pushd.
+
+emulate -R zsh				# Requires zsh 3.0-pre4 or later
+setopt localoptions extendedglob
+local from
+
+read -Ac from
+from="${from[2]}"
+
+eval "reply=( \${PWD:s@$from@$1*$2@}~$PWD(ND-/:) )"
+reply=( "${${reply[@]#${PWD%%$from*}}%${PWD#*$from}}" )
+[[ ${#reply[(r),-1]} != 0 ]] && reply[(r)]="''"
+
+return
diff --git a/Functions/Misc/checkmail b/Functions/Misc/checkmail
new file mode 100644
index 000000000..9cc743db4
--- /dev/null
+++ b/Functions/Misc/checkmail
@@ -0,0 +1,26 @@
+#! /usr/local/bin/zsh
+#
+# This autoloadable function checks the folders specified as arguments
+# for new mails.  The arguments are interpeted in exactly the same way
+# as the mailpath special zsh parameter (see zshparam(1)).
+#
+# If no arguments are given mailpath is used.  If mailpath is empty, $MAIL
+# is used and if that is also empty, /var/spool/mail/$LOGNAME is used.
+# This function requires zsh-3.0.1 or newer.
+#
+
+local file message
+
+for file in "${@:-${mailpath[@]:-${MAIL:-/var/spool/mail/$LOGNAME}}}"
+do
+	message="${${(M)file%%\?*}#\?}"
+	file="${file%%\?*}"
+	if [[ -d "$file" ]] then
+		file=( "$file"/**/*(.ND) )
+		if (($#file)) then
+			checkmail "${^file}\?$message"
+		fi
+	elif test -s "$file" -a -N "$file"; then  # this also sets $_ to $file
+		print -r -- "${(e)message:-You have new mail.}"
+	fi
+done
diff --git a/Functions/Misc/cx b/Functions/Misc/cx
new file mode 100755
index 000000000..a0b34a4f0
--- /dev/null
+++ b/Functions/Misc/cx
@@ -0,0 +1,6 @@
+#! /bin/sh
+#
+# zsh shell function to make its arguments executable
+# also works as a sh script
+#
+chmod +x $*
diff --git a/Functions/Misc/harden b/Functions/Misc/harden
new file mode 100644
index 000000000..c02689362
--- /dev/null
+++ b/Functions/Misc/harden
@@ -0,0 +1,6 @@
+#! /bin/sh
+# harden a link (convert it to a singly linked file)
+cp $1 $1.foo
+rm $1
+mv $1.foo $1
+
diff --git a/Functions/Misc/mere b/Functions/Misc/mere
new file mode 100644
index 000000000..cf8d8ad14
--- /dev/null
+++ b/Functions/Misc/mere
@@ -0,0 +1,3 @@
+#! /bin/sh
+# read a man page in the current directory
+nroff -man -Tman $1 | less -s
diff --git a/Functions/Misc/multicomp b/Functions/Misc/multicomp
new file mode 100755
index 000000000..c28558d95
--- /dev/null
+++ b/Functions/Misc/multicomp
@@ -0,0 +1,72 @@
+# multicomp() {
+# Completes all manner of files given prefixes for each path segment.
+# e.g. s/z/s -> src/zsh-2.4/src
+#
+# Usage: e.g.
+# compctl -D -f + -U -Q -S '' -K multicomp
+#
+# Will expand glob patterns already in the word, but use complete-word,
+# not TAB (expand-or-complete), or you will get ordinary glob expansion.
+# Requires the -U option to compctl.
+# Menucompletion is highly recommended for ambiguous matches.
+# Liable to screw up escaped metacharacters royally.
+# $fignore is not used: feel free to add your own bit.
+
+emulate -R zsh				# Requires zsh 3.0-pre4 or later
+local pref head sofar origtop newtop globdir="(-/)" wild
+setopt localoptions nullglob rcexpandparam globdots
+unsetopt markdirs globsubst shwordsplit nounset
+
+pref="${1}$2"
+# Hack to allow programmable completion to select multicomp after a :
+# (e.g.
+# compctl -D -f -x 's[:]' -U -Q -S '' -K multicomp
+# )
+pref="${pref#:}"
+
+sofar=('')
+reply=('')
+
+if [[ "$pref" = \~* ]]; then
+  # If the string started with ~, save the head and what it will become.
+  origtop="${pref%%/*}"
+  eval "newtop=$origtop"
+  # Save the expansion as the bit matched already
+  sofar=($newtop)
+  pref="${pref#$origtop}"
+fi
+
+while [[ -n "$pref" ]]; do
+  [[ "$pref" = /* ]] && sofar=(${sofar}/) && pref="${pref#/}"
+  head="${pref%%/*}"
+  pref="${pref#$head}"
+  [[ -z "$pref" ]] && globdir=
+  # if path segment contains wildcards, don't add another.
+  if [[ "$head" = *[\[\(\*\?\$\~]* ]]; then
+    wild=$head
+  else
+    # Simulate case-insensitive globbing for ASCII characters
+    wild="[${(j(][))${(s())head:l}}]*"	# :gs/a/[a]/ etc.
+    # The following could all be one expansion, but for readability:
+    wild=$wild:gs/a/aA/:gs/b/bB/:gs/c/cC/:gs/d/dD/:gs/e/eE/:gs/f/fF/
+    wild=$wild:gs/g/gG/:gs/h/hH/:gs/i/iI/:gs/j/jJ/:gs/k/kK/:gs/l/lL/
+    wild=$wild:gs/m/mM/:gs/n/nN/:gs/o/oO/:gs/p/pP/:gs/q/qQ/:gs/r/rR/
+    wild=$wild:gs/s/sS/:gs/t/tT/:gs/u/uU/:gs/v/vV/:gs/w/wW/:gs/x/xX/
+    wild=$wild:gs/y/yY/:gs/z/zZ/:gs/-/_/:gs/_/-_/:gs/[]//
+
+    # Expand on both sides of '.' (except when leading) as for '/'
+    wild="${${wild:gs/[.]/*.*/}#\*}"
+  fi
+
+  reply=(${sofar}"${wild}${globdir}")
+  reply=(${~reply})
+
+  [[ -z $reply[1] ]] && reply=() && break
+  [[ -n $pref ]] && sofar=($reply)
+done
+
+# Restore ~'s in front if there were any.
+# There had better not be anything funny in $newtop.
+[[ -n "$origtop" ]] && reply=("$origtop"${reply#$newtop})
+
+# }
diff --git a/Functions/Misc/proto b/Functions/Misc/proto
new file mode 100755
index 000000000..df1826506
--- /dev/null
+++ b/Functions/Misc/proto
@@ -0,0 +1,8 @@
+#! /bin/sh
+# generate prototypes, if your style is the same as mine
+for i
+do
+	rm $i:r.pro 2>/dev/null
+	grep -v '[{};:#]' $i | grep '^[A-Za-z]' |
+		grep -v static | sed 's/$/;/' >! $i:r.pro
+done
diff --git a/Functions/Misc/pushd b/Functions/Misc/pushd
new file mode 100644
index 000000000..965c774bf
--- /dev/null
+++ b/Functions/Misc/pushd
@@ -0,0 +1,13 @@
+# pushd function to emulate the old zsh behaviour.  With this function
+# pushd +/-n just lifts the selected element to the top of the stack
+# instead of just cycling the stack.
+
+emulate -R zsh
+setopt localoptions
+
+if [[ ARGC -eq 1 && "$1" == [+-]<-> ]] then
+	setopt pushdignoredups
+	builtin pushd ~$1
+else
+	builtin pushd "$@"
+fi
diff --git a/Functions/Misc/randline b/Functions/Misc/randline
new file mode 100755
index 000000000..7b06b7982
--- /dev/null
+++ b/Functions/Misc/randline
@@ -0,0 +1,3 @@
+# get a random line from a file
+integer z="$(wc -l <$1)"
+sed -n $[RANDOM%z+1]p $1
diff --git a/Functions/Misc/run-help b/Functions/Misc/run-help
new file mode 100644
index 000000000..a8109e3ea
--- /dev/null
+++ b/Functions/Misc/run-help
@@ -0,0 +1,72 @@
+#!/usr/local/bin/zsh
+#
+# Figure out where to get the best help, and get it.
+#
+# Install this function by placing it in your FPATH and then
+# adding to your .zshrc the lines:
+#	unalias run-help
+#	autoload run-help
+#
+
+emulate -R zsh
+setopt localoptions
+
+# Check whether Util/helpfiles has been used to generate zsh help
+if [[ $1 == "-l" ]]
+then
+    if [[ -n "${HELPDIR:-}" ]]
+    then
+	echo 'Here is a list of topics for which help is available:'
+	echo ""
+	print -rc $HELPDIR/*(:t)
+    else
+	echo 'There is no list of help topics available at this time'
+    fi
+    return 0
+elif [[ -n "${HELPDIR:-}" && -r $HELPDIR/$1 && $1 != compctl ]]
+then
+    ${=PAGER:-more} $HELPDIR/$1
+    return $?
+fi
+
+# No zsh help, use "whence" to figure out where else we might look
+local what places newline='
+'
+integer i=0 didman=0
+
+places=( "${(@f)$(builtin whence -va $1)}" )
+
+while ((i++ < $#places))
+do
+    what=$places[$i]
+    builtin print -r $what
+    case $what in
+    (*( is an alias)*)
+	[[ ${what[(w)6]:t} != ${what[(w)1]} ]] && run-help ${what[(w)6]:t}
+	;;
+    (*( is a * function))
+	builtin functions ${what[(w)1]} | ${=PAGER:-more}
+	;;
+    (*( is a * builtin))
+	case ${what[(w)1]} in
+	(compctl) man zshcompctl;;
+	(bindkey) man zshzle;;
+	(*setopt) man zshoptions;;
+	(*) man zshbuiltins;;
+	esac
+	;;
+    (*( is hashed to *))
+	man ${what[(w)-1]:t}
+	;;
+    (*)
+	((! didman++)) && man $1
+	;;
+    esac
+    if ((i < $#places && ! didman))
+    then
+	builtin print -nP "%SPress any key for more help or q to quit%s"
+	builtin read -k what
+	[[ $what != $newline ]] && echo
+	[[ $what == [qQ] ]] && break
+    fi
+done
diff --git a/Functions/Misc/yp b/Functions/Misc/yp
new file mode 100755
index 000000000..7e09613ef
--- /dev/null
+++ b/Functions/Misc/yp
@@ -0,0 +1,2 @@
+#! /bin/sh
+ypmatch $1 passwd
diff --git a/Functions/Misc/yu b/Functions/Misc/yu
new file mode 100755
index 000000000..3c5f170cf
--- /dev/null
+++ b/Functions/Misc/yu
@@ -0,0 +1,2 @@
+#! /bin/sh
+ypmatch $1 passwd.byuid
diff --git a/Functions/Misc/zed b/Functions/Misc/zed
new file mode 100644
index 000000000..e8e7212ef
--- /dev/null
+++ b/Functions/Misc/zed
@@ -0,0 +1,65 @@
+#
+# zed
+#
+# No other shell could do this.
+# Edit small files with the command line editor.
+# Use ^X^W to save, ^C to abort.
+# Option -f: edit shell functions.  (Also if called as fned.)
+#
+# Completion: use
+# compctl -f -x 'w[1,-f]' -F -- zed
+#
+
+local var fun cleanup
+# We do not want timeout while we are editing a file
+integer TMOUT=0
+
+[[ $1 = -f || $0 = fned ]] && fun=1
+[[ $1 = -(|-|f) ]] && shift
+
+[[ -z "$1" ]] && echo 'Usage: "zed filename" or "zed -f function"' && return 1
+
+# catch interrupts
+cleanup="$(bindkey -L "^M"; bindkey -L -M emacs "^X^W"; bindkey -aL "ZZ"
+    echo "trap - INT EXIT"; trap)"
+trap "return 130" INT
+trap "$cleanup" EXIT
+
+# don't mangle !'s
+setopt localoptions nobanghist
+
+bindkey "^M" self-insert-unmeta
+# Depending on your stty's, you may be able to use ^J as accept-line, else:
+bindkey -M emacs "^X^W" accept-line
+bindkey -a "ZZ" accept-line
+
+if ((fun)) then
+  var="$(functions $1)"
+  # If function is undefined but autoloadable, load it
+  if [[ $var = undefined* ]] then
+    local dir
+    for dir in $fpath; do
+      if [[ -f $dir/$1 ]] then
+	var="$1() {
+$(<$dir/$1)
+}"
+	break
+      fi
+    done
+  elif [[ -z $var ]] then
+    var="$1() {
+}"
+  fi
+  vared var && eval function "$var"
+else
+  [[ -f $1 ]] && var="$(<$1)"
+  while vared var
+  do
+    (print -r -- "$var" >| $1) && break
+    echo -n -e '\a'
+  done
+fi
+
+return 0
+
+# End of zed
diff --git a/Functions/Misc/zless b/Functions/Misc/zless
new file mode 100644
index 000000000..809ce35c7
--- /dev/null
+++ b/Functions/Misc/zless
@@ -0,0 +1,37 @@
+#!/usr/bin/zsh -f
+#
+# zsh function script to run less on various inputs, decompressing as required.
+# Author: Phil Pennock.  zsh-hacks@athenaeum.demon.co.uk
+# Modified by Bart Schaefer.
+# Thanks to zefram@fysh.org for a great deal of help in sorting this out,
+# ie wrt syntax for unsetting members of arrays and eval "$(...)" when I
+# asked for something better than . =(...)
+#
+# Use -zforce to pass through a display-formatting command
+#  zless -zforce 'bzip2 -dc' foo-no-dotbz2
+#  zless -zforce 'od -hc' foo-binfile
+#
+# If you can understand all of this without reference to zshexpn(1)
+# and zshparam(1) then you either have a photographic memory or you
+# need to get out more.
+#
+
+emulate -R zsh
+setopt localoptions
+
+[[ $# -ge 1 ]] || return
+local lessopts
+set -A lessopts
+integer i=1 loi=1
+while ((i <= $#))
+do
+  case $argv[i] in
+  -zforce) argv[i,i+2]=("=($argv[i+1] \"$argv[i+2]\")"); ((++i));;
+  -*) lessopts[loi++]=\"$argv[i]\"; argv[i]=(); continue;;
+  *.(gz|Z)) argv[i]="=(zcat \"$argv[i]\")";;
+  *.bz2) argv[i]="=(bzip2 -dc \"$argv[i]\")";;
+  *.bz) argv[i]="=(bzip -dc \"$argv[i]\")";;
+  esac
+  ((++i))
+done
+eval command less $lessopts $*
diff --git a/Functions/Misc/zls b/Functions/Misc/zls
new file mode 100644
index 000000000..22138cd6c
--- /dev/null
+++ b/Functions/Misc/zls
@@ -0,0 +1,72 @@
+# zls () {
+# simple internal ls using the stat module
+
+zmodload -i stat || return 1
+
+emulate -R zsh
+setopt localoptions
+
+local f opts='' L=L mod=: dirs list
+typeset -A stat
+
+dirs=()
+list=()
+
+while getopts ailLFdtuc f
+do
+    opts=$opts$f
+    if [[ $f == '?' ]] then
+	echo Usage: $0 [ -ailLFd ] [ filename ... ]
+	return 1
+    fi
+done
+shift OPTIND-1
+
+[[ $opts == *L* ]] && L=''
+[[ $opts == *F* ]] && mod=T$mod
+[[ $opts == *a* ]] && setopt globdots
+
+local time=mtime tmod=m
+[[ $opts == *u* ]] && time=atime tmod=a
+[[ $opts == *c* ]] && time=ctime tmod=c
+
+if ((! ARGC)) then
+    if [[ $opts = *t* ]]; then
+        set *(o$tmod)
+    else
+        set *
+    fi
+    opts=d$opts
+elif [[ $opts = *t* && $ARGC -gt 1 ]]; then
+    # another glaringly obvious zsh trick:  reorder the argv list
+    # by time, without messing up metacharacters inside
+    local n='$1'
+    for (( f = 2; f <= $ARGC; f++ )); do
+	n="$n|\$$f"
+    done
+    eval "argv=(($n)(o$tmod))"
+fi
+
+for f in $*
+do
+    stat -s$L -H stat -F "%b %e %H:%M" - $f || continue
+    if [[ $opts != *d* && $stat[mode] == d* ]] then
+	dirs=( $dirs $f )
+    elif [[ $opts == *l* ]] then
+	[[ $opts == *i* ]] && print -n "${(l:7:)stat[inode]} "
+	[[ -n $stat[link] ]] && f=( $f '->' $stat[link] ) || f=( $f($mod) )
+	print -r -- "$stat[mode] ${(l:3:)stat[nlink]} ${(r:8:)stat[uid]} " \
+		    "${(r:8:)stat[gid]} ${(l:8:)stat[size]} $stat[$time] $f"
+    else
+	f=( $f($mod) )
+	list=( "$list[@]" "${${(M)opts:%*i*}:+${(l:7:)stat[inode]} }$f" )
+    fi
+done
+(($#list)) && print -cr -- "$list[@]"
+while (($#dirs)) do
+    ((ARGC > $#dirs)) && echo
+    ((ARGC > 1)) && echo $dirs[1]:
+    (cd $dirs[1] && $0 -d$opts)
+    shift dirs
+done
+# }
diff --git a/Functions/README.zftp b/Functions/README.zftp
new file mode 100644
index 000000000..3b56f81d0
--- /dev/null
+++ b/Functions/README.zftp
@@ -0,0 +1,4 @@
+The Zftp directory contains a set of functions acting as a front end to the
+zftp command, provided as an add-on module.  They allow you to perform FTP
+tasks from within the shell using as many of the shell's own facilities
+as possible.  For more information, see the zshzftpsys manual page.
diff --git a/Functions/Zftp/.distfiles b/Functions/Zftp/.distfiles
new file mode 100644
index 000000000..c45e8d1c8
--- /dev/null
+++ b/Functions/Zftp/.distfiles
@@ -0,0 +1,7 @@
+DISTFILES_SRC='
+    .distfiles
+    zfanon zfautocheck zfcd zfcd_match zfcget zfclose zfcput zfdir
+    zfgcp zfget zfget_match zfhere zfinit zfls zfopen zfparams
+    zfpcp zfput zfrglob zfrtime zfstat zftp_chpwd zftp_progress
+    zftype zfuget zfuput
+'