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.24 2024/12/13 03:55:52 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# does local *actually* work? 68local_works() { 69 local _fu 70} 71 72if local_works > /dev/null 2>&1; then 73 _local=local 74else 75 _local=: 76fi 77# for backwards compatability 78local=$_local 79 80 81## 82# hooks_add_all list func ... 83# 84# add "func"s to "list" regardless 85# 86hooks_add_all() { 87 eval $_local __h 88 __h=$1; shift 89 case "$1" in 90 --first) 91 shift 92 eval "$__h=\"$* \$$__h\"" 93 ;; 94 *) eval "$__h=\"\$$__h $*\"";; 95 esac 96} 97 98## 99# hooks_add_once list func ... 100# 101# add "func"s to "list" if not already there 102# 103hooks_add_once() { 104 eval $_local __h __hh __first 105 __h=$1; shift 106 case "$1" in 107 --first) shift; __first=:;; 108 *) __first=;; 109 esac 110 eval "__hh=\$$__h" 111 while [ $# -gt 0 ] 112 do 113 : __hh="$__hh" 1="$1" 114 case "$__first $__hh " in 115 *" $1 "*) ;; # dupe 116 :*) __hh="$1 $__hh";; 117 *) __hh="$__hh $1";; 118 esac 119 shift 120 done 121 eval "$__h=\"$__hh\"" 122} 123 124## 125# hooks_add_default_set [--]{all,once} 126# 127# change the default method of hooks_add 128# 129hooks_add_default_set() { 130 case "$1" in 131 once|--once) HOOKS_ADD_DEFAULT=once;; 132 *) HOOKS_ADD_DEFAULT=all;; 133 esac 134} 135 136## 137# hooks_add [--{all,once}] list func ... 138# 139# add "func"s to "list" 140# 141# If '--once' use hooks_add_once, 142# default is hooks_add_all. 143# 144hooks_add() { 145 case "$1" in 146 --all) shift; hooks_add_all "$@";; 147 --once) shift; hooks_add_once "$@";; 148 *) hooks_add_${HOOKS_ADD_DEFAULT:-all} "$@";; 149 esac 150} 151 152## 153# hooks_get [--lifo] list [LIFO] 154# 155# return $list 156# 157hooks_get() { 158 eval $_local __h __h2 e __l 159 case "$1" in 160 --lifo) __l=LIFO; shift;; 161 esac 162 eval "__h=\$$1" 163 case "$__l$2" in 164 LIFO*) 165 __h2="$__h" 166 __h= 167 for e in $__h2 168 do 169 __h="$e $__h" 170 done 171 ;; 172 esac 173 echo "$__h" 174} 175 176## 177# hooks_has list func 178# 179# is func in $list ? 180# 181hooks_has() { 182 eval $_local __h 183 eval "__h=\$$1" 184 case " $__h " in 185 *" $1 "*) return 0;; 186 esac 187 return 1 188} 189 190## 191# hooks_run [--all] [--lifo] list [LIFO] [args] 192# 193# pass "args" to each function in "list" 194# Without '--all'; if any return non-zero return that immediately 195# 196hooks_run() { 197 eval $_local __a e __h __hl __h2 __l 198 __a=return 199 __l= 200 201 while : 202 do 203 case "$1" in 204 --all) __a=:; shift;; 205 --lifo) __l=$1; shift;; 206 *) break;; 207 esac 208 done 209 __hl=$1; shift 210 case "$1" in 211 LIFO) __l=--lifo; shift;; 212 esac 213 __h=`hooks_get $__l $__hl` 214 for e in $__h 215 do 216 $e "$@" || $__a $? 217 done 218} 219 220## 221# hooks_run_all [--lifo] list [LIFO] [args] 222# 223# pass "args" to each function in "list" 224# 225hooks_run_all() { 226 hooks_run --all "$@" 227} 228 229## 230# add_hooks,run_hooks[_all] aliases 231# 232add_hooks() { 233 hooks_add "$@" 234} 235 236run_hooks() { 237 hooks_run "$@" 238} 239 240run_hooks_all() { 241 hooks_run --all "$@" 242} 243 244 245case /$0 in 246*/hooks.sh) 247 # simple unit-test 248 list=HOOKS 249 flags= 250 while : 251 do 252 : 1=$1 253 case "$1" in 254 HOOKS|*hooks) list=$1; shift;; 255 --*) flags="$flags $1"; shift;; 256 *) break;; 257 esac 258 done 259 for f in "$@" 260 do 261 : f=$f 262 case "$f" in 263 LIFO) ;; 264 false|true) ;; 265 *) eval "$f() { echo This is $f; }";; 266 esac 267 done 268 echo hooks_add $flags $list "$@" 269 hooks_add $flags $list "$@" 270 echo hooks_run $list 271 hooks_run $list 272 echo hooks_run --all --lifo $list 273 hooks_run --all --lifo $list 274 echo hooks_run $list LIFO 275 hooks_run $list LIFO 276 ;; 277esac 278