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