1: 2# NAME: 3# hooks.sh - provide hooks for customization 4# 5# SYNOPSIS: 6# hooks_add_all HOOKS [--first] func [...] 7# hooks_add_once HOOKS [--first] func [...] 8# hooks_add_default_set {all,once} 9# hooks_add HOOKS func [...] 10# hooks_get [--lifo] HOOKS 11# hooks_run [--lifo] HOOKS ["args"] 12# hooks_run_all [--lifo] HOOKS ["args"] 13# hooks_has HOOKS func 14# 15# add_hooks HOOKS [--first] func [...] 16# run_hooks HOOKS [LIFO] ["args"] 17# run_hooks_all HOOKS [LIFO] ["args"] 18# 19# DESCRIPTION: 20# The functions add_hooks and run_hooks are retained for 21# backwards compatibility. They are aliases for hooks_add and 22# hooks_run. 23# 24# hooks_add_all simply adds the "func"s to the list "HOOKS". 25# 26# If the first arg is '--first' "func"s are added to the start 27# of the list. 28# 29# hooks_add_once does the same but only if "func" is not in "HOOKS". 30# hooks_add uses one of the above based on "option", '--all' (default) 31# or '--once'. 32# 33# hooks_add_default_set sets the default behavior of hooks_add 34# 35# hooks_get simply returns the named list of functions. 36# 37# hooks_has indicates whether "func" in in "HOOKS". 38# 39# hooks_run runs each "func" in $HOOKS and stops if any of them 40# return a bad status. 41# 42# hooks_run_all does the same but does not stop on error. 43# 44# If run_hooks or run_hooks_all is given a flag of '--lifo' or 45# 2nd argument of LIFO the hooks are run in the reverse order of 46# calls to hooks_add. 47# Any "args" specified are passed to each hook function. 48# 49 50# RCSid: 51# $Id: hooks.sh,v 1.26 2025/08/07 21:59:54 sjg Exp $ 52# 53# @(#)Copyright (c) 2000-2024 Simon J. Gerraty 54# 55# SPDX-License-Identifier: BSD-2-Clause 56# 57# Please send copies of changes and bug-fixes to: 58# sjg@crufty.net 59# 60 61# avoid multiple inclusion 62_HOOKS_SH=: 63 64# does local *actually* work? 65local_works() { 66 local _fu 67} 68 69if local_works > /dev/null 2>&1; then 70 _local=local 71else 72 _local=: 73fi 74# for backwards compatability 75local=$_local 76 77 78## 79# hooks_add_all list func ... 80# 81# add "func"s to "list" regardless 82# 83hooks_add_all() { 84 eval $_local __h 85 __h=$1; shift 86 case "$1" in 87 --first) 88 shift 89 eval "$__h=\"$* \$$__h\"" 90 ;; 91 *) eval "$__h=\"\$$__h $*\"";; 92 esac 93} 94 95## 96# hooks_add_once list func ... 97# 98# add "func"s to "list" if not already there 99# 100hooks_add_once() { 101 eval $_local __h __hh __first 102 __h=$1; shift 103 case "$1" in 104 --first) shift; __first=:;; 105 *) __first=;; 106 esac 107 eval "__hh=\$$__h" 108 while [ $# -gt 0 ] 109 do 110 : __hh="$__hh" 1="$1" 111 case "$__first $__hh " in 112 *" $1 "*) ;; # dupe 113 :*) __hh="$1 $__hh";; 114 *) __hh="$__hh $1";; 115 esac 116 shift 117 done 118 eval "$__h=\"$__hh\"" 119} 120 121## 122# hooks_add_default_set [--]{all,once} 123# 124# change the default method of hooks_add 125# 126hooks_add_default_set() { 127 case "$1" in 128 once|--once) HOOKS_ADD_DEFAULT=once;; 129 *) HOOKS_ADD_DEFAULT=all;; 130 esac 131} 132 133## 134# hooks_add [--{all,once}] list func ... 135# 136# add "func"s to "list" 137# 138# If '--once' use hooks_add_once, 139# default is hooks_add_all. 140# 141hooks_add() { 142 case "$1" in 143 --all) shift; hooks_add_all "$@";; 144 --once) shift; hooks_add_once "$@";; 145 *) hooks_add_${HOOKS_ADD_DEFAULT:-all} "$@";; 146 esac 147} 148 149## 150# hooks_get [--lifo] list [LIFO] 151# 152# return $list 153# 154hooks_get() { 155 eval $_local __h __h2 e __l 156 case "$1" in 157 --lifo) __l=LIFO; shift;; 158 esac 159 eval "__h=\$$1" 160 case "$__l$2" in 161 LIFO*) 162 __h2="$__h" 163 __h= 164 for e in $__h2 165 do 166 __h="$e $__h" 167 done 168 ;; 169 esac 170 echo "$__h" 171} 172 173## 174# hooks_has list func 175# 176# is func in $list ? 177# 178hooks_has() { 179 eval $_local __h 180 eval "__h=\$$1" 181 case " $__h " in 182 *" $1 "*) return 0;; 183 esac 184 return 1 185} 186 187## 188# hooks_run [--all] [--lifo] list [LIFO] [args] 189# 190# pass "args" to each function in "list" 191# Without '--all'; if any return non-zero return that immediately 192# 193hooks_run() { 194 eval $_local __a e __h __hl __h2 __l 195 __a=return 196 __l= 197 198 while : 199 do 200 case "$1" in 201 --all) __a=:; shift;; 202 --lifo) __l=$1; shift;; 203 *) break;; 204 esac 205 done 206 __hl=$1; shift 207 case "$1" in 208 LIFO) __l=--lifo; shift;; 209 esac 210 __h=`hooks_get $__l $__hl` 211 for e in $__h 212 do 213 $e "$@" || $__a $? 214 done 215} 216 217## 218# hooks_run_all [--lifo] list [LIFO] [args] 219# 220# pass "args" to each function in "list" 221# 222hooks_run_all() { 223 hooks_run --all "$@" 224} 225 226## 227# add_hooks,run_hooks[_all] aliases 228# 229add_hooks() { 230 hooks_add "$@" 231} 232 233run_hooks() { 234 hooks_run "$@" 235} 236 237run_hooks_all() { 238 hooks_run --all "$@" 239} 240 241 242case /$0 in 243*/hooks.sh) 244 # simple unit-test 245 list=HOOKS 246 flags= 247 while : 248 do 249 : 1=$1 250 case "$1" in 251 HOOKS|*hooks) list=$1; shift;; 252 --*) flags="$flags $1"; shift;; 253 *) break;; 254 esac 255 done 256 for f in "$@" 257 do 258 : f=$f 259 case "$f" in 260 LIFO) ;; 261 false|true) ;; 262 *) eval "$f() { echo This is $f; }";; 263 esac 264 done 265 echo hooks_add $flags $list "$@" 266 hooks_add $flags $list "$@" 267 echo hooks_run $list 268 hooks_run $list 269 echo hooks_run --all --lifo $list 270 hooks_run --all --lifo $list 271 echo hooks_run $list LIFO 272 hooks_run $list LIFO 273 ;; 274esac 275