1# 2# An almost ksh-compatible `autoload'. A function declared as `autoload' will 3# be read in from a file the same name as the function found by searching the 4# $FPATH (which works the same as $PATH), then that definition will be run. 5# 6# To do this without source support, we define a dummy function that, when 7# executed, will load the file (thereby re-defining the function), then 8# execute that newly-redefined function with the original arguments. 9# 10# It's not identical to ksh because ksh apparently does lazy evaluation 11# and looks for the file to load from only when the function is referenced. 12# This one requires that the file exist when the function is declared as 13# `autoload'. 14# 15# usage: autoload [-pu] [func ...] 16# 17# options: 18# -p print in a format that can be reused as input 19# -u unset each function and remove it from the autoload list 20# 21# The first cut of this was by Bill Trost, trost@reed.edu 22# 23# Chet Ramey 24# chet@ins.CWRU.Edu 25 26unset _AUTOLOADS 27_aindex=0 28 29# 30# Declare a function ($1) to be autoloaded from a file ($2) when it is first 31# called. This defines a `temporary' function that will `.' the file 32# containg the real function definition, then execute that new definition with 33# the arguments given to this `fake' function. The autoload function defined 34# by the file and the file itself *must* be named identically. 35# 36 37_aload() 38{ 39 eval $1 '() { . '$2' ; '$1' "$@" ; return $? ; }' 40 _autoload_addlist "$1" 41} 42 43_autoload_addlist() 44{ 45 local i=0 46 47 while (( i < $_aindex )); do 48 case "${_AUTOLOADS[i]}" in 49 "$1") return 1 ;; 50 esac 51 (( i += 1 )) 52 done 53 _AUTOLOADS[_aindex]="$1" 54 (( _aindex += 1 )) 55 return 0 56} 57 58_autoload_dump() 59{ 60 local func 61 62 for func in ${_AUTOLOADS[@]}; do 63 [ -n "$1" ] && echo -n "autoload " 64 echo "$func" 65 done 66} 67 68# Remove $1 from the list of autoloaded functions 69_autoload_remove_one() 70{ 71 local i=0 nnl=0 72 local -a nlist 73 74 while (( i < _aindex )); do 75 case "${_AUTOLOADS[i]}" in 76 "$1") ;; 77 *) nlist[nnl]="${_AUTOLOADS[i]}" ; (( nnl += 1 ));; 78 esac 79 (( i += 1 )) 80 done 81 unset _AUTOLOADS _aindex 82 eval _AUTOLOADS=( ${nlist[@]} ) 83 _aindex=$nnl 84} 85 86# Remove all function arguments from the list of autoloaded functions 87_autoload_remove() 88{ 89 local func i es=0 90 91 # first unset the autoloaded functions 92 for func; do 93 i=0 94 while (( i < _aindex )); do 95 case "${_AUTOLOADS[i]}" in 96 "$func") unset -f $func ; break ;; 97 esac 98 (( i += 1 )) 99 done 100 if (( i == _aindex )); then 101 echo "autoload: $func: not an autoloaded function" >&2 102 es=1 103 fi 104 done 105 106 # then rebuild the list of autoloaded functions 107 for func ; do 108 _autoload_remove_one "$func" 109 done 110 111 return $es 112} 113 114# 115# Search $FPATH for a file the same name as the function given as $1, and 116# autoload the function from that file. There is no default $FPATH. 117# 118 119autoload() 120{ 121 local -a fp 122 local _autoload_unset nfp i 123 124 if (( $# == 0 )) ; then 125 _autoload_dump 126 return 0 127 fi 128 129 OPTIND=1 130 while getopts pu opt 131 do 132 case "$opt" in 133 p) _autoload_dump printable; return 0;; 134 u) _autoload_unset=y ;; 135 *) echo "autoload: usage: autoload [-pu] [function ...]" >&2 136 return 1 ;; 137 esac 138 done 139 140 shift $(( $OPTIND - 1 )) 141 142 if [ -n "$_autoload_unset" ]; then 143 _autoload_remove "$@" 144 return $? 145 fi 146 147 # 148 # If there is no $FPATH, there is no work to be done 149 # 150 151 if [ -z "$FPATH" ] ; then 152 echo "autoload: FPATH not set or null" >&2 153 return 1 154 fi 155 156 # 157 # This treats FPATH exactly like PATH: a null field anywhere in the 158 # FPATH is treated the same as the current directory. 159 # 160 # This turns $FPATH into an array, substituting `.' for `' 161 # 162 eval fp=( $( 163 IFS=':' 164 set -- ${FPATH} 165 for p in "$@" ; do echo -n "${p:-.} "; done 166 ) 167 ) 168 169 nfp=${#fp[@]} 170 171 for FUNC ; do 172 i=0; 173 while (( i < nfp )) ; do 174 if [ -f ${fp[i]}/$FUNC ] ; then 175 break # found it! 176 fi 177 (( i += 1 )) 178 done 179 180 if (( i == nfp )) ; then 181 echo "autoload: $FUNC: autoload function not found" >&2 182 es=1 183 continue 184 fi 185 186# echo auto-loading $FUNC from ${fp[i]}/$FUNC 187 _aload $FUNC ${fp[i]}/$FUNC 188 es=0 189 done 190 191 return $es 192} 193