Imported from ../bash-2.05a.tar.gz.
[platform/upstream/bash.git] / examples / functions / autoload.v2
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
26 unset _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
119 autoload()
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 }