@@ -260,6 +260,124 @@ _upvars()
260260 done
261261}
262262
263+ # Filter the array elements with the specified condition.
264+ # @param $1 Array name (that is not "value" or other internal variable names)
265+ # @param $2 When none of the options -EFG are specified, this is used as the
266+ # command that tests the array element. If this is an existing function
267+ # name, the function is called with the value of the array element.
268+ # Otherwise, this shall be the shell command that tests the array-element
269+ # value stored in the shell variable "value".
270+ #
271+ # Options:
272+ # -E $2 is interpreted as a POSIX extended regular expression.
273+ # This is always the partial matching unless ^, $ is included
274+ # in $2.
275+ # -F $2 is interpreted as a fixed string.
276+ # -G $2 is interpreted as a glob pattern.
277+ #
278+ # -p Combined with -F or -G, it performs the prefix matching.
279+ # -s Combined with -F or -G, it performs the suffix matching.
280+ # -m Combined with -F or -G, it performs the middle matching.
281+ # -r Revert the condition, i.e., remove elements that satisfy
282+ # the original condition.
283+ #
284+ # -C Array compaction is not performed.
285+ #
286+ # @return 2 with a wrong usage, 1 when any elements are removed, 0 when the set
287+ # of array elements are unchanged. [ Note: the compaction will be performed
288+ # (without the option -C) even when the set of array elements are
289+ # unchanged. ]
290+ _comp_array_filter ()
291+ {
292+ local __comp_flags=' ' __comp_pattype=' ' __comp_anchoring=' '
293+ local OPTIND=1 OPTARG=' ' OPTERR=0 __comp_opt=' '
294+ while getopts ' EFGpsmrC' __comp_opt " $@ " ; do
295+ case $__comp_opt in
296+ [EFG]) __comp_pattype=$__comp_opt ;;
297+ [psm]) __comp_anchoring=$__comp_opt ;;
298+ [rC]) __comp_flags=$__comp_opt$__comp_flags ;;
299+ * )
300+ echo " bash_completion: $FUNCNAME : usage error" >&2
301+ return 2
302+ ;;
303+ esac
304+ done
305+
306+ shift $(( OPTIND - 1 ))
307+ if (( $# != 2 )) ; then
308+ printf ' bash_completion: %s: %s\n' " $FUNCNAME " " unexpected number of arguments." >&2
309+ printf ' usage: %s %s\n' " $FUNCNAME " " [-EFGpsmrC] ARRAY_NAME CONDITION" >&2
310+ return 2
311+ elif [[ $1 != [a-zA-Z_]* ([a-zA-Z_0-9]) ]]; then
312+ printf ' bash_completion: %s: %s\n' " $FUNCNAME " " invalid array name '$1 '." >&2
313+ return 2
314+ elif [[ $1 == @ (__comp_* | OPTIND| OPTARG| OPTERR) ]]; then
315+ printf ' bash_completion: %s: %s\n' " $FUNCNAME " " array name '$1 ' is reserved for internal uses." >&2
316+ return 2
317+ elif [[ ! $__comp_pattype && $1 == value ]]; then
318+ printf ' bash_completion: %s: %s\n' " $FUNCNAME " " array name '$1 ' cannot be used for the predicate." >&2
319+ return 2
320+ fi
321+ # When the array is empty:
322+ eval " ((\$ {#$1 [@]}))" || return 0
323+
324+ local __comp_predicate=' ' __comp_pattern=$2
325+ case $__comp_pattype in
326+ E)
327+ __comp_predicate=' [[ $__comp_value == $__comp_pattern ]]'
328+ ;;
329+ F)
330+ case $__comp_anchoring in
331+ p) __comp_predicate=' [[ $__comp_value == "$__comp_pattern"* ]]' ;;
332+ s) __comp_predicate=' [[ $__comp_value == *"$__comp_pattern" ]]' ;;
333+ m) __comp_predicate=' [[ $__comp_value == *"$__comp_pattern"* ]]' ;;
334+ * ) __comp_predicate=' [[ $__comp_value == "$__comp_pattern" ]]' ;;
335+ esac
336+ ;;
337+ G)
338+ case $__comp_anchoring in
339+ p) __comp_predicate=' [[ $__comp_value == $__comp_pattern* ]]' ;;
340+ s) __comp_predicate=' [[ $__comp_value == *$__comp_pattern ]]' ;;
341+ m) __comp_predicate=' [[ $__comp_value == *$__comp_pattern* ]]' ;;
342+ * ) __comp_predicate=' [[ $__comp_value == $__comp_pattern ]]' ;;
343+ esac
344+ ;;
345+ * )
346+ if declare -F " $2 " & > /dev/null; then
347+ _comp_predicate=" $2 \"\$ __comp_value\" "
348+ else
349+ _comp_predicate=" local value=\$ __comp_value; $2 "
350+ fi
351+ ;;
352+ esac
353+
354+ local __comp_unset=' ' __comp_expected_status=0
355+ [[ $__comp_flags == * r* ]] && __comp_expected_status=1
356+
357+ local __comp_indices __comp_index __comp_value
358+ eval " __comp_indices=(\"\$ {!$1 [@]}\" )"
359+ for __comp_index in " ${__comp_indices[@]} " ; do
360+ eval " __comp_value=\$ {$1 [\$ __comp_index]}; $__comp_predicate "
361+ case $? in
362+ " $__comp_expected_status " ) continue ;;
363+ [01])
364+ unset -v " $1 [\$ __comp_index]"
365+ __comp_unset=1
366+ ;;
367+ * )
368+ printf ' bash_completion: %s: %s\n' " $FUNCNAME " " the filter condition broken." >&2
369+ return 2
370+ ;;
371+ esac
372+ done
373+
374+ # Compaction of the sparse array
375+ [[ $__comp_flags == * C* ]] ||
376+ eval -- " ((\$ {#$1 [@]})) && $1 =(\"\$ {$1 [@]}\" )"
377+
378+ [[ ! $__comp_unset ]]
379+ }
380+
263381# Reassemble command line words, excluding specified characters from the
264382# list of word completion separators (COMP_WORDBREAKS).
265383# @param $1 chars Characters out of $COMP_WORDBREAKS which should
0 commit comments