blob: 2c464dd8c2f31e7cd6622910216986993b9bf46e [file] [log] [blame]
Michael Walsh61ce3e82019-05-29 17:14:47 -05001#!/bin/bash
2
3# This file contains list-manipulation functions.
4
Michael Walsh410b1782019-10-22 15:56:18 -05005# A list is defined here as a string of items separated by some delimiter. The PATH variable is one such
6# example.
Michael Walsh61ce3e82019-05-29 17:14:47 -05007
8if ! test "${default_delim+defined}" ; then
Patrick Williams90dfee32022-12-08 06:52:46 -06009 readonly default_delim=" "
Michael Walsh61ce3e82019-05-29 17:14:47 -050010fi
11
Michael Walsh410b1782019-10-22 15:56:18 -050012# Performance note: It is important for these functions to run quickly. One way to increase their speed is
13# to avoid copying function arguments to local variables and to instead use numbered arguments (e.g. ${1},
14# {2}, etc.) to access the arguments from inside the functions. In some trials, this doubled the speed of
15# the functions. The cost of this is that it makes the functions slightly more difficult to read.
Michael Walsh61ce3e82019-05-29 17:14:47 -050016
17
Patrick Williams90dfee32022-12-08 06:52:46 -060018function add_list_element() {
19 # local list_element="${1}"
20 # local list_name="${2}"
21 # local delim="${3:-${default_delim}}"
22 # local position="${4:-back}"
Michael Walsh61ce3e82019-05-29 17:14:47 -050023
Patrick Williams90dfee32022-12-08 06:52:46 -060024 # Add the list_element to the list named in list_name.
Michael Walsh61ce3e82019-05-29 17:14:47 -050025
Patrick Williams90dfee32022-12-08 06:52:46 -060026 # Description of argument(s):
27 # list_element The list element to be added.
28 # list_name The name of the list to be modified.
29 # delim The delimiter used to separate list elements.
30 # position Indicates the position in the list where the new element should be added
31 # ("front"/"back").
Michael Walsh61ce3e82019-05-29 17:14:47 -050032
Patrick Williams90dfee32022-12-08 06:52:46 -060033 if [ -z "${!2}" ] ; then
34 # The list is blank. Simply assign it the list_element value and return.
35 eval "${2}=\"${1}\""
36 return
37 fi
Michael Walsh61ce3e82019-05-29 17:14:47 -050038
Patrick Williams90dfee32022-12-08 06:52:46 -060039 if [ "${4:-back}" == "back" ] ; then
40 # Append the list_element to the back of the list and return.
41 eval "${2}=\"\${${2}}\${3-${default_delim}}\${1}\""
42 return
43 fi
Michael Walsh61ce3e82019-05-29 17:14:47 -050044
Patrick Williams90dfee32022-12-08 06:52:46 -060045 # Append the list_element to the front of the list and return.
46 eval "${2}=\"\${1}\${3-${default_delim}}\${${2}}\""
Michael Walsh61ce3e82019-05-29 17:14:47 -050047
48}
49
50
Patrick Williams90dfee32022-12-08 06:52:46 -060051function remove_list_element() {
52 # local list_element="${1}"
53 # local list_name="${2}"
54 local delim="${3:-${default_delim}}"
Michael Walsh61ce3e82019-05-29 17:14:47 -050055
Patrick Williams90dfee32022-12-08 06:52:46 -060056 # Remove all occurrences of list_element from the list named in list_name.
Michael Walsh61ce3e82019-05-29 17:14:47 -050057
Patrick Williams90dfee32022-12-08 06:52:46 -060058 # Description of argument(s):
59 # list_element The list element to be removed.
60 # list_name The name of the list to be modified.
61 # delim The delimiter used to separate list elements.
Michael Walsh61ce3e82019-05-29 17:14:47 -050062
Patrick Williams90dfee32022-12-08 06:52:46 -060063 local __rle_new_list__="${!2}"
Michael Walsh61ce3e82019-05-29 17:14:47 -050064
Patrick Williams90dfee32022-12-08 06:52:46 -060065 # Special case: The list contains one element which matches the specified list element:
66 if [ "${1}" == "${__rle_new_list__}" ] ; then
67 eval ${2}=\"\"
68 return
69 fi
Michael Walsh61ce3e82019-05-29 17:14:47 -050070
Patrick Williams90dfee32022-12-08 06:52:46 -060071 # Replace all occurrences of list_element that are bounded by the delimiter on both sides.
72 __rle_new_list__="${__rle_new_list__//${delim}${1}${delim}/${delim}}"
73 # Replace list_item if it occurs at the beginning of the string and is bounded on the right by the
74 # delimiter.
75 __rle_new_list__="${__rle_new_list__#${1}${delim}}"
76 # Replace list_item if it occurs at the end of the string and is bounded on the left by the delimiter.
77 __rle_new_list__="${__rle_new_list__%${delim}${1}}"
Michael Walsh61ce3e82019-05-29 17:14:47 -050078
Patrick Williams90dfee32022-12-08 06:52:46 -060079 # Set caller's variable to new value.
80 eval ${2}=\"\${__rle_new_list__}\"
Michael Walsh61ce3e82019-05-29 17:14:47 -050081
82}
83
84
Patrick Williams90dfee32022-12-08 06:52:46 -060085function cleanup_path_slashes() {
86 local var_name="${1}" ; shift
Michael Walsh61ce3e82019-05-29 17:14:47 -050087
Patrick Williams90dfee32022-12-08 06:52:46 -060088 # For the variable named in var_name, replace all multiple-slashes with single slashes and strip any
89 # trailing slash.
Michael Walsh61ce3e82019-05-29 17:14:47 -050090
Patrick Williams90dfee32022-12-08 06:52:46 -060091 # Description of argument(s):
92 # var_name The name of the variable whose contents are to be changed.
Michael Walsh61ce3e82019-05-29 17:14:47 -050093
Patrick Williams90dfee32022-12-08 06:52:46 -060094 local cmd_buf
Michael Walsh61ce3e82019-05-29 17:14:47 -050095
Patrick Williams90dfee32022-12-08 06:52:46 -060096 cmd_buf="${var_name}=\$(echo \"\${${var_name}}\" | sed -re 's#[/]+#/#g' -e 's#/\$##g')"
97 eval "${cmd_buf}"
Michael Walsh61ce3e82019-05-29 17:14:47 -050098
99}
100
101
Patrick Williams90dfee32022-12-08 06:52:46 -0600102function remove_path() {
103 local dir_path="${1}" ; shift
104 local path_var="${1:-PATH}" ; shift
Michael Walsh61ce3e82019-05-29 17:14:47 -0500105
Patrick Williams90dfee32022-12-08 06:52:46 -0600106 # Remove all occurrences of dir_path from the path variable named in path_var.
Michael Walsh61ce3e82019-05-29 17:14:47 -0500107
Patrick Williams90dfee32022-12-08 06:52:46 -0600108 # Note that this function will remove extraneous slashes from the elements of path_var.
Michael Walsh61ce3e82019-05-29 17:14:47 -0500109
Patrick Williams90dfee32022-12-08 06:52:46 -0600110 # Description of argument(s):
111 # dir_path The directory to be removed from the path variable.
112 # path_var The name of a variable containing directory paths separated by colons.
Michael Walsh61ce3e82019-05-29 17:14:47 -0500113
Patrick Williams90dfee32022-12-08 06:52:46 -0600114 cleanup_path_slashes dir_path || return 1
115 cleanup_path_slashes ${path_var} || return 1
116 remove_list_element "${dir_path}" "${path_var}" : || return 1
Michael Walsh61ce3e82019-05-29 17:14:47 -0500117
118}