summaryrefslogtreecommitdiff
path: root/pkgs/build-support/setup-hooks/arrayUtilities/sortArray/sortArray.bash
blob: 17e906553dc8a8068dd268691d4dd99433a18932 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# shellcheck shell=bash

# sortArray
# Sorts the indexed array referenced by inputArrRef and stores the result in the indexed array referenced by
# outputArrRef.
#
# Arguments:
# - inputArrRef: a reference to an indexed array (not mutated, may alias outputArrRef)
# - outputArrRef: a reference to an indexed array (contents are replaced entirely, may alias inputArrRef)
#
# Returns 0.
sortArray() {
  if (($# != 2)); then
    nixErrorLog "expected two arguments!"
    nixErrorLog "usage: sortArray inputArrRef outputArrRef"
    exit 1
  fi

  local -rn inputArrRef="$1"
  local -rn outputArrRef="$2"

  if ! isDeclaredArray "${!inputArrRef}"; then
    nixErrorLog "first argument inputArrRef must be a reference to an indexed array"
    exit 1
  elif ! isDeclaredArray "${!outputArrRef}"; then
    nixErrorLog "second argument outputArrRef must be a reference to an indexed array"
    exit 1
  fi

  local -a sortedArray=()

  # Guard on the length of the input array, as empty array will expand to nothing, but printf will still see it as an
  # argument, producing an empty string.
  if ((${#inputArrRef[@]} > 0)); then
    # NOTE from Bash's printf documentation:
    #   The format is reused as necessary to consume all of the arguments. If the format requires more arguments than
    #   are supplied, the extra format specifications behave as if a zero value or null string, as appropriate, had
    #   been supplied.
    #   - https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html#index-printf
    # NOTE from sort manpage:
    #   If you use a non-POSIX locale (e.g., by setting LC_ALL to 'en_US'), then sort may produce output that is sorted
    #   differently than you're accustomed to. In that case, set the LC_ALL environment variable to 'C'. Setting only
    #   LC_COLLATE has two problems. First, it is ineffective if LC_ALL is also set. Second, it has undefined behavior
    #   if LC_CTYPE (or LANG, if LC_CTYPE is unset) is set to an incompatible value. For example, you get undefined
    #   behavior if LC_CTYPE is ja_JP.PCK but LC_COLLATE is en_US.UTF-8.
    #   - https://www.gnu.org/software/coreutils/manual/html_node/sort-invocation.html#FOOT1
    mapfile -d $'\0' -t sortedArray < <(printf '%s\0' "${inputArrRef[@]}" | LC_ALL=C sort --stable --zero-terminated)
  fi

  outputArrRef=("${sortedArray[@]}")

  return 0
}