#!/bin/sh


# Zerocat Coreboot Machines --- Create very satisfying free software devices.
#
# Copyright (C) 2019, 2020, 2021, 2022  Kai Mertens <kmx@posteo.net>
# Re-exec code suggested by Ricardo Wurmus, 03/2021
#
# This file is part of Zerocat Coreboot Machines.
#
# Zerocat Coreboot Machines is free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# Zerocat Coreboot Machines is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with Zerocat Coreboot Machines.  If not, see <http://www.gnu.org/licenses/>.


# Purpose
# =======
#
# Set up a toolbox folder and put external projects (i.e.: grub,
# seabios, coreboot) in place.


# Usage
# =====
#
#     ./setup-toolbox.sh --usage


# Re-exec if we are not using Bash or are using Bash in POSIX mode.
if [ -z "$BASH" ] || [ "$BASH" = "/bin/sh" ]; then
  bash=`command -v bash`
  if [ -z "$bash" ]; then
    echo "Couldn't find Bash, sorry!"
    exit 1
  else
    exec "$bash" "$0" "$@"
  fi
fi

# We're using Bash now.
set +o errexit
set +o nounset
set -o pipefail

# external sources ###
source ./globals__ANSI-color-escapes.sh
source ./globals__project.sh
source ./lib__debug.sh
source ./lib__get-input.sh
source ./func__print_licheader.sh
source ./func__print_logo.sh

# global constants ###

# global variables ###

# functions ###

