sistema_progs

Programas para customizar o meu entorno de traballo nos meus equipos persoais
Log | Files | Refs

util.hook.sh (41735B)


      1 # -*- mode: sh; mode: sh-bash -*-
      2 
      3 #------------------------------------------------------------------------------
      4 # blehook
      5 
      6 ## @fn blehook/.print
      7 ##   @var[in] flags
      8 function blehook/.print {
      9   (($#)) || return 0
     10 
     11   local out= q=\' Q="'\''" nl=$'\n'
     12   local sgr0= sgr1= sgr2= sgr3=
     13   if [[ $flags == *c* ]]; then
     14     local ret
     15     ble/color/face2sgr command_function; sgr1=$ret
     16     ble/color/face2sgr syntax_varname; sgr2=$ret
     17     ble/color/face2sgr syntax_quoted; sgr3=$ret
     18     sgr0=$_ble_term_sgr0
     19     Q=$q$sgr0"\'"$sgr3$q
     20   fi
     21 
     22   local elem op_assign code='
     23     if ((${#_ble_hook_h_NAME[@]})); then
     24       op_assign==
     25       for elem in "${_ble_hook_h_NAME[@]}"; do
     26         out="${out}${sgr1}blehook$sgr0 ${sgr2}NAME$sgr0$op_assign${sgr3}$q${elem//$q/$Q}$q$sgr0$nl"
     27         op_assign=+=
     28       done
     29     else
     30       out="${out}${sgr1}blehook$sgr0 ${sgr2}NAME$sgr0=$nl"
     31     fi'
     32 
     33   local hookname
     34   for hookname; do
     35     ble/is-array "$hookname" || continue
     36     builtin eval -- "${code//NAME/${hookname#_ble_hook_h_}}"
     37   done
     38   ble/util/put "$out"
     39 }
     40 function blehook/.print-help {
     41   ble/util/print-lines \
     42     'usage: blehook [NAME[[=|+=|-=|-+=]COMMAND]]...' \
     43     '    Add or remove hooks. Without arguments, this prints all the existing hooks.' \
     44     '' \
     45     '  Options:' \
     46     '    --help      Print this help.' \
     47     '    -a, --all   Print all hooks including the internal ones.' \
     48     '    --color[=always|never|auto]' \
     49     '                  Change color settings.' \
     50     '' \
     51     '  Arguments:' \
     52     '    NAME            Print the corresponding hooks.' \
     53     '    NAME=COMMAND    Set hook after removing the existing hooks.' \
     54     '    NAME+=COMMAND   Add hook.' \
     55     '    NAME-=COMMAND   Remove hook.' \
     56     '    NAME!=COMMAND   Add hook if the command is not registered.' \
     57     '    NAME-+=COMMAND  Append the hook and remove the duplicates.' \
     58     '    NAME+-=COMMAND  Prepend the hook and remove the duplicates.' \
     59     '' \
     60     '  NAME:' \
     61     '    The hook name.  The character `@'\'' may be used as a wildcard.' \
     62     ''
     63 }
     64 
     65 ## @fn blehook/.read-arguments args...
     66 ##   @var[out] flags
     67 function blehook/.read-arguments {
     68   flags= print=() process=()
     69   local opt_color=auto
     70   while (($#)); do
     71     local arg=$1; shift
     72     if [[ $arg == -* ]]; then
     73       case $arg in
     74       (--help)
     75         flags=H$flags ;;
     76       (--color) opt_color=always ;;
     77       (--color=always|--color=auto|--color=never)
     78         opt_color=${arg#*=} ;;
     79       (--color=*)
     80         ble/util/print "blehook: '${arg#*=}': unrecognized option argument for '--color'." >&2
     81         flags=E$flags ;;
     82       (--all) flags=a$flags ;;
     83       (--*)
     84         ble/util/print "blehook: unrecognized long option '$arg'." >&2
     85         flags=E$flags ;;
     86       (-)
     87         ble/util/print "blehook: unrecognized argument '$arg'." >&2
     88         flags=E$flags ;;
     89       (*)
     90         local i c
     91         for ((i=1;i<${#arg};i++)); do
     92           c=${arg:i:1}
     93           case $c in
     94           (a) flags=a$flags ;;
     95           (*)
     96             ble/util/print "blehook: unrecognized option '-$c'." >&2
     97             flags=E$flags ;;
     98           esac
     99         done ;;
    100       esac
    101     elif [[ $arg =~ $rex1 ]]; then
    102       if [[ $arg == *@* ]] || ble/is-array "_ble_hook_h_$arg"; then
    103         ble/array#push print "$arg"
    104       else
    105         ble/util/print "blehook: undefined hook '$arg'." >&2
    106       fi
    107     elif [[ $arg =~ $rex2 ]]; then
    108       local name=${BASH_REMATCH[1]}
    109       if [[ $name == *@* ]]; then
    110         if [[ ${BASH_REMATCH[2]} == :* ]]; then
    111           ble/util/print "blehook: hook pattern cannot be combined with '${BASH_REMATCH[2]}'." >&2
    112           flags=E$flags
    113           continue
    114         fi
    115       else
    116         local var_counter=_ble_hook_c_$name
    117         if [[ ! ${!var_counter+set} ]]; then
    118           if [[ ${BASH_REMATCH[2]} == :* ]]; then
    119             (($var_counter=0))
    120           else
    121             ble/util/print "blehook: hook \"$name\" is not defined." >&2
    122             flags=E$flags
    123             continue
    124           fi
    125         fi
    126       fi
    127       ble/array#push process "$arg"
    128     else
    129       ble/util/print "blehook: invalid hook spec \"$arg\"" >&2
    130       flags=E$flags
    131     fi
    132   done
    133 
    134   # resolve patterns
    135   local pat ret out; out=()
    136   for pat in "${print[@]}"; do
    137     if [[ $pat == *@* ]]; then
    138       bleopt/expand-variable-pattern "_ble_hook_h_$pat"
    139       ble/array#filter ret ble/is-array
    140       [[ $pat == *[a-z]* || $flags == *a* ]] ||
    141         ble/array#remove-by-glob ret '_ble_hook_h_*[a-z]*'
    142       if ((!${#ret[@]})); then
    143         ble/util/print "blehook: '$pat': matching hook not found." >&2
    144         flags=E$flags
    145         continue
    146       fi
    147     else
    148       ret=("_ble_hook_h_$pat")
    149     fi
    150     ble/array#push out "${ret[@]}"
    151   done
    152   print=("${out[@]}")
    153 
    154   out=()
    155   for pat in "${process[@]}"; do
    156     [[ $pat =~ $rex2 ]]
    157     local name=${BASH_REMATCH[1]}
    158     if [[ $name == *@* ]]; then
    159       local type=${BASH_REMATCH[3]}
    160       local value=${BASH_REMATCH[4]}
    161 
    162       bleopt/expand-variable-pattern "_ble_hook_h_$pat"
    163       ble/array#filter ret ble/is-array
    164       [[ $pat == *[a-z]* || $flags == *a* ]] ||
    165         ble/array#remove-by-glob ret '_ble_hook_h_*[a-z]*'
    166       if ((!${#ret[@]})); then
    167         ble/util/print "blehook: '$pat': matching hook not found." >&2
    168         flags=E$flags
    169         continue
    170       fi
    171       if ((_ble_bash>=40300)) && ! shopt -q compat42; then
    172         ret=("${ret[@]/%/"$type$value"}") # WA #D1570 #D1751 checked
    173       else
    174         ret=("${ret[@]/%/$type$value}") # WA #D1570 #D1738 checked
    175       fi
    176     else
    177       ret=("_ble_hook_h_$pat")
    178     fi
    179     ble/array#push out "${ret[@]}"
    180   done
    181   process=("${out[@]}")
    182 
    183   [[ $opt_color == always || $opt_color == auto && -t 1 ]] && flags=c$flags
    184 }
    185 
    186 function blehook {
    187   local set shopt
    188   ble/base/adjust-BASH_REMATCH
    189   ble/base/.adjust-bash-options set shopt
    190 
    191   local flags print process
    192   local rex1='^([_a-zA-Z@][_a-zA-Z0-9@]*)$'
    193   local rex2='^([_a-zA-Z@][_a-zA-Z0-9@]*)(:?([-+!]|-\+|\+-)?=)(.*)$'
    194   blehook/.read-arguments "$@"
    195   if [[ $flags == *[HE]* ]]; then
    196     if [[ $flags == *H* ]]; then
    197       [[ $flags == *E* ]] &&
    198         ble/util/print >&2
    199       blehook/.print-help
    200     fi
    201     [[ $flags != *E* ]]; local ext=$?
    202     ble/base/.restore-bash-options set shopt
    203     ble/base/restore-BASH_REMATCH
    204     return "$ext"
    205   fi
    206 
    207   if ((${#print[@]}==0&&${#process[@]}==0)); then
    208     print=("${!_ble_hook_h_@}")
    209     [[ $flags == *a* ]] || ble/array#remove-by-glob print '_ble_hook_h_*[a-z]*'
    210   fi
    211 
    212   local proc ext=0
    213   for proc in "${process[@]}"; do
    214     [[ $proc =~ $rex2 ]]
    215     local name=${BASH_REMATCH[1]}
    216     local type=${BASH_REMATCH[3]}
    217     local value=${BASH_REMATCH[4]}
    218 
    219     local append=$value
    220     case $type in
    221     (*-*) # -=, -+=, +-=
    222       local ret
    223       ble/array#last-index "$name" "$value"
    224       if ((ret>=0)); then
    225         ble/array#remove-at "$name" "$ret"
    226       elif [[ ${type#:} == '-=' ]]; then
    227         ext=1
    228       fi
    229 
    230       if [[ $type != -+ ]]; then
    231         append=
    232         [[ $type == +- ]] &&
    233           ble/array#unshift "$name" "$value"
    234       fi ;;
    235 
    236     ('!') # !=
    237       local ret
    238       ble/array#last-index "$name" "$value"
    239       ((ret>=0)) && append= ;;
    240 
    241     ('') builtin eval "$name=()" ;; # =
    242     ('+'|*) ;; # +=
    243     esac
    244     [[ $append ]] && ble/array#push "$name" "$append"
    245   done
    246 
    247   if ((${#print[@]})); then
    248     blehook/.print "${print[@]}"
    249   fi
    250 
    251   ble/base/.restore-bash-options set shopt
    252   ble/base/restore-BASH_REMATCH
    253   return "$ext"
    254 }
    255 blehook/.compatibility-ble-0.3
    256 
    257 function blehook/has-hook {
    258   builtin eval "local count=\${#_ble_hook_h_$1[@]}"
    259   ((count))
    260 }
    261 ## @fn blehook/invoke.sandbox
    262 ##   @var[in] _ble_local_hook _ble_local_lastexit _ble_local_lastarg
    263 function blehook/invoke.sandbox {
    264   if type "$_ble_local_hook" &>/dev/null; then
    265     ble/util/setexit "$_ble_local_lastexit" "$_ble_local_lastarg"
    266     "$_ble_local_hook" "$@" 2>&3
    267   else
    268     ble/util/setexit "$_ble_local_lastexit" "$_ble_local_lastarg"
    269     builtin eval -- "$_ble_local_hook" 2>&3
    270   fi
    271 }
    272 function blehook/invoke {
    273   local _ble_local_lastexit=$? _ble_local_lastarg=$_ FUNCNEST=
    274   ((_ble_hook_c_$1++))
    275   local -a _ble_local_hooks
    276   builtin eval "_ble_local_hooks=(\"\${_ble_hook_h_$1[@]}\")"; shift
    277   local _ble_local_hook _ble_local_ext=0
    278   for _ble_local_hook in "${_ble_local_hooks[@]}"; do
    279     blehook/invoke.sandbox "$@" || _ble_local_ext=$?
    280   done
    281   return "$_ble_local_ext"
    282 } 3>&2 2>/dev/null # set -x 対策 #D0930
    283 function blehook/eval-after-load {
    284   local hook_name=${1}_load value=$2
    285   if ((_ble_hook_c_$hook_name)); then
    286     builtin eval -- "$value"
    287   else
    288     blehook "$hook_name+=$value"
    289   fi
    290 }
    291 
    292 #------------------------------------------------------------------------------
    293 # blehook
    294 
    295 _ble_builtin_trap_inside=  # ble/builtin/trap 処理中かどうか
    296 
    297 ## @fn ble/builtin/trap/.read-arguments args...
    298 ##   @var[out] flags
    299 function ble/builtin/trap/.read-arguments {
    300   flags= command= sigspecs=()
    301   while (($#)); do
    302     local arg=$1; shift
    303     if [[ $arg == -?* && flags != *A* ]]; then
    304       if [[ $arg == -- ]]; then
    305         flags=A$flags
    306         continue
    307       elif [[ $arg == --* ]]; then
    308         case $arg in
    309         (--help)
    310           flags=h$flags
    311           continue ;;
    312         (*)
    313           ble/util/print "ble/builtin/trap: unknown long option \"$arg\"." >&2
    314           flags=E$flags
    315           continue ;;
    316         esac
    317       fi
    318 
    319       local i
    320       for ((i=1;i<${#arg};i++)); do
    321         case ${arg:i:1} in
    322         (l) flags=l$flags ;;
    323         (p) flags=p$flags ;;
    324         (P) flags=P$flags ;;
    325         (*)
    326           ble/util/print "ble/builtin/trap: unknown option \"-${arg:i:1}\"." >&2
    327           flags=E$flags ;;
    328         esac
    329       done
    330     else
    331       if [[ $flags != *[pc]* ]]; then
    332         command=$arg
    333         flags=c$flags
    334       else
    335         ble/array#push sigspecs "$arg"
    336       fi
    337     fi
    338   done
    339 
    340   if [[ $flags != *[hlpPE]* ]]; then
    341     if [[ $flags != *c* ]]; then
    342       flags=p$flags
    343     elif ((${#sigspecs[@]}==0)); then
    344       sigspecs=("$command")
    345       command=-
    346     fi
    347   elif [[ $flags == *p* && $flags == *P* ]]; then
    348     ble/util/print "ble/builtin/trap: cannot specify both -p and -P" >&2
    349     flags=E${flags//[pP]}
    350   fi
    351 }
    352 
    353 builtin eval -- "${_ble_util_gdict_declare//NAME/_ble_builtin_trap_name2sig}"
    354 _ble_builtin_trap_sig_name=()
    355 _ble_builtin_trap_sig_opts=()
    356 _ble_builtin_trap_sig_base=1000
    357 _ble_builtin_trap_EXIT=
    358 _ble_builtin_trap_DEBUG=
    359 _ble_builtin_trap_RETURN=
    360 _ble_builtin_trap_ERR=
    361 function ble/builtin/trap/sig#register {
    362   local sig=$1 name=$2
    363   _ble_builtin_trap_sig_name[sig]=$name
    364   ble/gdict#set _ble_builtin_trap_name2sig "$name" "$sig"
    365 }
    366 function ble/builtin/trap/sig#reserve {
    367   local ret
    368   ble/builtin/trap/sig#resolve "$1" || return 1
    369   _ble_builtin_trap_sig_opts[ret]=${2:-1}
    370 }
    371 ## @fn ble/builtin/trap/sig#resolve sigspec
    372 ##   @var[out] ret
    373 function ble/builtin/trap/sig#resolve {
    374   ble/builtin/trap/sig#init
    375   if [[ $1 && ! ${1//[0-9]} ]]; then
    376     ret=$1
    377     return 0
    378   else
    379     ble/gdict#get _ble_builtin_trap_name2sig "$1"
    380     [[ $ret ]] && return 0
    381 
    382     ble/string#toupper "$1"; local upper=$ret
    383     ble/gdict#get _ble_builtin_trap_name2sig "$upper" ||
    384       ble/gdict#get _ble_builtin_trap_name2sig "SIG$upper" ||
    385       return 1
    386     ble/gdict#set _ble_builtin_trap_name2sig "$1" "$ret"
    387     return 0
    388   fi
    389 }
    390 ## @fn ble/builtin/trap/sig#new sig [opts]
    391 ##   @param[in,opt] opts
    392 ##
    393 ##     builtin (internal use)
    394 ##       reserve the special handling of the corresponding builtin trap.  Used
    395 ##       for DEBUG, RETURN, and ERR.
    396 ##
    397 ##     override-builtin-signal (internal use)
    398 ##       indicates that the builtin trap handler is overridden by ble.sh.  The
    399 ##       user traps should be restored on ble-unload.
    400 ##
    401 ##     user-trap-in-postproc
    402 ##       evaluate user traps outside the trap-handler function.  When this is
    403 ##       enabled, the last argument $_ is not modified by the user trap
    404 ##       handlers because of the limitation of the implementation.
    405 ##
    406 function ble/builtin/trap/sig#new {
    407   local name=$1 opts=$2
    408   local sig=$((_ble_builtin_trap_$name=_ble_builtin_trap_sig_base++))
    409   ble/builtin/trap/sig#register "$sig" "$name"
    410   if [[ :$opts: != *:builtin:* ]]; then
    411     ble/builtin/trap/sig#reserve "$sig" "$opts"
    412   fi
    413 }
    414 function ble/builtin/trap/sig#init {
    415   function ble/builtin/trap/sig#init { :; }
    416   local ret i
    417   ble/util/assign-words ret 'builtin trap -l' 2>/dev/null
    418   for ((i=0;i<${#ret[@]};i+=2)); do
    419     local index=${ret[i]%')'}
    420     local name=${ret[i+1]}
    421     ble/builtin/trap/sig#register "$index" "$name"
    422   done
    423 
    424   _ble_builtin_trap_EXIT=0
    425   ble/builtin/trap/sig#register "$_ble_builtin_trap_EXIT" EXIT
    426   ble/builtin/trap/sig#new DEBUG  builtin
    427   ble/builtin/trap/sig#new RETURN builtin
    428   ble/builtin/trap/sig#new ERR    builtin
    429 }
    430 
    431 _ble_builtin_trap_handlers=()
    432 _ble_builtin_trap_handlers_RETURN=()
    433 ## @fn ble/builtin/trap/user-handler#load sig
    434 ##   @param[in] sig
    435 ##     トラップ番号を指定します。
    436 ##   @var[out] _ble_trap_handler
    437 ##     ユーザートラップを格納します。
    438 ##   @exit
    439 ##     ユーザートラップが設定されている時に 0 を返します。
    440 function ble/builtin/trap/user-handler#load {
    441   local sig=$1 name=${_ble_builtin_trap_sig_name[$1]}
    442   if [[ $name == RETURN ]]; then
    443     ble/builtin/trap/user-handler#load:RETURN
    444   else
    445     _ble_trap_handler=${_ble_builtin_trap_handlers[sig]-}
    446     [[ ${_ble_builtin_trap_handlers[sig]+set} ]]
    447   fi
    448 }
    449 ## @fn ble/builtin/trap/user-handler#save sig handler
    450 ##   指定したトラップに対するハンドラーを記録します。
    451 ##   @param[in] sig handler
    452 ##     トラップ番号を指定します。
    453 ##   @var[out] _ble_trap_handler
    454 ##     ユーザートラップを格納します。
    455 ##   @exit
    456 ##     ユーザートラップが設定されている時に 0 を返します。
    457 function ble/builtin/trap/user-handler#save {
    458   local sig=$1 name=${_ble_builtin_trap_sig_name[$1]} handler=$2
    459   if [[ $name == RETURN ]]; then
    460     ble/builtin/trap/user-handler#save:RETURN "$handler"
    461   else
    462     if [[ $handler == - ]]; then
    463       builtin unset -v '_ble_builtin_trap_handlers[sig]'
    464     else
    465       _ble_builtin_trap_handlers[sig]=$handler
    466     fi
    467   fi
    468   return 0
    469 }
    470 function ble/builtin/trap/user-handler#save:RETURN {
    471   local handler=$1
    472 
    473   local offset=
    474   for ((offset=1;offset<${#FUNCNAME[@]};offset++)); do
    475     case ${FUNCNAME[offset]} in
    476     (trap | ble/builtin/trap) ;;
    477     (ble/builtin/trap/user-handler#save) ;;
    478     (*) break ;;
    479     esac
    480   done
    481   local current_level=$((${#FUNCNAME[@]}-offset))
    482 
    483   local level
    484   for level in "${!_ble_builtin_trap_handlers_RETURN[@]}"; do
    485     if ((level>current_level)); then
    486       builtin unset -v '_ble_builtin_trap_handlers_RETURN[level]'
    487     fi
    488   done
    489 
    490   if [[ $handler == - ]]; then
    491     if [[ $- == *T* ]] || shopt -q extdebug; then
    492       for ((level=current_level;level>=0;level--)); do
    493         builtin unset -v '_ble_builtin_trap_handlers_RETURN[level]'
    494       done
    495     else
    496       for ((level=current_level;level>=0;level--,offset++)); do
    497         builtin unset -v '_ble_builtin_trap_handlers_RETURN[level]'
    498         ((level)) && ble/function#has-attr "${FUNCNAME[offset]}" t || break
    499       done
    500     fi
    501   else
    502     _ble_builtin_trap_handlers_RETURN[current_level]=$handler
    503   fi
    504   return 0
    505 }
    506 function ble/builtin/trap/user-handler#load:RETURN {
    507   # この関数の呼び出し文脈・handler 探索開始関数レベルの決定
    508   local offset= in_trap=
    509   for ((offset=1;offset<${#FUNCNAME[@]};offset++)); do
    510     case ${FUNCNAME[offset]} in
    511     (trap | ble/builtin/trap) ;;
    512     (ble/builtin/trap/.handler) ;;
    513     (ble/builtin/trap/user-handler#load) ;;
    514     (ble/builtin/trap/user-handler#has) ;;
    515     (ble/builtin/trap/finalize) ;;
    516     (ble/builtin/trap/install-hook) ;;
    517     (ble/builtin/trap/invoke) ;;
    518     (*) break ;;
    519     esac
    520   done
    521   local search_level=
    522   if [[ $- == *T* ]] || shopt -q extdebug; then
    523     search_level=0
    524   else
    525     for ((;offset<${#FUNCNAME[@]};offset++)); do
    526       ble/function#has-attr "${FUNCNAME[offset]}" t || break
    527     done
    528     search_level=$((${#FUNCNAME[@]}-offset))
    529   fi
    530 
    531   # search_level 以降の最大 index に記録されている handler を取得
    532   local level found= handler=
    533   for level in "${!_ble_builtin_trap_handlers_RETURN[@]}"; do
    534     ((level>=search_level)) || continue
    535     found=1 handler=${_ble_builtin_trap_handlers_RETURN[level]}
    536   done
    537 
    538   _ble_trap_handler=$handler
    539   [[ $found ]]
    540 }
    541 ## @fn ble/builtin/trap/user-handler#update:RETURN
    542 ##   関数が戻る時に呼び出して RETURN トラップの呼び出し元への継承を実行します。
    543 ##   この関数は ble/builtin/trap/.handler から呼び出される事を想定しています。
    544 function ble/builtin/trap/user-handler#update:RETURN {
    545   # この関数の呼び出し文脈の取得
    546   local offset=2 # ... ble/builtin/trap/.handler から直接呼び出されると仮定
    547   local current_level=$((${#FUNCNAME[@]}-offset))
    548   ((current_level>0)) || return 0
    549 
    550   # current_level 以降の最大 index に記録されている handler を取得
    551   local level found= handler=
    552   for level in "${!_ble_builtin_trap_handlers_RETURN[@]}"; do
    553     ((level>=current_level)) || continue
    554     found=1 handler=${_ble_builtin_trap_handlers_RETURN[level]}
    555 
    556     # 自身及びそれ以下のレベルに記録した handler は削除する。見つかった handler
    557     # は後でひとつ上のレベルにコピーする。
    558     if ((level>=current_level)); then
    559       builtin unset -v '_ble_builtin_trap_handlers_RETURN[level]'
    560     fi
    561   done
    562   if [[ $found ]]; then
    563     _ble_builtin_trap_handlers_RETURN[current_level-1]=$handler
    564   fi
    565 }
    566 function ble/builtin/trap/user-handler#has {
    567   local _ble_trap_handler
    568   ble/builtin/trap/user-handler#load "$1"
    569 }
    570 function ble/builtin/trap/user-handler#init {
    571   local script _ble_builtin_trap_user_handler_init=1
    572   ble/util/assign script 'builtin trap -p'
    573   builtin eval -- "$script"
    574 }
    575 function ble/builtin/trap/user-handler/is-internal {
    576   case $1 in
    577   ('ble/builtin/trap/'*) return 0 ;; # ble-0.4
    578   ('ble/base/unload'*|'ble-edit/'*) return 0 ;; # bash-0.3 以前
    579   (*) return 1 ;;
    580   esac
    581 }
    582 
    583 function ble/builtin/trap/finalize {
    584   _ble_builtin_trap_handlers_reload=()
    585 
    586   local sig unload_opts=$1
    587   for sig in "${!_ble_builtin_trap_sig_opts[@]}"; do
    588     local name=${_ble_builtin_trap_sig_name[sig]}
    589     local opts=${_ble_builtin_trap_sig_opts[sig]}
    590     [[ $name && :$opts: == *:override-builtin-signal:* ]] || continue
    591 
    592     # Note (#D2021): reload の為に一旦設定を復元する時は readline によ
    593     # る WINCH trap を破壊しない様に WINCH だけはそのままにして置く。
    594     # 元々のユーザートラップは _ble_builtin_trap_handlers_reload に記
    595     # 録し、後の ble/builtin/trap/install-hook で読み取る。
    596     if [[ :$opts: == *:readline:* && :$unload_opts: == *:reload:* ]]; then
    597       if local _ble_trap_handler; ble/builtin/trap/user-handler#load "$sig"; then
    598         local q=\' Q="'\''"
    599         _ble_builtin_trap_handlers_reload[sig]="trap -- '${_ble_trap_handler//$q/$Q}' $name"
    600       else
    601         _ble_builtin_trap_handlers_reload[sig]=
    602       fi
    603       continue
    604     fi
    605 
    606     if local _ble_trap_handler; ble/builtin/trap/user-handler#load "$sig"; then
    607       builtin trap -- "$_ble_trap_handler" "$name"
    608     else
    609       builtin trap -- - "$name"
    610     fi
    611   done
    612 }
    613 function ble/builtin/trap {
    614   local set shopt; ble/base/.adjust-bash-options set shopt
    615   local flags command sigspecs
    616   ble/builtin/trap/.read-arguments "$@"
    617 
    618   if [[ $flags == *h* ]]; then
    619     builtin trap --help
    620     ble/base/.restore-bash-options set shopt
    621     return 2
    622   elif [[ $flags == *E* ]]; then
    623     builtin trap --usage 2>&1 1>/dev/null | ble/bin/grep ^trap >&2
    624     ble/base/.restore-bash-options set shopt
    625     return 2
    626   elif [[ $flags == *l* ]]; then
    627     builtin trap -l
    628   fi
    629 
    630   [[ ! $_ble_attached || $_ble_edit_exec_inside_userspace ]] &&
    631     ble/base/adjust-BASH_REMATCH
    632 
    633   if [[ $flags == *[pP]* ]]; then
    634     local -a indices=()
    635     if ((${#sigspecs[@]})); then
    636       local spec ret
    637       for spec in "${sigspecs[@]}"; do
    638         if ! ble/builtin/trap/sig#resolve "$spec"; then
    639           ble/util/print "ble/builtin/trap: invalid signal specification \"$spec\"." >&2
    640           continue
    641         fi
    642         ble/array#push indices "$ret"
    643       done
    644     else
    645       indices=("${!_ble_builtin_trap_handlers[@]}" "$_ble_builtin_trap_RETURN")
    646     fi
    647 
    648     local q=\' Q="'\''" index _ble_trap_handler
    649     for index in "${indices[@]}"; do
    650       if ble/builtin/trap/user-handler#load "$index"; then
    651         if [[ $flags == *p* ]]; then
    652           local n=${_ble_builtin_trap_sig_name[index]}
    653           _ble_trap_handler="trap -- '${_ble_trap_handler//$q/$Q}' $n"
    654         fi
    655         ble/util/print "$_ble_trap_handler"
    656       fi
    657     done
    658   else
    659     # Ignore ble.sh handlers of the previous session
    660     [[ $_ble_builtin_trap_user_handler_init ]] &&
    661       ble/builtin/trap/user-handler/is-internal "$command" &&
    662       return 0
    663 
    664     local _ble_builtin_trap_inside=1
    665     local spec ret
    666     for spec in "${sigspecs[@]}"; do
    667       if ! ble/builtin/trap/sig#resolve "$spec"; then
    668         ble/util/print "ble/builtin/trap: invalid signal specification \"$spec\"." >&2
    669         continue
    670       fi
    671       local sig=$ret
    672       local name=${_ble_builtin_trap_sig_name[sig]}
    673       ble/builtin/trap/user-handler#save "$sig" "$command"
    674       [[ $_ble_builtin_trap_user_handler_init ]] && continue
    675 
    676       local trap_command='builtin trap -- "$command" "$spec"'
    677       local install_opts=${_ble_builtin_trap_sig_opts[sig]}
    678       if [[ $install_opts ]]; then
    679         local custom_trap=ble/builtin/trap:$name
    680         if ble/is-function "$custom_trap"; then
    681           trap_command='"$custom_trap" "$command" "$spec"'
    682         elif [[ :$install_opts: == *:readline:* ]] && ! ble/util/is-running-in-subshell; then
    683           # Note (#D1345 #D1862): readline 介入を破壊しない為に親シェル内部では
    684           # builtin trap 再設定はしない。
    685           trap_command=
    686         elif [[ $command == - ]]; then
    687           if [[ :$install_opts: == *:inactive:* ]]; then
    688             # Note #D1858: 単に ble/builtin/trap/.handler 経由で処理する trap の場合。
    689             # trap を解除する時にはそのまま解除して良い。
    690             trap_command='builtin trap - "$spec"'
    691           else
    692             # Note #D1858: 内部処理の為に trap は常設しているので、trap の削除
    693             # はしない。だからと言って改めて内部処理の為のコマンドを登録する訳
    694             # でもない (特に subshell の中で改めて実行したい訳でもなければ)。
    695             trap_command=
    696           fi
    697         elif [[ :$install_opts: == *:override-builtin-signal:* ]]; then
    698           # Note #D1862: 内部処理の為に trap を常設していたとしても EXIT 等の
    699           # 様に subshell に継承されない trap があるので毎回明示的に builtin
    700           # trap を実行する。
    701           ble/builtin/trap/install-hook/.compose-trap_command "$sig"
    702           trap_command="builtin $trap_command"
    703         else
    704           # ble/builtin/trap/{.register,reserve} で登録したカスタム trap の場合
    705           # は builtin trap 関係の操作は何もしない。発火の制御に関しては
    706           # ble/builtin/trap/invoke を適切な場所で呼び出す様に実装するべき。
    707           trap_command=
    708         fi
    709       fi
    710 
    711       if [[ $trap_command ]]; then
    712         # Note #D1858: set -E (-o errtrace) が設定されていない限り、関数の中か
    713         # ら trap ERR を削除する事はできない。仕方がないので空の command を
    714         # trap として設定する事にする。元々 trap ERR が設定されていない時の動作
    715         # は「何もしない」なので空文字列で問題ないはず。
    716         if [[ $name == ERR && $command == - && $- != *E* ]]; then
    717           command=
    718         fi
    719         builtin eval -- "$trap_command"
    720       fi
    721     done
    722   fi
    723 
    724   [[ ! $_ble_attached || $_ble_edit_exec_inside_userspace ]] &&
    725     ble/base/restore-BASH_REMATCH
    726   ble/base/.restore-bash-options set shopt
    727   return 0
    728 }
    729 function trap { ble/builtin/trap "$@"; }
    730 ble/builtin/trap/user-handler#init
    731 
    732 function ble/builtin/trap/.TRAPRETURN {
    733   local IFS=$_ble_term_IFS
    734   local backtrace=" ${BLE_TRAP_FUNCNAME[*]-} "
    735   case $backtrace in
    736   # 呼び出し元が RETURN trap の設置に用いた trap の時は RETURN は無視する。それ
    737   # 以外の trap 呼び出しについても無視して良い。
    738   (' trap '* | ' ble/builtin/trap '*) return 126 ;;
    739   # ble/builtin/trap/.handler 内部処理に対する RETURN は無視するが、
    740   # ble/builtin/trap/.handler から更に呼び出された blehook / trap_string の中で
    741   # 呼び出されている関数については RETURN を発火させる。
    742   (*' ble/builtin/trap/.handler '*)
    743     case ${backtrace%%' ble/builtin/trap/.handler '*}' ' in
    744     (' '*' blehook/invoke.sandbox '* | ' '*' ble/builtin/trap/invoke.sandbox '*) ;;
    745     (*) return 126 ;;
    746     esac ;;
    747   # 待避処理をしていないユーザーコマンド実行後に呼び出される関数達。
    748   (*' ble-edit/exec:gexec/.save-lastarg ' | ' _ble_edit_exec_gexec__TRAPDEBUG_adjust ') return 126 ;;
    749   esac
    750   return 0
    751 }
    752 blehook internal_RETURN!=ble/builtin/trap/.TRAPRETURN
    753 
    754 # user trap handler 専用の $?, $_ の記録。
    755 _ble_builtin_trap_user_lastcmd=
    756 _ble_builtin_trap_user_lastarg=
    757 _ble_builtin_trap_user_lastexit=
    758 ## @fn ble/builtin/trap/invoke.sandbox params...
    759 ##   @param[in] params...
    760 ##   @var[in] _ble_trap_handler
    761 ##   @var[out] _ble_trap_done
    762 ##   @var[in,out] _ble_trap_lastexit _ble_trap_lastarg
    763 function ble/builtin/trap/invoke.sandbox {
    764   local _ble_trap_count
    765   for ((_ble_trap_count=0;_ble_trap_count<1;_ble_trap_count++)); do
    766     _ble_trap_done=return
    767     # Note #D1757: そのまま制御を変更せずに trap handler の実行が終わっ
    768     # た時は $? $_ を保存する。同じ eval の中でないと $_ が eval を抜
    769     # けた時に eval の最終引数に置き換えられてしまう事に注意する。
    770     ble/util/setexit "$_ble_trap_lastexit" "$_ble_trap_lastarg"
    771     builtin eval -- "$_ble_trap_handler"$'\n_ble_trap_lastexit=$? _ble_trap_lastarg=$_' 2>&3
    772     _ble_trap_done=done
    773     return 0
    774   done
    775   _ble_trap_lastexit=$? _ble_trap_lastarg=$_
    776 
    777   # break/continue 検出
    778   if ((_ble_trap_count==0)); then
    779     _ble_trap_done=break
    780   else
    781     _ble_trap_done=continue
    782   fi
    783   return 0
    784 }
    785 ## @fn ble/builtin/trap/invoke sig params...
    786 ##   @param[in] sig
    787 ##   @param[in] params...
    788 ##   @var[in] ? _
    789 ##   @var[in,out] _ble_builtin_trap_postproc[sig]
    790 ##   @var[in,out] _ble_builtin_trap_lastarg[sig]
    791 function ble/builtin/trap/invoke {
    792   local _ble_trap_lastexit=$? _ble_trap_lastarg=$_ _ble_trap_sig=$1; shift
    793   if [[ ${_ble_trap_sig//[0-9]} ]]; then
    794     local ret
    795     ble/builtin/trap/sig#resolve "$_ble_trap_sig" || return 1
    796     _ble_trap_sig=$ret
    797     ble/util/unlocal ret
    798   fi
    799 
    800   local _ble_trap_handler
    801   ble/builtin/trap/user-handler#load "$_ble_trap_sig"
    802   [[ $_ble_trap_handler ]] || return 0
    803 
    804   # restore $_ and $? for user trap handlers
    805   if [[ $_ble_attached && ! $_ble_edit_exec_inside_userspace ]]; then
    806     if [[ $_ble_builtin_trap_user_lastcmd != $_ble_edit_CMD ]]; then
    807       _ble_builtin_trap_user_lastcmd=$_ble_edit_CMD
    808       _ble_builtin_trap_user_lastexit=$_ble_edit_exec_lastexit
    809       _ble_builtin_trap_user_lastarg=$_ble_edit_exec_lastarg
    810     fi
    811     _ble_trap_lastexit=$_ble_builtin_trap_user_lastexit
    812     _ble_trap_lastarg=$_ble_builtin_trap_user_lastarg
    813   fi
    814 
    815   local _ble_trap_done=
    816   ble/builtin/trap/invoke.sandbox "$@"; local ext=$?
    817   case $_ble_trap_done in
    818   (done)
    819     _ble_builtin_trap_lastarg[_ble_trap_sig]=$_ble_trap_lastarg
    820     _ble_builtin_trap_postproc[_ble_trap_sig]="ble/util/setexit $_ble_trap_lastexit" ;;
    821   (break | continue)
    822     _ble_builtin_trap_lastarg[_ble_trap_sig]=$_ble_trap_lastarg
    823     if ble/string#match "$_ble_trap_lastarg" '^-?[0-9]+$'; then
    824       _ble_builtin_trap_postproc[_ble_trap_sig]="$_ble_trap_done $_ble_trap_lastarg"
    825     else
    826       _ble_builtin_trap_postproc[_ble_trap_sig]=$_ble_trap_done
    827     fi ;;
    828   (return)
    829     # Note #D1757: return 自体の lastarg は最早取得できないが、もし
    830     # 仮に直接 builtin trap で実行されたとしても、return で関数を抜
    831     # けた時に lastarg は書き換えられるので取得できない。精々関数を
    832     # 呼び出す前の lastarg を設定して置いて return が失敗した時に前
    833     # の状態を keep するぐらいしかない気がする。
    834     _ble_builtin_trap_lastarg[_ble_trap_sig]=$ext
    835     _ble_builtin_trap_postproc[_ble_trap_sig]="return $ext" ;;
    836   (exit)
    837     # Note #D1782: trap handler の中で ble/builtin/exit (edit.sh) を呼
    838     #   び出した時は、即座に bash を終了せずに取り敢えずは trap の処理
    839     #   は完了させる。TRAPDEBUGによって _ble_trap_done=exit が設定され
    840     #   る。また、元々 exit に渡された引数は $_ble_trap_lastarg に設定
    841     #   される。
    842     # Note #D1782: 他の trap の中で更にまた DEBUG trap が起動している
    843     #   時などの為に、builtin exit ではなく ble/builtin/exit を再度呼
    844     #   び出し直す。
    845     _ble_builtin_trap_lastarg[_ble_trap_sig]=$_ble_trap_lastarg
    846     _ble_builtin_trap_postproc[_ble_trap_sig]="ble/builtin/exit $_ble_trap_lastarg" ;;
    847   esac
    848 
    849   # save $_ and $? for user trap handlers
    850   if [[ $_ble_attached && ! $_ble_edit_exec_inside_userspace ]]; then
    851     _ble_builtin_trap_user_lastexit=$_ble_trap_lastexit
    852     _ble_builtin_trap_user_lastarg=$_ble_trap_lastarg
    853   fi
    854 
    855   return 0
    856 } 3>&2 2>/dev/null # set -x 対策 #D0930
    857 
    858 ## @var _ble_builtin_trap_processing
    859 ##   ble/builtin/trap/.handler 実行中かどうかを表すローカル変数です。
    860 ##   以下の二つの形式の内のどちらかを取ります。
    861 ##
    862 ##   SUBSHELL/SIG
    863 ##     SUBSHELL は trap 処理の実行元のサブシェルの深さ (呼び出し元にお
    864 ##     ける BASH_SUBSHELL の値) を記録します。SIG はシグナルを表す整数
    865 ##     値です。
    866 ##
    867 ##   SUBSHELL/exit:EXIT
    868 ##     EXIT は ble/builtin/exit に渡された終了ステータスで、これは最終
    869 ##     的な exit で使われる終了ステータスです。
    870 ##
    871 _ble_builtin_trap_processing=
    872 _ble_builtin_trap_postproc=()
    873 _ble_builtin_trap_lastarg=()
    874 function ble/builtin/trap/install-hook/.compose-trap_command {
    875   local sig=$1 name=${_ble_builtin_trap_sig_name[$1]}
    876   local handler='ble/builtin/trap/.handler SIGNUM "$BASH_COMMAND" "$@"; builtin eval -- "${_ble_builtin_trap_postproc[SIGNUM]}" \# "${_ble_builtin_trap_lastarg[SIGNUM]}"'
    877   trap_command="trap -- '${handler//SIGNUM/$sig}' $name" # WA #D1738 checked (sig is integer)
    878 }
    879 
    880 _ble_trap_builtin_handler_DEBUG_filter=
    881 
    882 ## @fn ble/builtin/trap/.handler sig bash_command params...
    883 ##   @param[in] sig
    884 ##     Specifies the signal number
    885 ##   @param[in] bash_command
    886 ##     Specifies the value of BASH_COMMAND in the original context
    887 ##   @param[in] params...
    888 ##     Specifies the positional parameters in the original context
    889 ##   @var[in] _ble_builtin_trap_depth
    890 ##   @var[out] _ble_builtin_trap_xlastarg[_ble_builtin_trap_depth]
    891 ##   @var[out] _ble_builtin_trap_xpostproc[_ble_builtin_trap_depth]
    892 function ble/builtin/trap/.handler {
    893   local _ble_trap_lastexit=$? _ble_trap_lastarg=$_ FUNCNEST= IFS=$_ble_term_IFS
    894   local _ble_trap_sig=$1 _ble_trap_bash_command=$2
    895   shift 2
    896 
    897   # Note: bash-5.2 では read -t の最中に WINCH が来るとその場で発火して変なこと
    898   #   が色々起こる。(1) 内部で ble/util/msleep を実行しようとすると外側の
    899   #   timeout 設定が削除されて、外側の read -t が永遠に終わらない状態になる。特
    900   #   に msleep では終端しないストリームから読み出そうとするのでデッドロックす
    901   #   る。(2) 中でコマンド置換 $() や mapfile を使おうとすると、
    902   #   run_pending_trap (trap.c) が途中で予期せず中断してしまって running_trap
    903   #   が放置された状態になる。trap 処理入れ子状態になってしまってずっと WINCH
    904   #   を受信できない状態になってしまう。
    905   if [[ $_ble_bash_read_winch && ${_ble_builtin_trap_sig_name[_ble_trap_sig]} == SIGWINCH ]]; then
    906     local ret
    907     ble/string#quote-command "$FUNCNAME" "$_ble_trap_sig" "$_ble_trap_bash_command" "$@"
    908     _ble_bash_read_winch=$ret$'\n''builtin eval -- "${_ble_builtin_trap_postproc['$_ble_trap_sig']}"'
    909     return 0
    910   fi
    911 
    912   # Early filter for frequently called DEBUG (set by edit.sh)
    913   if ((_ble_trap_sig==_ble_builtin_trap_DEBUG)) &&
    914        ! builtin eval -- "$_ble_trap_builtin_handler_DEBUG_filter"; then
    915     _ble_builtin_trap_lastarg[_ble_trap_sig]=${_ble_trap_lastarg//*$_ble_term_nl*}
    916     _ble_builtin_trap_postproc[_ble_trap_sig]="ble/util/setexit $_ble_trap_lastexit"
    917     return 0
    918   fi
    919 
    920   # Adjust trap context
    921   local _ble_trap_set _ble_trap_shopt; ble/base/.adjust-bash-options _ble_trap_set _ble_trap_shopt
    922   local _ble_trap_name=${_ble_builtin_trap_sig_name[_ble_trap_sig]#SIG}
    923   local -a _ble_trap_args; _ble_trap_args=("$@")
    924   if [[ ! $_ble_trap_bash_command ]] || ((_ble_bash<30200)); then
    925     # Note: Bash 3.0, 3.1 は trap 中でも BASH_COMMAND は trap 発動対象ではなく
    926     # て現在実行中のコマンドになっている。_ble_trap_bash_command には単に
    927     # ble/builtin/trap/.handler が入っているので別の適当な値で置き換える。
    928     if [[ $_ble_attached ]]; then
    929       _ble_trap_bash_command=$_ble_edit_exec_BASH_COMMAND
    930     else
    931       ble/util/assign _ble_trap_bash_command 'HISTTIMEFORMAT=__ble_ext__ builtin history 1'
    932       _ble_trap_bash_command=${_ble_trap_bash_command#*__ble_ext__}
    933     fi
    934   fi
    935 
    936   local _ble_builtin_trap_processing=${BASH_SUBSHELL:-0}/$_ble_trap_sig
    937   _ble_builtin_trap_lastarg[_ble_trap_sig]=$_ble_trap_lastarg
    938   _ble_builtin_trap_postproc[_ble_trap_sig]="ble/util/setexit $_ble_trap_lastexit"
    939 
    940   # Note #D1782: ble/builtin/exit で "builtin exit ... &>/dev/null" と
    941   #   したリダイレクションを元に戻す。元々 builtin exit が出力するエラー
    942   #   を無視する為のリダイレクトだが、続いて呼び出される EXIT trap に
    943   #   対してもこのリダイレクションが有効なままになる (但し、
    944   #   bash-4.4..5.1 ではバグで top-level まで制御を戻してから EXIT
    945   #   trap 他の処理が実行されるので、EXIT trap は tty に繋がった状態で
    946   #   実行される)。他の trap が予期せず呼び出された場合にも同様の事が
    947   #   起こる。trap handler を exit を実行した文脈での stdout/stderr で
    948   #   実行する為に、stdout/stderr を保存していた物に繋ぎ戻す。
    949   if [[ $_ble_builtin_exit_processing ]]; then
    950     exec 1>&- 1>&"$_ble_builtin_exit_stdout"
    951     exec 2>&- 2>&"$_ble_builtin_exit_stderr"
    952   fi
    953 
    954   local BLE_TRAP_FUNCNAME BLE_TRAP_SOURCE BLE_TRAP_LINENO
    955   BLE_TRAP_FUNCNAME=("${FUNCNAME[@]:1}")
    956   BLE_TRAP_SOURCE=("${BASH_SOURCE[@]:1}")
    957   BLE_TRAP_LINENO=("${BASH_LINENO[@]}")
    958   [[ $_ble_attached ]] &&
    959     BLE_TRAP_LINENO[${#BASH_LINENO[@]}-1]=$_ble_edit_LINENO
    960 
    961   # ble.sh internal hook
    962   ble/util/joblist.check
    963   ble/util/setexit "$_ble_trap_lastexit" "$_ble_trap_lastarg"
    964   blehook/invoke "internal_$_ble_trap_name"; local internal_ext=$?
    965   ble/util/joblist.check ignore-volatile-jobs
    966 
    967   if ((internal_ext!=126)); then
    968     if ! ble/util/is-running-in-subshell; then
    969       # blehook (only activated in parent shells)
    970       ble/util/setexit "$_ble_trap_lastexit" "$_ble_trap_lastarg"
    971       BASH_COMMAND=$_ble_trap_bash_command \
    972         blehook/invoke "$_ble_trap_name"
    973       ble/util/joblist.check ignore-volatile-jobs
    974     fi
    975 
    976     # user hook
    977     local install_opts=${_ble_builtin_trap_sig_opts[_ble_trap_sig]}
    978     if [[ :$_ble_tra_opts: == *:user-trap-in-postproc:* ]]; then
    979       # ユーザートラップを外で実行 (Note: user-trap lastarg は反映されず)
    980       local q=\' Q="'\''" _ble_trap_handler postproc=
    981       ble/builtin/trap/user-handler#load "$_ble_trap_sig"
    982       if [[ $_ble_trap_handler == *[![:space:]]* ]]; then
    983         postproc="ble/util/setexit $_ble_trap_lastexit '${_ble_trap_lastarg//$q/$Q}'"
    984         postproc=$postproc";LINENO=$BLE_TRAP_LINENO builtin eval -- '${_ble_trap_handler//$q/$Q}'"
    985       else
    986         postproc="ble/util/setexit $_ble_trap_lastexit"
    987       fi
    988       _ble_builtin_trap_postproc[_ble_trap_sig]=$postproc
    989     else
    990       ble/util/setexit "$_ble_trap_lastexit" "$_ble_trap_lastarg"
    991       BASH_COMMAND=$_ble_trap_bash_command LINENO=$BLE_TRAP_LINENO \
    992         ble/builtin/trap/invoke "$_ble_trap_sig" "${_ble_trap_args[@]}"
    993     fi
    994   fi
    995 
    996   # 何処かの時点で exit が要求された場合
    997   if [[ $_ble_builtin_trap_processing == */exit:* && ${_ble_builtin_trap_postproc[_ble_trap_sig]} != 'ble/builtin/exit '* ]]; then
    998     _ble_builtin_trap_postproc[_ble_trap_sig]="ble/builtin/exit ${_ble_builtin_trap_processing#*/exit:}"
    999   fi
   1000 
   1001   # Note #D1757: 現在 eval が終わった後の $_ を設定する為には eval に
   1002   # '#' "$lastarg" を余分に渡すしかないので改行を含める事はできない。
   1003   # 中途半端な値を設定するよりは最初から何も設定しない事にする。ここ設
   1004   # 定する lastarg は一見して誰も使わない様な気がするが、裸で設定され
   1005   # た user trap が参照するかもしれないので一応設定する。
   1006   [[ ${_ble_builtin_trap_lastarg[_ble_trap_sig]} == *$'\n'* ]] &&
   1007     _ble_builtin_trap_lastarg[_ble_trap_sig]=
   1008 
   1009   if ((_ble_trap_sig==_ble_builtin_trap_EXIT)); then
   1010     # Note #D1797: EXIT に対する ble/base/unload は trap handler のできるだけ最
   1011     # 後に実行する。勝手に削除されても困るし、他の handler が ble.sh の機能を使っ
   1012     # た時に問題が起こらない様にする為。
   1013     ble/base/unload EXIT
   1014   elif ((_ble_trap_sig==_ble_builtin_trap_RETURN)); then
   1015     # Note #D1863: RETURN trap の呼び出し元への継承処理を実行する。
   1016     ble/builtin/trap/user-handler#update:RETURN
   1017   fi
   1018 
   1019   ble/base/.restore-bash-options _ble_trap_set _ble_trap_shopt
   1020 }
   1021 
   1022 ## @fn ble/builtin/trap/install-hook sig [opts]
   1023 ##   @param[in] sig
   1024 ##     シグナル名、もしくは番号
   1025 ##   @param[in,opt] opts
   1026 ##     readline readline による処理が追加されることが期待される trap handler で
   1027 ##              ある事を示します。既に設定済みのハンドラーが存在している場合に
   1028 ##              はハンドラーの再設定を行いません。
   1029 ##     inactive ユーザートラップが設定されていない時は builtin trap からハンド
   1030 ##              ラの登録を削除します。
   1031 function ble/builtin/trap/install-hook {
   1032   local ret opts=${2-}
   1033   ble/builtin/trap/sig#resolve "$1"
   1034   local sig=$ret name=${_ble_builtin_trap_sig_name[ret]}
   1035   ble/builtin/trap/sig#reserve "$sig" "override-builtin-signal:$opts"
   1036 
   1037   local trap_command; ble/builtin/trap/install-hook/.compose-trap_command "$sig"
   1038   local trap_string; ble/util/assign trap_string "builtin trap -p $name"
   1039 
   1040   if [[ :$opts: == *:readline:* ]] && ! ble/util/is-running-in-subshell; then
   1041     # Note #D1345: ble.sh の内部で "builtin trap -- WINCH" 等とすると
   1042     # readline の処理が行われなくなってしまう (COLUMNS, LINES が更新さ
   1043     # れない)。
   1044     #
   1045     # Bash では TSTP, TTIN, TTOU, INT, TERM, HUP, QUIT, WINCH について
   1046     # は readline が処理を追加している。builtin trap を実行すると、一旦
   1047     # は trap の設定した trap_handler が設定されるが、"コマンド実行後"
   1048     # に readline が rl_maybe_set_sighandler という関数を用いて上書きし
   1049     # てreadline 特有の処理を挿入する。ble.sh は readline の "コマンド
   1050     # 実行"を使わないので、readline による追加処理が消滅する。
   1051     #
   1052     # 対策として、今から登録しようとしている文字列が既に登録されている
   1053     # 物と一致する場合には、builtin trap の呼び出しを省略する。
   1054     #
   1055     # - 現状では問題になっているのは WINCH だけなので取り敢えず WINCH
   1056     #   だけ対策をする。
   1057     # - INT は bind -x 内だと改めて設定しないと有効にならない(?)様なの
   1058     #   で既に登録されていても、builtin trap は省略できない。
   1059     #
   1060     [[ $trap_command == "$trap_string" ]] && trap_command= trap_string=
   1061 
   1062     # Note (#D2021): reload 時に元の trap が保存されていればそれを読み取る。
   1063     [[ $trap_string ]] || trap_string=${_ble_builtin_trap_handlers_reload[sig]-}
   1064   fi
   1065 
   1066   [[ ! $trap_command || :$opts: == *:inactive:* && ! $trap_string ]] ||
   1067     builtin eval "builtin $trap_command"; local ext=$?
   1068 
   1069   local q=\'
   1070   if [[ $trap_string == "trap -- '"* ]] && ! ble/builtin/trap/user-handler/is-internal "${trap_string#*$q}"; then
   1071     # Note: 1000 以上はデバグ用の trap (DEBUG, RETURN, EXIT) で既定では trapが
   1072     # 関数呼び出しで継承されないので、trap_string の内容は信用できない。
   1073     ((sig<1000)) &&
   1074       # Note: 既存の handler がない時のみ設定を読み取る。既存の設定がある時は
   1075       # ble.sh をロードしてから trap が実行された事を意味する。一方で、ble.sh
   1076       # がロードされて以降に builtin trap の設定がユーザーによって直接変更され
   1077       # る事は想定していないので、builtin trap から読み取った結果は ble.sh ロー
   1078       # ド前と想定して良い。
   1079       ! ble/builtin/trap/user-handler#has "$sig" &&
   1080       builtin eval -- "ble/builtin/$trap_string"
   1081   fi
   1082 
   1083   return "$ext"
   1084 }