]>
Commit | Line | Data |
---|---|---|
ccc6cda3 JA |
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 | # | |
f73dda09 | 21 | # The first cut of this was by Bill Trost, trost@reed.edu |
ccc6cda3 JA |
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 | } |