# $1: version
retrieve_flashrom()
{
  _funcstart "$FUNCNAME"

  local version="${1}"
  local folder="${pname[flashrom]}${FVS}${version}"

  _info "Set up:${RTAB}${toolbox_folder}/${folder}"

  _info "Retrieve sources ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    pushd ${toolbox_folder} &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    rm -r -f "${folder}" 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    git clone https://review.coreboot.org/flashrom.git ${folder} 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... sources retrieved."

  _info "Perform version checkout ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    pushd ${folder} &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    git checkout ${version} 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... version checkout performed."

  _info "Compile ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    CC="$(command -v gcc)" make all 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... successfully compiled."

  # back to root
  [ "$opt__dryrun" ] || {
    popd +1 &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    popd &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... successful setup:${RTAB}${FG_GREEN}${toolbox_folder}/${folder}${FG_DEFAULT}"

  _funcstop "$FUNCNAME"
}

# $1: version
retrieve_uefitool()
{
  _funcstart "$FUNCNAME"

  declare -r -a commands__check_UEFITool=(
    'qmake'   # UEFITool only
  )
  # --- UEFITool only? ---
  # topmenu-gtk2                topmenu-gtk2
  # qt
  # qt4-qmake                   qt4-qmake
  # libqt4-dev                  libqt4-dev
  # libqt4-dev-bin              libqt4-dev-bin
  #
  declare -r -a packages_UEFITool__trisquel=(
    'topmenu-gtk2'
    'qt4-qmake'
    'libqt4-dev'
    'libqt4-dev-bin'
  )
  declare -r -a packages_UEFITool__guix=(
    'qt'
  )

  local version="${1}"
  local folder="${pname[uefitool]}${FVS}${version}"

  _info "Set up:${RTAB}${toolbox_folder}/${folder}"

  _info "Check environment ..."
  check_packages "packages_UEFITool__${osid}"
  check_commands 'commands__check_UEFITool'
  _pass "... environment checked."

  _info "Retrieve sources ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    pushd ${toolbox_folder} &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    rm -r -f "${folder}" 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    git clone https://github.com/LongSoft/UEFITool.git "${folder}" 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... sources retrieved."

  _info "Perform version checkout ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    pushd ${folder} &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    git checkout "${version}" 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... version checkout performed."

  _info "Create Makefile ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    qmake uefitool.pro 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... Makefile created."

  _info "Start compilation ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    CC="$(command -v gcc)" make all 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... successfully compiled."

  # back to root
  [ "$opt__dryrun" ] || {
    popd +1 &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    popd &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... successful setup:${RTAB}${FG_GREEN}${toolbox_folder}/${folder}${FG_DEFAULT}"

  _funcstop "$FUNCNAME"
}

# $1: version
retrieve_fcode_utils()
{
  _funcstart "$FUNCNAME"

  local version="${1}"
  local folder="${pname[fcode_utils]}${FVS}${version}"

  _info "Set up:${RTAB}${toolbox_folder}/${folder}"

  _info "Retrieve sources ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    pushd ${toolbox_folder} &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    rm -r -f "${folder}" 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    git clone https://github.com/openbios/fcode-utils.git ${folder} 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... sources retrieved."

  _info "Perform version checkout ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    pushd ${folder} &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    git checkout ${version} 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... version checkout performed."

  _info "Compile ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    CC="$(command -v gcc)" make all 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... successfully compiled."

  # back to root
  [ "$opt__dryrun" ] || {
    popd +1 &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    popd &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... successful setup:${RTAB}${FG_GREEN}${toolbox_folder}/${folder}${FG_DEFAULT}"

  _funcstop "$FUNCNAME"
}

# $1: version
retrieve_bios_extract()
{
  _funcstart "$FUNCNAME"

  local version="${1}"
  local folder="${pname[bios_extract]}${FVS}${version}"

  _info "Set up:${RTAB}${toolbox_folder}/${folder}"

  _info "Retrieve sources ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    pushd ${toolbox_folder} &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    rm -r -f "${folder}" 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    git clone https://review.coreboot.org/bios_extract.git ${folder} 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... sources retrieved."

  _info "Perform version checkout ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    pushd ${folder} &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    git checkout ${version} 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... version checkout performed."

  _info "Compile ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    CC="$(command -v gcc)" make all 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... successfully compiled."

  # back to root
  [ "$opt__dryrun" ] || {
    popd +1 &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    popd &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... successful setup:${RTAB}${FG_GREEN}${toolbox_folder}/${folder}${FG_DEFAULT}"

  _funcstop "$FUNCNAME"
}

# $1: version
retrieve_coreboot()
{
  _funcstart "$FUNCNAME"

  local version="${1}"
  local folder="${pname[coreboot]}${FVS}${version}"

  _info "Set up:${RTAB}${toolbox_folder}/${folder}"

  _info "Enter toolbox folder ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    pushd ${toolbox_folder} &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... toolbox folder entered."

  _info "Retrieve sources ..."
  [ "$opt__dryrun" ] || {
    if [ -d "$folder" ]; then
      _info "Existing project folder found."
      yes_no_abort "Discard (yes|no|abort) or Reuse? "
    else
      true
    fi
    if [ $? -eq 0 ]; then
      echo -e -n "${SET_DIM}"
      rm -r -f "${folder}" 1>"${opt__mute:-/dev/stdout}" ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
      git clone https://review.coreboot.org/coreboot.git ${folder} 1>"${opt__mute:-/dev/stdout}" ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    fi
  }
  _pass "... sources retrieved."

  _info "Descend into project folder ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    pushd ${folder} &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... project folder entered."

  _info "Clean up ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    [ -f Makefile ] && {
      CC="$(command -v gcc)" make distclean 1>"${opt__mute:-/dev/stdout}" ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    }
  }
  _pass "... cleaned."

  _info "Perform version checkout ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    git checkout ${version} 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... version checkout performed."

  _info "Call submodule ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    git submodule update --init --checkout 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... submodule called."

  _info "Compile ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    CC="$(command -v gcc)" make crossgcc-i386 CPUS=2 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "...successfully compiled."

  # back to root
  _info "Return to toolchain folder ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    popd +1 &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    popd &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... successfully returned."

  _pass "Successfully set up:${RTAB}${toolbox_folder}/${folder}"

  _funcstop "$FUNCNAME"
}

# $1: version
retrieve_grub()
{
  _funcstart "$FUNCNAME"

  # Here an example on what you should expect with ./configure on Trisquel.
  # How to get devmapper support on GNU Guix? Do we need that?
  #
  # *******************************************************
  # GRUB2 will be compiled with following components:
  # Platform: i386-coreboot
  # With devmapper support: Yes
  # With memory debugging: No
  # With disk cache statistics: No
  # With boot time statistics: No
  # efiemu runtime: No (explicitly disabled)
  # grub-mkfont: Yes
  # grub-mount: Yes
  # starfield theme: Yes
  # With DejaVuSans font from /usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf
  # With libzfs support: No (explicitly disabled)
  # Build-time grub-mkfont: Yes
  # With unifont from /usr/share/fonts/X11/misc/unifont.pcf.gz
  # With liblzma from -llzma (support for XZ-compressed mips images)
  # *******************************************************

  local version="${1}"
  local folder="${pname[grub]}${FVS}${version}"
  local config_options="--enable-efiemu=no --enable-libzfs=no --disable-grub-mount"
  local path_ft=

  _info "Set up:${RTAB}${toolbox_folder}/${folder}"

  _info "Descend into toolbox folder ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    pushd "${toolbox_folder}" &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... toolbox successfully entered."

  _info "Retrieve sources ..."
  [ "$opt__dryrun" ] || {
    if [ -d "$folder" ]; then
      _info "Existing project folder found."
      yes_no_abort "Discard (yes|no|abort) or Reuse? "
    else
      true
    fi
    if [ $? -eq 0 ]; then
      echo -e -n "${SET_DIM}"
      rm -r -f "${folder}" 1>"${opt__mute:-/dev/stdout}" ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
      git clone git://git.savannah.gnu.org/grub.git ${folder} 1>"${opt__mute:-/dev/stdout}" ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    fi
  }
  _pass "... sources retrieved."

  _info "Descend into project folder ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    pushd ${folder} &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... project folder entered."

  _info "Clean up ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    [ -f Makefile ] && {
      CC="$(command -v gcc)" make distclean 1>"${opt__mute:-/dev/stdout}" ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    }
    [ -L "./unifont.ttf" ] &&
      rm -f "./unifont.ttf"
    [ -L "./DejaVuSans.ttf" ] &&
      rm -f "./DejaVuSans.ttf"
  }
  _pass "... cleaned."

  _info "Perform version checkout ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    git checkout ${version} 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... version checkout performed."

  _info "Start configuration ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}" && {
      case "$version" in
        ('grub-2.06')
          ./bootstrap 1>"${opt__mute:-/dev/stdout}" ||
            go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
          ;;
        ('2.02')
          ./autogen.sh 1>"${opt__mute:-/dev/stdout}" ||
            go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
          ;;
        (*)
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "unsupported version: $version"
          ;;
      esac
    }

    # Help configure script and specify path to freetype2.pc
    local ft_i386="/usr/lib/i386-linux-gnu/pkgconfig/freetype2.pc"
    local ft_amd64="/usr/lib/x86_64-linux-gnu/pkgconfig/freetype2.pc"
    local ft_gnuguix="$GUIX_ENVIRONMENT/lib/pkgconfig/freetype2.pc"
    if [ -f "$ft_i386" ]; then
      path_ft=${ft_i386%/*}
    elif [ -f "$ft_amd64" ]; then
      path_ft=${ft_amd64%/*}
    elif [ -f "$ft_gnuguix" ]; then
      path_ft=${ft_gnuguix%/*}
    else
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "unknown path to freetype2.pc"
    fi
    _mesg "Found freetype2.pc:${RTAB}$path_ft"

    # Help configure script and link unifont.ttf, required for gfxmenu
    if [ -f "$GUIX_ENVIRONMENT/share/fonts/truetype/unifont.ttf" -a ! -f "./unifont.ttf" ]; then
      ln -sf "$GUIX_ENVIRONMENT/share/fonts/truetype/unifont.ttf" unifont.ttf
      _mesg "Link created:${RTAB}$GUIX_ENVIRONMENT/share/fonts/truetype/unifont.ttf"
    fi

    # Help configure script and link DejaVuSans.ttf, required for Starfield Theme
    if [ -f "$GUIX_ENVIRONMENT/share/fonts/truetype/DejaVuSans.ttf" -a ! -f "./DejaVuSans.ttf" ]; then
      ln -sf "$GUIX_ENVIRONMENT/share/fonts/truetype/DejaVuSans.ttf" DejaVuSans.ttf
      _mesg "Link created:${RTAB}$GUIX_ENVIRONMENT/share/fonts/truetype/DejaVuSans.ttf"
    fi

    # Run ./configure
    _mesg "Running ./configure ..."
    echo -e -n "${SET_DIM}" && {
      ./configure \
        --with-platform=coreboot \
        --prefix=$PWD/out \
        PKG_CONFIG_PATH="$path_ft" \
        $config_options \
        1>"${opt__mute:-/dev/stdout}" ||
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    }
  }
  _pass "... configuration complete."

  yes_no_abort || {
    # back to root
    [ "$opt__dryrun" ] || {
      popd +1 &>/dev/null ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
      popd &>/dev/null ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    }
    go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "abort by user"
  }

  _info "Compile ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    CC="$(command -v gcc)" make 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... successfully compiled."

  _info "Install ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    CC="$(command -v gcc)" make install 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... successfully installed."

  # back to root
  _info "Return to toolchain folder ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    popd +1 &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    popd &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... successfully returned."

  _pass "Successfully set up:${RTAB}${toolbox_folder}/${folder}"

  _funcstop "$FUNCNAME"
}

# $1: version
retrieve_seabios()
{
  _funcstart "$FUNCNAME"

  local version="${1}"
  local folder="${pname[seabios]}${FVS}${version}"

  _info "Set up:${RTAB}${toolbox_folder}/${folder}"

  _info "Descend into toolbox folder ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    pushd "${toolbox_folder}" &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... toolbox successfully entered."

  _info "Retrieve sources ..."
  [ "$opt__dryrun" ] || {
    if [ -d "$folder" ]; then
      _info "Existing project folder found."
      yes_no_abort "Discard (yes|no|abort) or Reuse? "
    else
      true
    fi
    if [ $? -eq 0 ]; then
      echo -e -n "${SET_DIM}"
      rm -r -f "${folder}" 1>"${opt__mute:-/dev/stdout}" ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
      git clone https://git.seabios.org/seabios.git ${folder} 1>"${opt__mute:-/dev/stdout}" ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    fi
  }
  _pass "... sources retrieved."

  _info "Enter project folder ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    pushd ${folder} &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... project folder entered."

  _info "Clean up ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    [ -f Makefile ] && {
      CC="$(command -v gcc)" make clean 1>"${opt__mute:-/dev/stdout}" ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    }
  }
  _pass "... cleaned."

  _info "Perform version checkout ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    git checkout ${version} 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... version checkout performed."

  _info "Skip configuration tool."
  #make menuconfig

  _info "Skip compilation."
  #make

  # back to root
  _info "Return to toolchain folder ..."
  [ "$opt__dryrun" ] || {
    popd +1 &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    popd &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... successfully returned."

  _pass "Successfully set up:${RTAB}${toolbox_folder}/${folder}"

  _funcstop "$FUNCNAME"
}

# $1: version
retrieve_libreboot()
{
  _funcstart "$FUNCNAME"

  local version="${1}"
  local folder="${pname[libreboot]}${FVS}${version}"

  _info "Set up:${RTAB}${toolbox_folder}/${folder}"

  _info "Enter toolbox folder ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    pushd "${toolbox_folder}" &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... toolbox successfully entered."

  _info "Retrieve sources ..."
  [ "$opt__dryrun" ] || {
    if [ -d "$folder" ]; then
      _info "Existing project folder found."
      yes_no_abort "Discard (yes|no|abort) or Reuse? "
    else
      true
    fi
    if [ $? -eq 0 ]; then
      echo -e -n "${SET_DIM}"
      rm -r -f "${folder}" 1>"${opt__mute:-/dev/stdout}" ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
      git clone https://notabug.org/libreboot/libreboot.git ${folder} 1>"${opt__mute:-/dev/stdout}" ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    fi
  }
  _pass "... sources retrieved."

  _info "Descend into project folder ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    pushd ${folder} &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... project folder entered."

  _info "Clean up utility ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    pushd resources/utilities/ich9deblob &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    CC="$(command -v gcc)" make clean 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    popd &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... utility successfully cleaned."

  _info "Perform version checkout ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    git checkout ${version} 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... version checkout performed."

  _info "Compile utility ..."
  [ "$opt__dryrun" ] || {
    echo -e -n "${SET_DIM}"
    pushd resources/utilities/ich9deblob &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    CC="$(command -v gcc)" make 1>"${opt__mute:-/dev/stdout}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    popd +1 &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... utility successfully compiled."

  # back to root
  _info "Return to toolchain folder ..."
  [ "$opt__dryrun" ] || {
    popd +1 &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    popd &>/dev/null ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }
  _pass "... successfully returned."

  _pass "Successfully set up:${RTAB}${toolbox_folder}/${folder}"

  _funcstop "$FUNCNAME"
}

# $1: folder to remove, must match $TEMPLATE_TOOLBOX_FOLDER
clean_toolbox_folder()
{
  _funcstart "$FUNCNAME"

  # skip removal if folder is not existent (or has already been removed)
  if [ -d "${1%/}" ]; then
    _warn "Folder to remove:${RTAB}${1%/}"
    [ "${1%.*}" != "${TEMPLATE_TOOLBOX_FOLDER%.*}" ] && {
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"  "pattern mismatch: $1"
    }
    yes_no_abort && {
      [ "$opt__dryrun" ] || {
        rm -rf ${1%\/} ||
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
      }
      _pass "Folder ${1%/} has been removed."
    }
  else
    _info "Folder ${1%/} does not exist."
  fi

  _funcstop "$FUNCNAME"
}

# $1: array with list of packages to check
check_packages()
{
  _funcstart "$FUNCNAME"

  declare -n aref=$1
  declare pkg_status
  declare -a miss=()
  declare i

  _info "Test availability of required packages ($1) ..."
  case "$osid" in
    ('trisquel')
      for i in ${aref[*]}
      do
        pkg_status=$(dpkg-query -l "$i" 2>/dev/null | tail -n 1 | sed -r -e 's#(^.?.?.?)(.*$)#\1#;' -)
        [[ "${pkg_status}" != 'ii ' ]] &&
          miss+=("$i")
      done
      ;;
  esac
  [ "${#miss}" -ne 0 ] && {
    _fail "Please install missing packages:"
    for i in ${miss[*]}
    do
      _mesg "${LIITEM}$i"
    done
    _mesg "After installation, please run this check again."
    exit 1
  }
  _pass "... availability tested."

  _funcstop "$FUNCNAME"
}

set_toolbox_folder()
{
  _funcstart "$FUNCNAME"

  if [ "$arg__toolbox" ]; then
    toolbox_folder="$arg__toolbox"
    _pass "Existent toolbox folder in use:"
  else
    toolbox_folder="${TEMPLATE_TOOLBOX_FOLDER}"
    [ "$opt__dryrun" ] ||
      toolbox_folder=$(mktemp -d -q ${TEMPLATE_TOOLBOX_FOLDER})
    _pass "New toolbox folder created:"
  fi
  _mesg "${INDENT}${FG_GREEN}${toolbox_folder}${FG_DEFAULT}"

  _funcstop "$FUNCNAME"
}

# $1: grub|seabios|coreboot|libreboot|bios_extract|fcode-utils|uefitool|flashrom
add_project()
{
  _funcstart "$FUNCNAME"

  declare pname
  declare pfunc

  while [ "${1}" ]; do
    # Attention, subscripts are specified here:
    pname=${1%%@*}
    pfunc=${pname//-/_}
    retrieve_${pfunc} "${1##*@}"
    shift 1
  done

  _funcstop "$FUNCNAME"
}

usage()
{
  _funcstart "$FUNCNAME"

  _info "Provide usage information ..."
  cat<<EOF

${SET_BOLD}NAME${CLR_INTENSITY}
    ${SET_BOLD}$BASH_SOURCE${CLR_INTENSITY} – Set up a toolbox folder and put external projects in place.

${SET_BOLD}USAGE${CLR_INTENSITY}
    ${SET_BOLD}$BASH_SOURCE${CLR_INTENSITY} \\
        [${SET_BOLD}--help${CLR_INTENSITY}|${SET_BOLD}--usage${CLR_INTENSITY}] \\
        [${SET_BOLD}--check${CLR_INTENSITY}] \\
        [${SET_BOLD}--mute${CLR_INTENSITY}] \\
        [${SET_BOLD}--debug${CLR_INTENSITY}]
    ${SET_BOLD}$BASH_SOURCE${CLR_INTENSITY} \\
        [${SET_BOLD}--toolbox${CLR_INTENSITY} [<path/to/toolbox-folder>]] \\
        [${SET_BOLD}--add-project${CLR_INTENSITY} <list-of-projects>] \\
        [${SET_BOLD}--dryrun${CLR_INTENSITY}] \\
        [${SET_BOLD}--mute${CLR_INTENSITY}] \\
        [${SET_BOLD}--debug${CLR_INTENSITY}]
    ${SET_BOLD}$BASH_SOURCE${CLR_INTENSITY} \\
        [${SET_BOLD}--remove${CLR_INTENSITY} <path/to/toolbox-folder1> [<path/to/toolbox-folder2>] ... ] \\
        [${SET_BOLD}--dryrun${CLR_INTENSITY}] \\
        [${SET_BOLD}--mute${CLR_INTENSITY}] \\
        [${SET_BOLD}--debug${CLR_INTENSITY}]
    ${SET_BOLD}$BASH_SOURCE${CLR_INTENSITY} \\
        [${SET_BOLD}--remove-all${CLR_INTENSITY}] \\
        [${SET_BOLD}--dryrun${CLR_INTENSITY}] \\
        [${SET_BOLD}--mute${CLR_INTENSITY}] \\
        [${SET_BOLD}--debug${CLR_INTENSITY}]

${SET_BOLD}OPTIONS${CLR_INTENSITY}
    Note the order of options on the command line should have no importance.

    ${SET_BOLD}--help${CLR_INTENSITY}
    ${SET_BOLD}--usage${CLR_INTENSITY}
        Display usage information.
    ${SET_BOLD}--check${CLR_INTENSITY}
        Check environment for missing programs and packages.
    ${SET_BOLD}--toolbox${CLR_INTENSITY} [<path/to/toolbox-folder>]
        Specify an existing folder in case you want to populate that folder with selected external projects.
        Otherwise, a new, unique, empty toolbox folder will be created. The name of this folder will be tested
        or created to match pattern ${SET_BOLD}${TEMPLATE_TOOLBOX_FOLDER//X/?}${CLR_INTENSITY}.
    ${SET_BOLD}--add-project${CLR_INTENSITY} <list-of-projects>
        Populate the toolbox folder in use with listed external projects.
    ${SET_BOLD}--dryrun${CLR_INTENSITY}
        Together with ${SET_BOLD}--add-project${CLR_INTENSITY}, just screen messages will be issued.
    ${SET_BOLD}--remove${CLR_INTENSITY} <path/to/toolbox-folder1> [<path/to/toolbox-folder2> ...]
        Delete specified toolbox folders. You will be prompted to enter “yes” or “no” beforehand.
    ${SET_BOLD}--remove-all${CLR_INTENSITY}
        Remove ${FG_RED}all toolbox folders${FG_DEFAULT} matching ${SET_BOLD}${TEMPLATE_TOOLBOX_FOLDER//X/?}${CLR_INTENSITY} in working directory.
        For each match, you will be prompted to enter “yes” or “no” beforehand.
    ${SET_BOLD}--mute${CLR_INTENSITY}
        Discard standard output of verbose external processes.
        However, their output to stderr will still be visible.
    ${SET_BOLD}--debug${CLR_INTENSITY}
        Enable extra screen output which eases debugging.

    <path/to/toolbox-folder>
        This unique folder should match pattern ${SET_BOLD}${TEMPLATE_TOOLBOX_FOLDER//X/?}${CLR_INTENSITY} and is to be passed
        to ${SET_BOLD}${TOOLCHAIN_SCRIPT[2]}${CLR_INTENSITY}, ${SET_BOLD}${TOOLCHAIN_SCRIPT[3]}${CLR_INTENSITY} and ${SET_BOLD}${TOOLCHAIN_SCRIPT[4]}${CLR_INTENSITY} as a
        command line argument.
    <list-of-projects>
        Accepted values are:
        ${LIITEM}“${pname[coreboot]}”
        ${LIITEM}“${pname[seabios]}”
        ${LIITEM}“${pname[grub]}”
        ${LIITEM}“${pname[bios_extract]}”
        ${LIITEM}“${pname[fcode_utils]}”
        ${LIITEM}“${pname[uefitool]}”
        ${LIITEM}“${pname[flashrom]}”
        ${LIITEM}“${pname[libreboot]}”
        Values are not case sensitive.
        Multiple values separated by space are accepted.
        Projects like ${SET_UNDERLINE}${pname[coreboot]}${CLR_UNDERLINE},  ${SET_UNDERLINE}${pname[seabios]}${CLR_UNDERLINE} and ${SET_UNDERLINE}${pname[grub]}${CLR_UNDERLINE} should be regarded as a required, standard set of projects.
        Projects like ${SET_UNDERLINE}${pname[flashrom]}${CLR_UNDERLINE}, ${SET_UNDERLINE}${pname[bios_extract]}${CLR_UNDERLINE}, ${SET_UNDERLINE}${pname[fcode_utils]}${CLR_UNDERLINE}, ${SET_UNDERLINE}${pname[uefitool]}${CLR_UNDERLINE} and ${SET_UNDERLINE}${pname[libreboot]}${CLR_UNDERLINE} are optional,
        as they are not yet used by the toolchain scripts.

${SET_BOLD}EXIT CODES${CLR_INTENSITY}
    ${SET_BOLD}0${CLR_INTENSITY}
        normal exit
    ${SET_BOLD}1${CLR_INTENSITY}
        an error occurred

${SET_BOLD}EXAMPLES${CLR_INTENSITY}
    Check  for missing dependencies and create a new, unique, empty toolbox folder:
    ${SET_BOLD}$BASH_SOURCE${CLR_INTENSITY} \\
      ${SET_BOLD}--check${CLR_INTENSITY} \\
      ${SET_BOLD}--toolbox${CLR_INTENSITY}

    Populate an existing toolbox folder with a basic, standard set of external projects:
    ${SET_BOLD}$BASH_SOURCE${CLR_INTENSITY} \\
      ${SET_BOLD}--toolbox${CLR_INTENSITY} <path/to/toolbox-folder> \\
      ${SET_BOLD}--add-project ${pname[coreboot]} ${pname[seabios]} ${pname[grub]}${CLR_INTENSITY}

    Enrich existing toolbox folder with some more external projects, useful to deal with
    extracted VGA Option ROMs:
    ${SET_BOLD}$BASH_SOURCE${CLR_INTENSITY} \\
      ${SET_BOLD}--toolbox${CLR_INTENSITY} <path/to/toolbox-folder> \\
      ${SET_BOLD}--add-project ${pname[bios_extract]} ${pname[fcode_utils]} ${pname[uefitool]} ${pname[flashrom]}${CLR_INTENSITY}

EOF
  _pass "... usage information has been provided."

  _funcstop "$FUNCNAME"
}

parse_cmdline()
{
  _funcstart "$FUNCNAME"

  declare -i n=
  declare opt=

  _info "Parse command line ..."
  while [ $# -gt 0 ]; do
    opt=${1:?${FG_RED}missing parameter${FG_DEFAULT}}
    n=1
    opt=${opt,,}
    case $opt in
      # parameters
      '--debug')
        # no action here, see bottom of script
        ;;
      '--mute')
        opt__mute="/dev/null"
        ;;
      '--dryrun')
        opt__dryrun=1
        ;;
      # jobs
      '--help')
        ;&
      '--usage')
        opt__usage=1
        ;;
      '--remove')
        until [ "${2:0:2}" = '--' ] || [ "${2}" = '' ]; do
          [ -d "${2}" ] ||
            go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"  "--remove: no such directory: ${2}"
          arg__remove[${#arg__remove[@]}]="${2%/}"
          shift 1
        done
        [ "${#arg__remove[@]}" -eq 0 ] &&
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--remove: missing argument"
        opt__remove=1
        ;;
      '--remove-all')
        opt__remove_all=1
        ;;
      '--check')
        opt__check=1
        ;;
      '--toolbox')
        [ "$opt__toolbox" ] &&
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--toolbox: duplicate option"
        opt__toolbox=1
        [ "${2:0:2}" = '--' ] || [ "${2}" = '' ] || {
          [ -d "${2}" ] ||
            go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"  "--toolbox: no such directory: ${2}"
          arg__toolbox="${2%/}"
          n+=1
        }
        ;;
      '--add-project')
        declare -i match
        declare i
        until [ "${2:0:2}" = '--' ] || [ "${2}" = '' ]
        do
          declare pn=${2%%@*}
          declare pv=${2##*@}
          [ "$pv" = "$pn" ] &&
            pv=''
          pn=${pn,,}
          pv=${pv,,}
          match=1   # false
          for i in \
            grub seabios coreboot libreboot \
            bios_extract fcode_utils uefitool flashrom
          do
            [ "${pn}" = "${pname[$i],,}" ] && {
              if [ "${pv}" = '' ]
              then
                pv="${pversion[$i]%% *}"
                match=0   # true
              else
                for j in ${pversion[$i],,}
                do
                  [ "${j}" = "$pv" ] &&
                    match=0   # true
                done
              fi
              [ $match -eq 0 ] && {
                arg__add_project[${#arg__add_project[@]}]="$pn@$pv"
                shift 1
                break 1
              }
            }
          done
          [ $match -eq 1 ] &&
            go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"  "--add-project: unknown argument: ${2}"
        done
        unset i
        unset match
        [ "${#arg__add_project[@]}" -eq 0 ] &&
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--add-project: missing argument"
        opt__add_project=1
        ;;
      *)
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "unknown option: ${opt}"
        ;;
    esac
    shift $n
  done
  if [ $# -ne 0 ]; then
    _warn "... $# parameters were skipped."
  else
    _pass "... command line parsed."
  fi

  _funcstop "$FUNCNAME"
}

check_options()
{
  _funcstart "$FUNCNAME"

  _info "Check options ..."

  # --debug

  # --mute

  # --dryrun
  [ "$opt__dryrun" ] && {
    [ "$opt__toolbox" ] || [ "$opt__remove" ] || [ "$opt__remove_all" ] ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--dryrun: incomplete set of command line options"
  }

  # --help
  # --usage

  # --remove

  # --remove-all

  # --check
  [ "$opt__check" ] &&
    check_commands "commands__check__${osid}"

  # --toolbox

  # --add-project
  [ "$opt__add_project" ] && {
    [ "$opt__toolbox" ] ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--add-project: incomplete set of command line options"
  }

  _pass "... options checked."

  _funcstop "$FUNCNAME"
}

check_settings()
{
  _funcstart "$FUNCNAME"

  _info "Check settings ..."

  # --debug
  [ "$DEBUG" -eq 0 ] ||
    _dbug "Debug output is activated."

  # --mute
  [ "$opt__mute" ] &&
    _mesg "Standard output of external processes is muted."

  # --dryrun
  [ "$opt__dryrun" ] &&
    _mesg "${FG_LIGHTGREEN}This is a dry run.${FG_DEFAULT}"

  # --help
  # --usage

  # --remove
  [ "${#arg__remove[@]}" -eq 0 ] || {
    declare i
    for i in "${arg__remove[@]}"; do
      [ "${i%/}" = "${arg__toolbox}" ] &&
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" \
          "--remove: will remove toolbox folder in use"
    done
    unset i
  }

  # --remove-all
  [ "$opt__remove_all" ] && {
    declare i
    for i in ${TEMPLATE_TOOLBOX_FOLDER//X/?}; do
      [ "${i%/}" = "${arg__toolbox}" ] &&
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" \
          "--remove-all: will remove toolbox folder in use"
        par__remove_all[${#par__remove_all[@]}]="${i%/}"
    done
    unset i
  }

  # --check

  # --toolbox

  # --add-project

  _pass "... settings checked."

  _funcstop "$FUNCNAME"
}

job_list()
{
  _funcstart "$FUNCNAME"

  declare retval=1

  # jobs
  _dbug "${FG_MAGENTA}Jobs ...${FG_DEFAULT}"
  _info "Requested jobs are:"
  [ "$opt__usage" ] && {
    _mesg "${LIITEM}display usage information"
    retval=0
  }
  [ "$opt__remove" ] && {
    _mesg "${LIITEM}remove folder${arg__remove[1]:+s} as specified with --remove"
    for i in ${arg__remove[@]}; do
      _mesg "${INDENT}${LIITEM}$i"
    done
    retval=0
  }
  [ "$opt__remove_all" ] && {
    _mesg "${LIITEM}remove all folder${par__remove_all[1]:+s}"
    for i in ${par__remove_all[@]}; do
      _mesg "${INDENT}${LIITEM}$i"
    done
    retval=0
  }
  [ "$opt__check" ] && {
    _mesg "${LIITEM}check environment"
    retval=0
  }
  [ "$opt__toolbox" ] && {
    if ! [ "$arg__toolbox" ]; then
      _mesg "${LIITEM}create new, unique, empty toolbox folder"
      retval=0
    else
      _mesg "${LIITEM}use specified toolbox folder"
      _mesg "${INDENT}toolbox in use:${RTAB}${arg__toolbox}"
      retval=0
    fi
    [ "$opt__add_project" ] && {
      _mesg "${LIITEM}populate toolbox folder with:"
      for i in "${arg__add_project[@]}"; do
        _mesg "${INDENT}${LIITEM}${i}"
      done
      retval=0
    }
  }
  [ "$retval" -eq 0 ] || {
    _mesg "${INDENT}none"
  }

  _funcstop "$FUNCNAME" $retval
}

parse_debug()
{
  declare i=

  DEBUG=0
  for i in "$@"; do
    [ "$i" = '--debug' ] && DEBUG=1
  done

  true
}

main()
{
  trap '
    echo
    go_exit "$BASH_SOURCE" "$FUNCNAME" "" "$BASH_COMMAND"
    ' SIGINT ERR   # what sigspec is related to ERR??

  _funcstart "$FUNCNAME"

  declare -r scriptname="${TOOLCHAIN_SCRIPT[1]}"
  declare osid=
  declare -r -a commands_script=(
    'source'
    'echo'
    'printf'
    'cat'
    'tail'
    'sed'
    'rm'
    'mv'
    'cd'
    'sleep'
    'exit'
    'git'
    'make'
    'gcc'     # required for toolchain scripts
  )
  declare -r -a commands__check__trisquel=(
    'dpkg-query'
  )
  declare -r -a commands__check__guix=(
  )
  declare -r TEMPLATE_TOOLBOX_FOLDER="toolbox.${TEMP_SUFFIX}"
  declare -r -A pname=(
    [seabios]='seabios'
    [coreboot]='coreboot'
    [libreboot]='libreboot'
    [bios_extract]='bios_extract'
    [fcode_utils]='fcode-utils'
    [uefitool]='UEFITool'
    [flashrom]='flashrom'
    [grub]='grub'
  )
  # Separate entries by space.
  # First entry in string will be used as default.
  declare -r -A pversion=(
    [seabios]='rel-1.14.0'
    [coreboot]='4.14 4.8.1'
    [libreboot]='r20160907'
    [bios_extract]='effb120'
    [fcode_utils]='v1.0.2'
    [uefitool]='0.26.0'
    [flashrom]='v1.2 v1.1 v1.0.1'
    [grub]='grub-2.06 2.02'
  )

  declare opt__mute=
  declare opt__dryrun=
  declare opt__usage=
  declare opt__remove=
  declare opt__remove_all=
  declare opt__toolbox=
  declare opt__check=
  declare opt__add_project=

  declare arg__toolbox=
  declare -a arg__add_project
  declare -a arg__remove
  declare -a par__remove_all

  declare toolbox_folder=             # toolbox folder in use

  _head "Zerocat Coreboot Machines ${PROJECT_NUMBER}”"
  _head "$scriptname – Set up a unique toolbox folder"
  print_licheader
  print_logo
  test_scriptname "$BASH_SOURCE" "$scriptname" && {
    get_OSID 'osid'
    check_commands 'commands_script'
    _info "$(date), ready to start."
    hit_enter
    parse_cmdline "$@"
    check_options
    check_settings
    job_list && {
      yes_no_abort && {
        [ "$opt__usage" ] && {
          usage
        }
        [ "$opt__remove" ] && {
          _info "Starting interactive batch removal:"
          for i in "${arg__remove[@]}"; do
            clean_toolbox_folder "${i:?${FG_RED}is not set${FG_DEFAULT}}"
          done
          _pass "All folders as specified with --remove have been processed."
        }
        [ "$opt__remove_all" ] && {
          _info "Starting interactive batch removal:"
          for i in "${par__remove_all[@]}"; do
            clean_toolbox_folder "${i:?${FG_RED}is not set${FG_DEFAULT}}"
          done
          _pass "All folders as specified with --remove-all have been processed."
        }
        [ "$opt__check" ] && {
          # Required Package            Trisquel 10.0.1                   GNU Guix System
          # ----------------            ---------------                   ---------------
          # Note git, make and qmake are required by this script itself and have already been checked.

          # --- GCC Toolchain (“binutils”, “gcc”, “ld”, “glibc”) ---
          #                                                               gcc-toolchain@7
          # build-essential             build-essential
          # binutils                    binutils
          # gcc                         gcc-9
          # gnat¹                       gnat-9
          # glibc >= 2.1                libc?, libc?-dev
          #
          # ¹gnat must match gcc
          #
          declare -r -a packages_gcc__trisquel=(
            'build-essential'
            'binutils'
            'gcc-9'
            'gnat-9'
            'libc?'
            #~ 'libc?-dev'                 # comes with gcc-9
          )

          # --- Packages required by Projects ---
          # Program Collections:
          # wget                        wget                              wget
          # flex                        flex                              flex
          # bison                       bison                             bison
          # gettext                     gettext                           gettext
          # pkg-config                  pkg-config                        pkg-config
          # dh-autoreconf               dh-autoreconf                     autoconf
          # automake                    automake                          automake
          # libtool                     libtool                           libtool
          # tar                         tar                               tar
          #
          # Libraries:
          # zlib1g-dev                  zlib1g-dev                        zlib
          # libfuse-dev                 libfuse-dev                       fuse
          # libzfs                      (?)                               #zfs
          # libdevmapper-dev            libdevmapper-dev                  (?)
          # liblzma-dev                 liblzma-dev                       (?)
          # libncurses5-dev             libncurses5-dev                   ncurses
          # libpci-dev                  libpci-dev                        pciutils
          # libusb-dev                  libusb-dev                        libusb
          # libusb-1.0-0-dev            libusb-1.0-0-dev                  libusb-compat (?)
          #
          # Fonts:
          # unifont                     unifont                           font-gnu-unifont
          # Freetype >= 2               libfreetype?, libfreetype?-dev    freetype
          # ttf-dejavu-core             ttf-dejavu-core                   font-dejavu
          #
          # Programming:
          # python2                     python                            python2
          #
          # Misc:
          # doxygen                     doxygen                           doxygen
          # ckbcomp                     console-setup                     console-setup
          # xkb/rules/evdev.lst         xkb-data                          xkeyboard-config
          #
          declare -r -a packages_Projects_but_UEFITool__trisquel=(
            'wget'              # i.e. Coreboot
            'flex'
            'bison'
            'gettext'
            'pkg-config'
            'dh-autoreconf'
            #~ 'libtool'           # i.e. GRUB2 (comes with dh-autoreconf)
            'autoconf'          # i.e. GRUB2
            #~ 'automake'          # i.e. GRUB2 (comes with autoconf)
            'tar'               # i.e. GRUB2

            'zlib1g-dev'        # i.e. Coreboot

            'libfuse-dev'
            'libdevmapper-dev'
            'liblzma-dev'
            'libncurses5-dev'
            'libpci-dev'
            'libusb-dev'
            'libusb-1.0-0-dev'

            'libfreetype?' 'libfreetype?-dev'   # i.e. GRUB2
            'unifont'           # i.e. GRUB2 (gfxterm)
            'ttf-dejavu-core'   # i.e. GRUB2 (Starfield Theme)

            'python-is-python2' # i.e. GRUB2, SeaBIOS

            'doxygen'           # i.e. doc/Makefile
            'console-setup'     # i.e. gen-payload-grub.sh
            'xkb-data'          # i.e. gen-payload-grub.sh
          )

          # Check packages (trisquel only)
          if [ "$osid" = 'trisquel' ]; then
            check_packages "packages_gcc__${osid}"
            check_packages "packages_Projects_but_UEFITool__${osid}"
          elif [ "$osid" = 'guix' ]; then
            [ -z "$GUIX_ENVIRONMENT" ] && {
              _fail "Please prepare the environment, first:"
              _mesg "  guix environment --pure -m ../guix/manifest.scm"
              _mesg "  ... invoke toolchain scripts ..."
              _mesg "  exit"
              go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "missing guix environment"
            }
            _warn "Guix environment already set up. Let’s give it a try!"
          fi
        }
        [ "$opt__toolbox" ] && {
          set_toolbox_folder
          [ "$opt__add_project" ] && {
            add_project "${arg__add_project[@]}"
          }
        }
      }
    }
  }
  _info "Good Bye."

  _funcstop "$FUNCNAME"

  trap - ERR SIGINT
}

# script
parse_debug "$@"
main "$@"
