commit 316a2b347de962bbf146c3619f1a6e3841e6dd34
Author: Thomas Schöpping <tschoepp@cit-ec.uni-bielefeld.de>
Date:   Tue Jan 9 15:02:38 2018 +0100

    Enhanced GCC setup script: now it is possible to uninstall versions via the script.

diff --git a/compiler/GCC/gccsetup.sh b/compiler/GCC/gccsetup.sh
index 653eb10..f32b677 100755
--- a/compiler/GCC/gccsetup.sh
+++ b/compiler/GCC/gccsetup.sh
@@ -309,6 +309,8 @@ function printHelp {
   printf "              Print this help text.\n"
   printf "          -i, --install\n"
   printf "              Install another version.\n"
+  printf "          -u, --uninstall\n"
+  printf "              Unistall a version.\n"
   printf "          -c, --change\n"
   printf "              Change the default version.\n"
   printf "          -q, --quit\n"
@@ -320,11 +322,13 @@ function printHelp {
 ### detect installed versions ##################################################
 # Detect all installed version of arm-none-eabi-gcc, if any.
 #
-# usage:      detectInstalledVersions <binarray> <current>
+# usage:      detectInstalledVersions <binarray> <current> [<current_idx>]
 # arguments:  <binarray>
 #                 Array variable to store all detected binary paths to. 
 #             <current>
 #                 Variable to store the currently active binary to.
+#             <current_idx>
+#                 Index of the curretly selected version in the output array (<binarray>).
 # return:     n/a
 #
 function detectInstalledVersions {
@@ -341,10 +345,15 @@ function detectInstalledVersions {
     armgcc_commanddir=$(dirname $armgcc_command)
     armgcc_currentbin=$armgcc_command
     while [ -L $armgcc_currentbin ]; do
-      armgcc_currentbin=$(readlink $armgcc_currentbin)
+      # differentiate between relative and absolute paths
+      if [[ $(readlink $armgcc_currentbin) = /* ]]; then
+        armgcc_currentbin=$(readlink $armgcc_currentbin)
+      else
+        armgcc_currentbin=$(realpath $(dirname $armgcc_currentbin)/$(readlink $armgcc_currentbin))
+      fi
     done
     # the installation location is assumed to be two directories up
-    armgcc_installdir=$(realpath $(dirname ${armgcc_currentbin})/../../)
+    armgcc_installdir=$(realpath $(dirname ${armgcc_currentbin})/../..)
     # list all detected instalations
     for dir in $(ls -d ${armgcc_installdir}/*/); do
       if [ -f ${dir}/bin/arm-none-eabi-gcc ]; then
@@ -352,10 +361,24 @@ function detectInstalledVersions {
         armgcc_bincnt=$((armgcc_bincnt + 1))
       fi
     done
-  fi
 
-  eval "$1=(${armgcc_bins[*]})"
-  eval $2="$armgcc_currentbin"
+    # set the output variables
+    eval "$1=(${armgcc_bins[*]})"
+    eval $2="$armgcc_currentbin"
+    if [ -n "$3" ]; then
+      for (( bin=0; bin<${#armgcc_bins[@]}; ++bin )); do
+        if [ ${armgcc_bins[bin]} = "$armgcc_currentbin" ]; then
+          eval $3=$bin
+        fi
+      done
+    fi
+  else
+    eval "$1=()"
+    eval $2=""
+    if [ -n "$3" ]; then
+      eval $3=""
+    fi
+  fi
 }
 
 ### install new version ########################################################
@@ -401,10 +424,19 @@ function installNewVersion {
   # read download URL form user
   printLog "read installation url from user\n"
   local armgcc_downloadurl=""
-  while [[ "$armgcc_downloadurl" != *".tar.bz2" ]]; do
+  while [ -z "$armgcc_downloadurl" ]; do
     read -p "Download link for the installation file: " -e armgcc_downloadurl
+    if [ -z "$armgcc_downloadurl" ]; then
+      printWarning "installation aborted by user\n"
+      return 1
+    fi
     if [[ $armgcc_downloadurl != *".tar.bz2" ]]; then
       printWarning "please specify a .tar.bz2 file\n"
+      armgcc_downloadurl=""
+    fi
+    if [ ! wget --spider $armgcc_downloadurl 2>/dev/null ]; then
+      printWarning "$armgcc_downloadurl can not be reached\n"
+      armgcc_downloadurl=""
     fi
   done
   printLog "user selected $armgcc_downloadurl\n"
@@ -512,7 +544,6 @@ function installNewVersion {
         # don't do anything if the line is already present
         local bashrc_entrylines=$(grep -x -n "$bashrc_entry" $bashrc_file | cut -f1 -d:) # string of line numbers
         bashrc_entrylines=(${bashrc_entrylines//"\n"/" "}) # array of line numbers
-        printf "$bashrc_entrylines\n"
         if [[ ${#bashrc_entrylines[@]} = 0 ]]; then
           # insert the entry before the closing identifier
           sed -i "${bashrc_idlines[1]}"'i'"$bashrc_entry" $bashrc_file
@@ -560,10 +591,110 @@ function installNewVersion {
   return 0
 }
 
+### uninstall a version ########################################################
+# Select an installed version and uninstall it from the system.
+#
+# usage:      uninstallVersion <versions> <current_idx> <linkdir>
+# arguments:  <version>
+#                 Array of available versions (full path to binary).
+#             <current_idx>
+#                 Index of the currently selected version in the array.
+#             <linkdir>
+#                 Path where to delete old links.
+# return:     0
+#                 No error or warning occurred.
+#             1
+#                 Warning: Installation aborted by user.
+#             -1
+#                 Error: An exception occurred.
+#
+function uninstallVersion {
+  local versions=("${!1}")
+  local current_idx="$2"
+  local linkdir="$3"
+
+  # check whether at least two installations were detected
+  if [ ${#versions[@]} -eq 0 ]; then
+    printError "no installation detected\n"
+    return -1
+  else
+    # print all available versions
+    printInfo "choose the installation to uninstall to or type 'A' to abort:\n"
+    for (( cnt=0; cnt<${#versions[@]}; ++cnt )); do
+      if [ $cnt -eq $current_idx ]; then
+        printf "*%3u: %s\n" $(($cnt + 1)) ${versions[$cnt]}
+      else
+        printf " %3u: %s\n" $(($cnt + 1)) ${versions[$cnt]}
+      fi
+    done
+
+    # read user selection
+    printLog "read user slection\n"
+    local userinput=""
+    while [ -z $userinput ] ; do
+      read -p "your selection: " -e userinput
+      printLog "user selection: $userinput\n"
+      if [[ ! "$userinput" =~ ^[0-9]+$ ]] || [ ! "$userinput" -gt 0 ] || [ ! "$userinput" -le ${#versions[@]} ] && [[ ! "$userinput" =~ ^[Aa]$ ]]; then
+        printWarning "Please enter an integer between 1 and ${#versions[@]} or 'A' to abort.\n"
+        userinput=""
+      fi
+      if [ ${#versions[@]} -gt 1 ] && [ $((userinput - 1)) -eq $current_idx ]; then
+        printWarning "Unable to uninstall currently selected version (as long as there are others).\n"
+        userinput=""
+      fi
+    done
+
+    if [[ "$userinput" =~ ^[Aa]$ ]]; then
+      printWarning "aborted by user\n"
+      return 1
+    else
+      local idx=$((userinput - 1))
+      printf "\n"
+      # prompt selected and aks user for confirmation
+      printInfo "${versions[$idx]} will be removed. Continue? [y/n]\n"
+      readUserInput "YyNn" userinput
+      case "$userinput" in
+        Y|y)
+          ;;
+        N|n)
+          printWarning "uninstallation process aborted by user\n"
+          return 1
+          ;;
+        *) # sanity check (exit with error)
+          printError "invalid option: $userinput\n"
+          return -1
+          ;;
+      esac
+      # find and delete any links pointing to the version to be deleted
+      for link in `find $linkdir -maxdepth 1 -type l`; do
+        local l=$link
+        # follow the link to the actual binary
+        while [ -L $l ]; do
+          # differentiate between relative and absolute paths
+          if [[ $(readlink $l) = /* ]]; then
+            l=$(readlink $l)
+          else
+            l=$(realpath $(dirname $l)/$(readlink $l))
+          fi
+        done
+        # delete the link if it points to the version to be uninstalled
+        if [ $(dirname $l) == $(dirname ${versions[$idx]}) ]; then
+          rm $link
+        fi
+      done
+      # delete the version directory (assumed to be one directory up)
+      rm -rf $(realpath $(dirname ${versions[$idx]})/..)
+      printInfo "${versions[$idx]} has been removed.\n"
+    fi
+  fi
+
+  return 0
+}
+
 ### change default version #####################################################
 # Change the default arm-none-eabi-gcc version.
 #
-# usage:      installNewVersion <versions> <linkdir>
+# usage:      changeDefaultVersion <versions> <linkdir>
 # argumenst:  <versions>
 #                 Array of available versions (full path to binary).
 #             <linkdir>
@@ -669,7 +800,8 @@ function main {
   # detect installed versions and inform user
   local installedversions=()
   local currentversion=""
-  detectInstalledVersions installedversions currentversion
+  local currentversionidx="n/a"
+  detectInstalledVersions installedversions currentversion currentversionidx
   case "${#installedversions[@]}" in
     0)
       printInfo "no installation has been detected\n";;
@@ -694,15 +826,29 @@ function main {
       case "$1" in
         -h|--help) # already handled; ignore
           shift 1;;
-        -i|--init)
+        -i|--install)
           if [ -z "$currentversion" ]; then
             installNewVersion
           else
-            installNewVersion --install=$(realpath $(dirname "$currentversion")/../../) --link=$(realpath $(dirname "$currentversion")/../../)
+            installNewVersion --install=$(realpath $(dirname $currentversion)/../..) --link=$(realpath $(dirname $currentversion)/../..)
+          fi
+          detectInstalledVersions installedversions currentversion currentversionidx
+          printf "\n"; shift 1;;
+        -u|--uninstall)
+          if [ ! -z "$currentversion" ]; then
+            uninstallVersion installedversions[@] $currentversionidx $(realpath $(dirname $currentversion)/../..)
+            detectInstalledVersions installedversions currentversion currentversionidx
+          else
+            printError "no installation detected\n"
           fi
           printf "\n"; shift 1;;
         -c|--change)
-          changeDefaultVersion installedversions[@] $(realpath $(dirname "$currentversion")/../../); printf "\n"; shift 1;;
+          if [ ! -z "$currentversion" ]; then
+            changeDefaultVersion installedversions[@] $(realpath $(dirname $currentversion)/../..)
+          else
+            printError "no installation detected\n"
+          fi
+          printf "\n"; shift 1;;
         -q|--quit)
           quitScript; shift 1;;
         --log=*|--LOG=*) # already handled; ignore
@@ -726,10 +872,11 @@ function main {
     printInfo "GCC setup main menu\n"
     printf "Please select one of the following actions:\n"
     printf "  [I] - install another version\n"
+    printf "  [U] - uninstall a version\n"
     printf "  [C] - change default version\n"
     printf "  [Q] - quit this setup\n"
     local userinput=""
-    readUserInput "IiCcQq" userinput
+    readUserInput "IiUuCcQq" userinput
     printf "\n"
 
     # evaluate user selection
@@ -738,11 +885,25 @@ function main {
         if [ -z "$currentversion" ]; then
           installNewVersion
         else
-          installNewVersion --install=$(realpath $(dirname "$currentversion")/../../) --link=$(realpath $(dirname "$currentversion")/../../)
+          installNewVersion --install=$(realpath $(dirname $currentversion)/../..) --link=$(realpath $(dirname $currentversion)/../..)
+        fi
+        detectInstalledVersions installedversions currentversion currentversionidx
+        printf "\n";;
+      U|u)
+        if [ ! -z "$currentversion" ]; then
+          uninstallVersion installedversions[@] $currentversionidx $(realpath $(dirname $currentversion)/../..)
+          detectInstalledVersions installedversions currentversion currentversionidx
+        else
+          printError "no installation detected\n"
         fi
         printf "\n";;
       C|c)
-        changeDefaultVersion installedversions[@] $(realpath $(dirname "$currentversion")/../../); printf "\n";;
+        if [ ! -z "$currentversion" ]; then
+          changeDefaultVersion installedversions[@] $(realpath $(dirname $currentversion)/../..)
+        else
+          printError "no installation detected\n"
+        fi
+        printf "\n";;
       Q|q)
         quitScript;;
       *) # sanity check (exit with error)
