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